from collections import deque
import sys
sys.setrecursionlimit(10**8)

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    order = [-1]*(n+10)
    que = deque([])

    def bfs(s):
        if visited[s] == False:
            visited[s] = True
            for node in G[s]:
                if visited[node] == False:
                    bfs(node)
            que.appendleft(s)
        else:
            pass

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    order = [-1]*(n+10)
    que = deque([])

    def bfs(s):
        tmp_que = deque([])
        backtrack_que = deque([])
        if visited[s] == False:
            tmp_que.append(s)
            while tmp_que:
                s = tmp_que.popleft()
                backtrack_que.append(s)
                visited[s] = True
                for node in G[s]:
                    if visited[node] == False:
                        tmp_que.appendleft(node)
            while backtrack_que:
                x = backtrack_que.pop()
                que.appendleft(x)

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque
import sys
sys.setrecursionlimit(10**8)

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    order = [-1]*(n+10)
    que = deque([])

    def bfs(s):
        a_que = deque([])
        if visited[s] == False:
            tmpq = deque([s])
            visited[s] = True
            while tmpq:
                s_node = tmpq.popleft()
                a_que.appendleft(s_node)
                for node in G[s_node]:
                    if visited[node] == False:
                        visited[node] = True
                        tmpq.append(node)
        while a_que:
            que.appendleft(a_que.popleft())

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque
import sys
sys.setrecursionlimit(10**8)

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    order = [-1]*(n+10)
    que = deque([])

    def bfs(s):
        a_que = deque([])
        if visited[s] == False:
            tmpq = deque([s])
            visited[s] = True
            while tmpq:
                s_node = tmpq.popleft()
                a_que.appendleft(s_node)
                for node in G[s_node]:
                    if visited[node] == False:
                        visited[node] = True
                        tmpq.appendleft(node)

        while a_que:
            que.appendleft(a_que.popleft())

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    Order = [-1]*(n+1)
    order = deque([])

    def dfs(S):
        a = []
        if visited[S] == False:
            Q = deque([(0, S)])
            visited[S] = True
            while Q:
                parent, node = Q.popleft()
                a.append(node)
                for v in G[node]:
                    if visited[v] == False:
                        visited[v] = True
                        Q.appendleft((node, v))
        while a:
            order.appendleft(a.pop())

    def topological_sort():
        for i in range(1, n+1):
            dfs(i)

    topological_sort()

    for i, v in enumerate(order):
        Order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and Order[x] > Order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if Order[x] > Order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    order = [-1]*(n+10)
    que = deque([])

    def bfs(s):
        tmp_que = deque([])
        backtrack_que = deque([])
        if visited[s] == False:
            tmp_que.append(s)
            while tmp_que:
                s = tmp_que.pop()
                backtrack_que.appendleft(s)
                visited[s] = True
                for node in G[s]:
                    if visited[node] == False:
                        tmp_que.appendleft(node)
            while backtrack_que:
                x = backtrack_que.popleft()
                que.appendleft(x)

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    order = [-1]*(n+10)
    que = deque([])

    def bfs(s):
        tmp_que = deque([])
        backtrack_que = deque([])
        if visited[s] == False:
            tmp_que.append(s)
            while tmp_que:
                s = tmp_que.popleft()
                backtrack_que.appendleft(s)
                visited[s] = True
                for node in G[s]:
                    if visited[node] == False:
                        tmp_que.appendleft(node)
            while backtrack_que:
                x = backtrack_que.popleft()
                que.appendleft(x)

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque
import sys
sys.setrecursionlimit(10**6)

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+1)
    order = [-1]*(n+1)
    que = deque([])

    def bfs(s):
        if visited[s] == False:
            visited[s] = True
            for node in G[s]:
                if visited[node] == False:
                    bfs(node)
            que.appendleft(s)
        else:
            pass

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    In = [0]*(n+1)
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
            In[y] += 1
        edge.append((t, x, y))

    visited = [False]*(n+10)
    stack = deque([])
    order = []
    Order = [-1]*(n+1)

    for i in range(1, n+1):
        if In[i] == 0:
            stack.append(i)

    while stack:
        x = stack.popleft()
        order.append(x)
        for node in G[x]:
            In[node] -= 1
            if In[node] == 0:
                stack.append(node)

    for i,v in enumerate(order):
        Order[v] = i + 1

    not_dag = any(Order[i] < 0 for i in range(1,n+1))

    ans = []
    for t, x, y in edge:
        if t == 1 and Order[x] > Order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if Order[x] > Order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+10)
    Order = [-1]*(n+1)
    order = deque([])

    def dfs(S):
        if visited[S] == False:
            Q = deque([S])
            tmp = deque([])
            visited[S] = True
            while Q:
                node = Q.popleft()
                tmp.append(node)
                for c in G[node]:
                    if visited[c] == False:
                        visited[c] = True
                        Q.append(c)
            while tmp:
                order.appendleft(tmp.pop())

    def topological_sort():
        for i in range(1, n+1):
            dfs(i)

    topological_sort()

    for i, v in enumerate(order):
        Order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and Order[x] > Order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if Order[x] > Order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        print("YES")
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from collections import deque
import sys
sys.setrecursionlimit(10**6)

def solve():
    n, m = map(int, input().split())
    G = [[]for i in range(n+1)]
    edge = []
    for i in range(m):
        t, x, y = map(int, input().split())
        if t == 1:
            G[x].append(y)
        edge.append((t, x, y))

    visited = [False]*(n+1)
    order = [-1]*(n+1)
    que = deque([])

    def bfs(s):
        if visited[s] == False:
            visited[s] = True
            for node in G[s]:
                if visited[node] == False:
                    bfs(node)
            que.appendleft(s)
        else:
            pass

    for i in range(1, n+1):
        bfs(i)

    for i, v in enumerate(que):
        order[v] = i + 1

    not_dag = False

    ans = []
    for t, x, y in edge:
        if t == 1 and order[x] > order[y]:
            not_dag = True
            break
        else:
            if t == 1:
                ans.append((x, y))
            else:
                if order[x] > order[y]:
                    ans.append((y, x))
                else:
                    ans.append((x, y))

    if not_dag:
        print("NO")
    else:
        for x, y in ans:
            print(x, y)

def main():
    t = int(input())
    for i in range(t):
        solve()
    return

if __name__ == "__main__":
    main()


from sys import setrecursionlimit
setrecursionlimit(10 ** 9)

import threading
threading.stack_size(67108864)

def dfs(v):
    global used, ts, ok, u
    used[v] = 1
    for i in u[v]:
        if used[i] == 0:
            dfs(i)
        elif used[i] == 1:
            ok = False
            #return
    used[v] = 2
    ts.append(v)

def main():
    global used, ts, ok, u
    ans = []
    for _ in range(int(input())):
        n, m = map(int, input().split())
        u = []
        w = []
        for i in range(n):
            u.append([])
            w.append([])
        for i in range(m):
            t, a, b = map(lambda x: int(x) - 1, input().split())
            if t == -1:
                w[a].append(b)
                w[b].append(a)
            else:
                u[a].append(b)
        ok = True
        ts = []
        used = [0] * n
        for i in range(n):
            if used[i] == 0:
                dfs(i)
        if not ok:
            ans.append('NO')
            continue
        ans.append('YES')
        ts.reverse()
        #ans.append(' '.join(map(str, ts)))
        pr = [False] * n
        for i in range(len(ts)):
            for j in w[ts[i]]:
                if not pr[j]:
                    ans.append(str(ts[i] + 1) + ' ' + str(j + 1))
            pr[ts[i]] = True
        for i in range(n):
            for j in u[i]:
                ans.append(str(i + 1) + ' ' + str(j + 1))
    print('\n'.join(ans))

thread = threading.Thread(target=main)
thread.start()
thread.join()


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices
        self.cnt = 0

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except:
            if self.cnt == 0:
                return True
            else:
                return False

            self.cnt += 1

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except:
            return True

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except:
            return False

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
import traceback

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except Exception as e:
            print(e)
            print(traceback.format_exc())

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices
        self.cnt = 0

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        visited[v] = True
        recStack[v] = True

        for neighbour in self.graph[v]:
            if visited[neighbour] == False:
                if self.isCyclicUtil(neighbour, visited, recStack) == True:
                    return True
            elif recStack[neighbour] == True:
                return True

        recStack[v] = False
        return False

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if n == 100000 and m == 200000:
                    print(node, visited, recStack)
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices
        self.cnt = 0

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except:
            if self.cnt == 0:
                return False
            else:
                return True

            self.cnt += 1

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
import sys
import linecache

setrecursionlimit(10 ** 9)

def print_exception():
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    print('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj))

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except Exception as e:
            print_exception()

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
import sys
import linecache

setrecursionlimit(10 ** 9)

def print_exception():
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    print 'EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except Exception as e:
            print_exception()

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
import traceback

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except Exception as e:
            print(traceback.format_exc())

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self, vertices):
        self.graph = {}
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u] = self.graph.get(u, []) + [v]

    def isCyclicUtil(self, v, visited, recStack):

        visited[v] = True
        recStack[v] = True

        for neighbour in self.graph.get(v, []):
            if visited[neighbour] == False:
                if self.isCyclicUtil(neighbour, visited, recStack) == True:
                    return True
            elif recStack[neighbour] == True:
                return True

        recStack[v] = False
        return False

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
import sys

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except Exception as e:
            print(sys.exc_info()[2].tb_lineno)

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
import sys
import linecache

setrecursionlimit(10 ** 9)

def print_exception():
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    print('LINE {}'.format(lineno))

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False

        except Exception as e:
            print_exception()

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit
from sys import stdin

input = stdin.readline
setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):

        visited[v] = True
        recStack[v] = True

        for neighbour in self.graph[v]:
            if visited[neighbour] == False:
                if self.isCyclicUtil(neighbour, visited, recStack) == True:
                    return True
            elif recStack[neighbour] == True:
                return True

        recStack[v] = False
        return False

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices
        self.cnt = 0

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False
        except Exception as e:
            print(e)

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if n == 100000 and m == 200000:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices
        self.cnt = 0

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        try:
            visited[v] = True
            recStack[v] = True

            for neighbour in self.graph[v]:
                if visited[neighbour] == False:
                    if self.isCyclicUtil(neighbour, visited, recStack) == True:
                        return True
                elif recStack[neighbour] == True:
                    return True

            recStack[v] = False
            return False
        except Exception as e:
            print(e)

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        visited[v] = True
        recStack[v] = True

        for neighbour in self.graph[v]:
            if visited[neighbour] == False:
                if self.isCyclicUtil(neighbour, visited, recStack) == True:
                    return True
            elif recStack[neighbour] == True:
                return True

        recStack[v] = False
        return False

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

class Graph():
    def __init__(self,vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):

        visited[v] = True
        recStack[v] = True

        for neighbour in self.graph[v]:
            if visited[neighbour] == False:
                if self.isCyclicUtil(neighbour, visited, recStack) == True:
                    return True
            elif recStack[neighbour] == True:
                return True

        recStack[v] = False
        return False

    def isCyclic(self):
        visited = [False] * self.V
        recStack = [False] * self.V
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node,visited,recStack) == True:
                    return True
        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg[u] = dg.get(u, []) + [v]
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u+1, v+1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []
    order = []
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v)
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]:
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]

class Graph():
    def __init__(self, vertices):
        self.graph = defaultdict(list)
        self.V = vertices

        self.visited = [False] * self.V
        self.recStack = [False] * self.V

    def addEdge(self, u, v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v):
        try:
            self.visited[v] = True
            self.recStack[v] = True

            for neighbour in self.graph[v]:
                if not self.visited[neighbour]:
                    if self.isCyclicUtil(neighbour):
                        return True
                elif self.recStack[neighbour]:
                    return True

            self.recStack[v] = False
            return False

        except Exception as e:
            pass

    def isCyclic(self):
        for node in range(self.V):
            if not self.visited[node]:
                if self.isCyclicUtil(node):
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg.addEdge(u, v)
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u + 1, v + 1)


from collections import defaultdict
from sys import setrecursionlimit

setrecursionlimit(10 ** 9)

def topological_sort(graph, start):
    seen = set()
    stack = []
    order = []
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v)
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]:
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]

class Graph():
    def __init__(self, vertices):
        self.graph = defaultdict(list)
        self.V = vertices

        self.visited = [False] * self.V
        self.recStack = [False] * self.V

    def addEdge(self, u, v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v):
        try:
            self.visited[v] = True
            self.recStack[v] = True

            for neighbour in self.graph[v]:
                if not self.visited[neighbour]:
                    if self.isCyclicUtil(neighbour):
                        return True
                elif self.recStack[neighbour]:
                    return True

            self.recStack[v] = False
            return False

        except Exception as e:
            print(":(")

    def isCyclic(self):
        for node in range(self.V):
            if not self.visited[node]:
                if self.isCyclicUtil(node):
                    return True

        return False

for _ in range(int(input())):
    n, m = map(int, input().split())

    graph = [[] for _ in range(n)]
    degrees = [0] * n

    dg = Graph(n)

    undirected = []

    for _ in range(m):
        w, u, v = map(int, input().split())
        u -= 1
        v -= 1

        if w:
            dg.addEdge(u, v)
            graph[u].append(v)
            degrees[v] += 1
        else:
            undirected.append((u, v))

    if dg.isCyclic():
        print('NO')
        continue

    top = []

    for u in range(n):
        if degrees[u] == 0:
            top.extend(topological_sort(graph, u))

    if not top:
        print('NO')
        continue

    d = {}

    for i in range(len(top)):
        d[top[i]] = i

    for u, v in undirected:
        try:
            if d[u] < d[v]:
                dg.addEdge(u, v)
                graph[u].append(v)
            else:
                dg.addEdge(v, u)
                graph[v].append(u)
        except:
            dg.addEdge(u, v)
            graph[u].append(v)

    if dg.isCyclic():
        print('NO')
        continue

    print('YES')

    for u in range(n):
        for v in graph[u]:
            print(u + 1, v + 1)


import queue

class Task:

    def __init__(self) -> None:
        self.nedges = 0
        self.nvertices = 0
        self.directed = {}
        self.undirected = []
        self.position = {}

    def pos(self, u) -> int:
        if u in self.position:
            return self.position[u]
        return 0

    def ReadInput(self) -> None:
        self.nvertices, self.nedges = map(int, input().split())

        for _ in range(self.nedges):
            t, start, end = map(int, input().split())

            if t == 1:
                if start in self.directed:
                    self.directed[start].append(end)
                else:
                    self.directed[start] = [end]
            else:
                self.undirected.append((start, end))

    def WriteOutput(self) -> None:
        if not self.Topsort():
            print('NO')
            return

        for u in range(1, self.nvertices + 1):
            if u in self.directed:
                for v in self.directed[u]:
                    if self.pos(u) >= self.pos(v):
                        print('NO')
                        return

        print("YES")

        for u in self.directed:
            for v in self.directed[u]:
                print(u, v)

        for u, v in self.undirected:
            if self.pos(u) < self.pos(v):
                print(u, v)
            else:
                print(v, u)

    def Topsort(self) -> bool:
        Q = queue.Queue()
        ideg = {}
        position = 1

        for u in range(1, self.nvertices + 1):
            if u in self.directed:
                for v in self.directed[u]:
                    if v in ideg:
                        ideg[v] += 1
                    else:
                        ideg[v] = 1

        for u in range(1, self.nvertices + 1):
            if u not in ideg:
                Q.put(u)

        if Q.empty():
            return False

        while not Q.empty():
            u = Q.get()
            self.position[u] = position
            position += 1

            if u in self.directed:
                for v in self.directed[u]:
                    ideg[v] -= 1
                    if ideg[v] == 0:
                        Q.put(v)
        return True

def main() -> None:
    ntests = int(input())
    for _ in range(ntests):
        task = Task()
        task.ReadInput()
        task.WriteOutput()

if __name__ == '__main__':
    main()


import queue

class Task:

    def __init__(self) -> None:
        self.nedges = 0
        self.nvertices = 0
        self.directed = {}
        self.undirected = []
        self.position = {}

    def ReadInput(self) -> None:
        self.nvertices, self.nedges = map(int, input().split())

        for _ in range(self.nedges):
            t, start, end = map(int, input().split())

            if t == 1:
                if start in self.directed:
                    self.directed[start].append(end)
                else:
                    self.directed[start] = [end]
            else:
                self.undirected.append((start, end))

    def WriteOutput(self) -> None:
        if not self.Topsort():
            print('NO')
            return

        for u in range(1, self.nvertices + 1):
            if u in self.directed:
                for v in self.directed[u]:
                    if self.position[u] >= self.position[v]:
                        print('NO')
                        return

        print("YES")

        for u in self.directed:
            for v in self.directed[u]:
                print(u, v)

        for u, v in self.undirected:
            if self.position[u] < self.position[v]:
                print(u, v)
            else:
                print(v, u)

    def Topsort(self) -> bool:
        Q = queue.Queue()
        ideg = {}
        position = 1

        for u in range(1, self.nvertices + 1):
            if u in self.directed:
                for v in self.directed[u]:
                    if v in ideg:
                        ideg[v] += 1
                    else:
                        ideg[v] = 1

        for u in range(1, self.nvertices + 1):
            if u not in ideg:
                Q.put(u)

        if Q.empty():
            return False

        while not Q.empty():
            u = Q.get()
            self.position[u] = position
            position += 1

            if u in self.directed:
                for v in self.directed[u]:
                    ideg[v] -= 1
                    if ideg[v] == 0:
                        Q.put(v)
        return True

def main() -> None:
    ntests = int(input())
    for _ in range(ntests):
        task = Task()
        task.ReadInput()
        task.WriteOutput()

if __name__ == '__main__':
    main()


import queue

class Task:

    def __init__(self) -> None:
        self.nedges = 0
        self.nvertices = 0
        self.directed = {}
        self.undirected = []
        self.position = {}

    def pos(self, u: int) -> int:
        if u in self.position:
            return self.position[u]
        return 0

    def ReadInput(self) -> None:
        self.nvertices, self.nedges = map(int, input().split())

        for _ in range(self.nedges):
            t, start, end = map(int, input().split())

            if t == 1:
                if start in self.directed:
                    self.directed[start].append(end)
                else:
                    self.directed[start] = [end]
            else:
                self.undirected.append((start, end))

    def WriteOutput(self) -> None:
        if not self.Topsort():
            print('NO')
            return

        for u in range(1, self.nvertices + 1):
            if u in self.directed:
                for v in self.directed[u]:
                    if self.pos(u) >= self.pos(v):
                        print('NO')
                        return

        print("YES")

        for u in self.directed:
            for v in self.directed[u]:
                print(u, v)

        for u, v in self.undirected:
            if self.pos(u) < self.pos(v):
                print(u, v)
            else:
                print(v, u)

    def Topsort(self) -> bool:
        Q = queue.Queue()
        ideg = {}
        position = 1

        for u in range(1, self.nvertices + 1):
            if u in self.directed:
                for v in self.directed[u]:
                    if v in ideg:
                        ideg[v] += 1
                    else:
                        ideg[v] = 1

        for u in range(1, self.nvertices + 1):
            if u not in ideg:
                Q.put(u)

        if Q.empty():
            return False

        while not Q.empty():
            u = Q.get()
            self.position[u] = position
            position += 1

            if u in self.directed:
                for v in self.directed[u]:
                    ideg[v] -= 1
                    if ideg[v] == 0:
                        Q.put(v)
        return True

def main() -> None:
    ntests = int(input())
    for _ in range(ntests):
        task = Task()
        task.ReadInput()
        task.WriteOutput()

if __name__ == '__main__':
    main()


for _ in range(int(input())):
  n,m=map(int,input().split())
  go={i:set() for i in range(1,n+1)}
  gi={i:set() for i in range(1,n+1)}
  eu=[]
  ed=[]
  for i in range(m):
    t,x,y=map(int,input().split())
    if t:
      go[x]|={y}
      gi[y]|={x}
      ed+=[(x,y)]
    else:
      eu+=[(x,y)]
  l=[]
  s=[i for i in gi if len(gi[i])==0]
  while s:
    i=s.pop()
    l+=[i]
    for j in go[i]:
      gi[j]-={i}
      if len(gi[j])==0:
        s+=[j]
    go[i]=set()
  #print(go,gi)
  if all(len(i)==0 for i in go.values()):
    print("YES")
    for i in range(1,n+1):
      if i not in l:
        l+=[i]
    for i,j in eu:
      if l.index(i)<l.index(j):
        print(i,j)
      else:
        print(j,i)
    for i,j in ed:
      print(i,j)
  else:
    print("NO")


for _ in range(int(input())):
  n,m=map(int,input().split())
  go={i:set() for i in range(1,n+1)}
  gi={i:set() for i in range(1,n+1)}
  eu=[]
  ed=[]
  for i in range(m):
    t,x,y=map(int,input().split())
    if t:
      go[x].add(y)
      gi[y].add(x)
      ed.append((x,y))
    else:
      eu.append((x,y))
  l=[]
  s=[i for i in gi if len(gi[i])==0]
  while s:
    i=s.pop()
    l.append(i)
    for j in go[i]:
      gi[j].discard(i)
      if gi[j]==set():
        s.append(j)
    go[i].clear()
  if any(go.values()):
    print("NO")
  else:
    print("YES")
    x={}
    for i,j in enumerate(l):
      x[j]=i
    for i in range(1,n+1):
      if i not in x:
        x[i]=n+i
    for i,j in eu:
      if x[i]<x[j]:
        print(i,j)
      else:
        print(j,i)
    for i,j in ed:
      print(i,j)


from collections import defaultdict, deque
for _ in range(int(input())):
    n,m = map(int,input().split());gr0 = defaultdict(list);gr1 = defaultdict(list);edges = [];indeg = [0]*(n+1)
    for i in range(m):
        t,x,y = map(int,input().split())
        if t==0:edges.append([x,y])
        else:gr0[x].append(y);indeg[y]+=1
    q = deque();cnt = 0;top = [];mp = {}
    for i in range(1,n+1):
        if indeg[i]==0:q.append(i)
    while q:
        s = q.popleft();top.append(s)
        for i in gr0[s]:
            indeg[i]-=1
            if indeg[i]==0:q.append(i)
        cnt+=1
    if cnt!=n:print("NO");continue
    for i in range(n):mp[top[i]] = i
    for x,y in edges:
        if mp[x]<mp[y]:gr0[x].append(y)
        else:gr0[y].append(x)
    print("YES")
    for i in gr0.keys():
        for j in gr0[i]:print(i,j)


from collections import deque
from collections import defaultdict
for _ in range(int(input())):
    n, m = list(map(int, input().split()))
    ud = defaultdict(list)
    d = defaultdict(list)
    pi = [0] * (n + 1)
    v = [0] * (n + 1)
    pis = [0] * (n + 1)
    u = 0
    co = 0
    for _ in range(m):
        t, a, b = list(map(int, input().split()))
        if (t == 0):
            ud[a].append(b)
            ud[b].append(a)
        else:
            d[a].append(b)
            pi[b] += 1
    queue = deque([])
    for i in range(1, n + 1):
        if (pi[i] == 0):
            queue.append(i)
            pis[i] = co
            co += 1
            v[i] = 1
    # print(pis)
    while (len(queue) != 0):
        a = queue.popleft()
        for i in d[a]:
            pi[i] -= 1
            if (pi[i] == 0):
                queue.append(i)
                pis[i] = co
                co += 1
                v[i] = 1
    if(sum(v) == n):
        print("YES")
    else:
        print("NO")
        continue
    for i in ud:
        for j in ud[i]:
            if (pis[i] < pis[j]):
                print(i, j)
    for i in ud:
        for j in ud[i]:
            if (pis[i] == pis[j] and i<j):
                print(i, j)
    for i in d:
        for j in d[i]:
            print(i, j)


import sys

def toposort(graph):
    res = []
    found = [0] * len(graph)
    stack = list(range(len(graph)))
    while stack:
        node = stack.pop()
        if node < 0:
            res.append(~node)
        elif not found[node]:
            found[node] = 1
            stack.append(~node)
            stack += graph[node]

    # cycle check
    for node in res:
        if any(found[nei] for nei in graph[node]):
            return None
        found[node] = 0

    return res[::-1]

t=int(input())

for _ in range(t):
    n, m = map(int,input().split())
    g = [[] for _ in range(n + 1)]
    ug = []
    for i in range(m):
        t, u, v = map(int,input().split())
        if t == 0:
            ug.append([u, v])
        else:
            g[u].append(v)
    sorted = toposort(g)
    if not sorted:
        print("NO")
    else:
        print("YES")
        index = [0] * (n + 1)
        for i in range(n + 1):
            index[sorted[i]] = i
        for i in range(n + 1):
            for u in g[i]:
                print(i, u)
        for u, v in ug:
            if index[u] < index[v]:
                print(u, v)
            else:
                print(v, u)


import sys

def toposort(graph):
    res = []
    found = [0] * len(graph)
    stack = list(range(len(graph)))
    while stack:
        node = stack.pop()
        if node < 0:
            res.append(~node)
        elif not found[node]:
            found[node] = 1
            stack.append(~node)
            stack += graph[node]

    # cycle check
    for node in res:
        if any(found[nei] for nei in graph[node]):
            return None
        found[node] = 0

    return res[::-1]

t=int(input())

for _ in range(t):
    n, m = map(int,input().split())
    g = [[] for _ in range(n + 1)]
    ug = []
    for i in range(m):
        t, u, v = map(int,input().split())
        if t == 0:
            u.append([u, v])
        else:
            g[u].append(v)
    sorted = toposort(g)
    if not sorted:
        print("NO")
    else:
        print("YES")
        index = [0] * (n + 1)
        for i in range(n + 1):
            index[sorted[i]] = i
        for i in range(n + 1):
            for u in g[i]:
                print(i, u)
        for u, v in ug:
            if index[u] < index[v]:
                print(u, v)
            else:
                print(v, u)


t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	dfs()
	if cycle:
		print("NO")
		continue

	print("YES")

	for i in undirected:
		u = i[0]
		v = i[1]

		if startTime[u] != -1 and startTime[v] != -1:
			if startTime[u]<startTime[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif startTime[u]!=-1:
			startTime[v]=time
			time+=1

			print(u+1, v+1)

		elif startTime[v]!=-1:
			startTime[u]=time
			time+=1
			print(v+1, u+1)

		else:
			startTime[u] = time
			time+=1
			startTime[v] = time
			time+=1

			print(u+1, v+1)

	for i in extra:
		print(i[0], i[1])


import resource, sys
resource.setrlimit(resource.RLIMIT_STACK, (2**29,-1))

sys.setrecursionlimit(10**6)

t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	sortedList = []

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1
		sortedList.append(node)

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	try:
		dfs()
	except Exception as e:
		print(e)

	if cycle:
		print("NO")
		continue

	print("YES")

	count = 0

	final = [-1]*n

	for i in sortedList:
		final[i] = count
		count+=1

	for i in undirected:
		u = i[0]
		v = i[1]

		# print(u, v, startTime[u], startTime[v])

		if final[u] != -1 and final[v] != -1:
			if final[u]>final[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif final[u]!=-1:
			final[v]=count
			count+=1

			print(v+1, u+1)

		elif final[v]!=-1:
			final[u]=count
			count+=1
			print(u+1, v+1)

		else:
			final[u] = count
			count+=1
			final[v] = count
			count+=1

			print(v+1, u+1)

	for i in extra:
		print(i[0], i[1])


import sys

sys.setrecursionlimit(10**6)

t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	sortedList = []

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1
		sortedList.append(node)

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	try:
		dfs()
	except Exception as e:
		print(e)

	if cycle:
		print("NO")
		continue

	print("YES")

	count = 0

	final = [-1]*n

	for i in sortedList:
		final[i] = count
		count+=1

	for i in undirected:
		u = i[0]
		v = i[1]

		# print(u, v, startTime[u], startTime[v])

		if final[u] != -1 and final[v] != -1:
			if final[u]>final[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif final[u]!=-1:
			final[v]=count
			count+=1

			print(v+1, u+1)

		elif final[v]!=-1:
			final[u]=count
			count+=1
			print(u+1, v+1)

		else:
			final[u] = count
			count+=1
			final[v] = count
			count+=1

			print(v+1, u+1)

	for i in extra:
		print(i[0], i[1])


t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	sortedList = []

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1
		sortedList.append(node)

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	dfs()
	if cycle:
		print("NO")
		continue

	print("YES")

	count = 0

	final = [-1]*n

	for i in sortedList:
		final[i] = count
		count+=1

	for i in undirected:
		u = i[0]
		v = i[1]

		# print(u, v, startTime[u], startTime[v])

		if final[u] != -1 and final[v] != -1:
			if final[u]>final[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif final[u]!=-1:
			final[v]=count
			count+=1

			print(v+1, u+1)

		elif final[v]!=-1:
			final[u]=count
			count+=1
			print(u+1, v+1)

		else:
			final[u] = count
			count+=1
			final[v] = count
			count+=1

			print(v+1, u+1)

	for i in extra:
		print(i[0], i[1])


import sys

sys.setrecursionlimit(10**6)

t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	sortedList = []

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1
		sortedList.append(node)

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	try:
		dfs()
	except:
		print("SOME ERROR")
	if cycle:
		print("NO")
		continue

	print("YES")

	count = 0

	final = [-1]*n

	for i in sortedList:
		final[i] = count
		count+=1

	for i in undirected:
		u = i[0]
		v = i[1]

		# print(u, v, startTime[u], startTime[v])

		if final[u] != -1 and final[v] != -1:
			if final[u]>final[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif final[u]!=-1:
			final[v]=count
			count+=1

			print(v+1, u+1)

		elif final[v]!=-1:
			final[u]=count
			count+=1
			print(u+1, v+1)

		else:
			final[u] = count
			count+=1
			final[v] = count
			count+=1

			print(v+1, u+1)

	for i in extra:
		print(i[0], i[1])


import threading, sys

threading.stack_size(2**26)

sys.setrecursionlimit(10**6)

startTime = []
finishTime = []
time = 0
cycle = False

def main():
	global startTime, finishTime, time, cycle
	t = int(input())

	for ii in range(t):

		n, m = map(int, input().split())

		undirected = set()

		directed = []

		extra = []

		for i in range(n):
			directed.append([])

		for i in range(m):
			t, u, v = map(int, input().split())

			if t == 0:
				undirected.add((u-1, v-1))

			else:
				directed[u-1].append(v-1)
				extra.append((u, v))

		startTime = [-1]*n
		finishTime = [-1]*n
		time = 0
		cycle = False

		sortedList = []

		def dfsVisit(node):
			global time
			global cycle
			startTime[node] = time
			time+=1

			for i in directed[node]:
				if startTime[i] == -1:
					dfsVisit(i)
				elif finishTime[i] == -1:
					cycle = True

			finishTime[node] = time
			time+=1
			sortedList.append(node)

		def dfs():
			global cycle
			for i in range(n):
				if startTime[i] == -1:
					dfsVisit(i)
				if cycle:
					break

		dfs()

		if cycle:
			print("NO")
			continue

		print("YES")

		count = 0

		final = [-1]*n

		for i in sortedList:
			final[i] = count
			count+=1

		for i in undirected:
			u = i[0]
			v = i[1]

			# print(u, v, startTime[u], startTime[v])

			if final[u] != -1 and final[v] != -1:
				if final[u]>final[v]:
					print(u+1, v+1)
				else:
					print(v+1, u+1)

			elif final[u]!=-1:
				final[v]=count
				count+=1

				print(v+1, u+1)

			elif final[v]!=-1:
				final[u]=count
				count+=1
				print(u+1, v+1)

			else:
				final[u] = count
				count+=1
				final[v] = count
				count+=1

				print(v+1, u+1)

		for i in extra:
			print(i[0], i[1])

threading.Thread(target=main).start()


try:
	import resource, sys
	resource.setrlimit(resource.RLIMIT_STACK, (2**29,-1))

	sys.setrecursionlimit(10**6)

	t = int(input())

	for ii in range(t):

		n, m = map(int, input().split())

		undirected = set()

		directed = []

		extra = []

		for i in range(n):
			directed.append([])

		for i in range(m):
			t, u, v = map(int, input().split())

			if t == 0:
				undirected.add((u-1, v-1))

			else:
				directed[u-1].append(v-1)
				extra.append((u, v))

		startTime = [-1]*n
		finishTime = [-1]*n
		time = 0
		cycle = False

		sortedList = []

		def dfsVisit(node):
			global time
			global cycle
			startTime[node] = time
			time+=1

			for i in directed[node]:
				if startTime[i] == -1:
					dfsVisit(i)
				elif finishTime[i] == -1:
					cycle = True

			finishTime[node] = time
			time+=1
			sortedList.append(node)

		def dfs():
			global cycle
			for i in range(n):
				if startTime[i] == -1:
					dfsVisit(i)
				if cycle:
					break

		try:
			dfs()
		except Exception as e:
			print(e)

		if cycle:
			print("NO")
			continue

		print("YES")

		count = 0

		final = [-1]*n

		for i in sortedList:
			final[i] = count
			count+=1

		for i in undirected:
			u = i[0]
			v = i[1]

			# print(u, v, startTime[u], startTime[v])

			if final[u] != -1 and final[v] != -1:
				if final[u]>final[v]:
					print(u+1, v+1)
				else:
					print(v+1, u+1)

			elif final[u]!=-1:
				final[v]=count
				count+=1

				print(v+1, u+1)

			elif final[v]!=-1:
				final[u]=count
				count+=1
				print(u+1, v+1)

			else:
				final[u] = count
				count+=1
				final[v] = count
				count+=1

				print(v+1, u+1)

		for i in extra:
			print(i[0], i[1])

except Exception as e:
	print(e, "In end")


import sys

sys.setrecursionlimit(10**6)

t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	sortedList = []

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1
		sortedList.append(node)

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	try:
		dfs()
	except RecursionError:
		print("SOME ERROR")

	if cycle:
		print("NO")
		continue

	print("YES")

	count = 0

	final = [-1]*n

	for i in sortedList:
		final[i] = count
		count+=1

	for i in undirected:
		u = i[0]
		v = i[1]

		# print(u, v, startTime[u], startTime[v])

		if final[u] != -1 and final[v] != -1:
			if final[u]>final[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif final[u]!=-1:
			final[v]=count
			count+=1

			print(v+1, u+1)

		elif final[v]!=-1:
			final[u]=count
			count+=1
			print(u+1, v+1)

		else:
			final[u] = count
			count+=1
			final[v] = count
			count+=1

			print(v+1, u+1)

	for i in extra:
		print(i[0], i[1])


import sys

sys.setrecursionlimit(10**6)

t = int(input())

for ii in range(t):

	n, m = map(int, input().split())

	undirected = set()

	directed = []

	extra = []

	for i in range(n):
		directed.append([])

	for i in range(m):
		t, u, v = map(int, input().split())

		if t == 0:
			undirected.add((u-1, v-1))

		else:
			directed[u-1].append(v-1)
			extra.append((u, v))

	startTime = [-1]*n
	finishTime = [-1]*n
	time = 0
	cycle = False

	sortedList = []

	def dfsVisit(node):
		global time
		global cycle
		startTime[node] = time
		time+=1

		for i in directed[node]:
			if startTime[i] == -1:
				dfsVisit(i)
			elif finishTime[i] == -1:
				cycle = True

		finishTime[node] = time
		time+=1
		sortedList.append(node)

	def dfs():
		global cycle
		for i in range(n):
			if startTime[i] == -1:
				dfsVisit(i)
			if cycle:
				break

	dfs()
	if cycle:
		print("NO")
		continue

	print("YES")

	count = 0

	final = [-1]*n

	for i in sortedList:
		final[i] = count
		count+=1

	for i in undirected:
		u = i[0]
		v = i[1]

		# print(u, v, startTime[u], startTime[v])

		if final[u] != -1 and final[v] != -1:
			if final[u]>final[v]:
				print(u+1, v+1)
			else:
				print(v+1, u+1)

		elif final[u]!=-1:
			final[v]=count
			count+=1

			print(v+1, u+1)

		elif final[v]!=-1:
			final[u]=count
			count+=1
			print(u+1, v+1)

		else:
			final[u] = count
			count+=1
			final[v] = count
			count+=1

			print(v+1, u+1)

	for i in extra:
		print(i[0], i[1])