def main():
    import sys
    from collections import deque, defaultdict
    from heapq import heappop, heappush
    sys.setrecursionlimit(10**9)
    input = sys.stdin.readline
    for __ in [0]*int(input()):
        N, M = map(int, input().split())
        deg = [0]*N
        directed = defaultdict(list)
        undirected = defaultdict(list)
        for _ in [0]*M:
            t, a, b = map(int, input().split())
            a -= 1
            b -= 1
            if t:
                directed[a].append(b)
                deg[b] += 1
            else:
                undirected[a].append(b)
                undirected[b].append(a)

        q = deque([i for i, d in enumerate(deg) if d == 0])
        topological = []
        while q:
            v = q.popleft()
            topological.append(v)
            if v not in directed:
                continue
            for u in directed[v]:
                deg[u] -= 1
                if deg[u] == 0:
                    q.append(u)
        if len(topological) != N:
            print('NO')
            continue

        del deg

        print('YES')

        used = [0]*N
        for v in topological:
            if v in directed:
                for u in directed[v]:
                    print(v+1, u+1)
            if v in undirected:
                for u in undirected[v]:
                    if used[u]:
                        continue
                    print(v+1, u+1)
            used[v] = 1

        del used

if __name__ == '__main__':
    main()


from collections import deque

def solve():
    n, m = map(int, raw_input().split())

    d = [0] * n
    e = [[] for i in range(n)]
    u = {}
    for i in range(m):
        t, x, y = map(int, raw_input().split())
        x -= 1
        y -= 1
        if t == 1:
            d[y] += 1
            e[x].append(y)
        else:
            e[x].append(y)
            e[y].append(x)
            u[(min(x, y), max(x, y))] = False

    c = 0
    v = [False for i in range(n)]
    z = []
    for i  in range(n):
        if v[i] or d[i] > 0: continue
        v[i] = True
        c += 1
        w = deque([i])
        while len(w) > 0:
            x = w.popleft()
            for y in e[x]:
                k = (min(x, y), max(x, y))
                if k in u:
                    if not u[k]:
                        u[k] = True
                        z.append((x, y))
                else:
                    z.append((x, y))
                    d[y] -= 1

                if v[y] or d[y] > 0: continue
                v[y] = True
                c += 1
                w.append(y)

    if c == n:
        print 'YES'
        for x, y in z: print x + 1, y + 1
    else:
        print 'NO'

t = input()
while t > 0:
    solve()
    t -= 1


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N	200000
#define M	200000

int *oj[N], oo[N];

void link(int i, int j) {
	int o = oo[i]++;

	if (o >= 2 && (o & o - 1) == 0)
		oj[i] = (int *) realloc(oj[i], o * 2 * sizeof *oj[i]);
	oj[i][o] = j;
}

int main() {
	int t;

	scanf("%d", &t);
	while (t--) {
		static int tt[N], ii[N], jj[N], dd[N], qu[N], cc[N];
		int n, m, h, i, j, head, cnt;

		scanf("%d%d", &n, &m);
		for (i = 0; i < n; i++)
			oj[i] = (int *) malloc(2 * sizeof *oj[i]), oo[i] = 0;
		memset(dd, 0, n * sizeof *dd);
		for (h = 0; h < m; h++) {
			scanf("%d%d%d", &tt[h], &ii[h], &jj[h]), ii[h]--, jj[h]--;
			if (tt[h] == 1)
				link(ii[h], jj[h]), dd[jj[h]]++;
		}
		head = cnt = 0;
		for (i = 0; i < n; i++)
			if (dd[i] == 0)
				qu[head + cnt++] = i;
		while (cnt) {
			int o;

			i = qu[cnt--, head++], cc[i] = head;
			for (o = 0; o < oo[i]; o++) {
				j = oj[i][o];
				if (--dd[j] == 0)
					qu[head + cnt++] = j;
			}
		}
		if (head != n)
			printf("NO\n");
		else {
			printf("YES\n");
			for (h = 0; h < m; h++) {
				int tmp;

				i = ii[h], j = jj[h];
				if (tt[h] == 0 && cc[i] > cc[j])
					tmp = i, i = j, j = tmp;
				printf("%d %d\n", i + 1, j + 1);
			}
		}
		for (i = 0; i < n; i++)
			free(oj[i]);
	}
	return 0;
}


#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#define __cmp(x, y, op)                  \
	({                               \
		__typeof((x)) __x = (x); \
		__typeof((y)) __y = (y); \
		__x op __y ? __x : __y;  \
	})

#define max(x, y) __cmp(x, y, >)

static void *
xrealloc(void *ptr, size_t size)
{
	void *retval;

	retval = realloc(ptr, size);
	assert(retval != NULL);

	return retval;
}

struct vector {
	size_t size;
	size_t capacity;
	size_t tsize;
	void *data;
};

static void
vector_init(struct vector *vector, size_t tsize)
{
	bzero(vector, sizeof(*vector));
	vector->tsize = tsize;
}

static void
vector_ensure_capacity(struct vector *vector, size_t capacity)
{
	if (vector->capacity >= capacity)
		return;

	vector->data = xrealloc(vector->data, vector->tsize * capacity);
	vector->capacity = capacity;
}

static void
vector_push(struct vector *vector, void *element)
{
	if (vector->size >= vector->capacity)
		vector_ensure_capacity(vector, max(2 * vector->capacity, 1UL));

	bcopy(element, vector->data + vector->tsize * vector->size,
	    vector->tsize);
	vector->size++;
}

static void *
vector_at(struct vector *vector, size_t index)
{
	if (vector->size <= index)
		return NULL;
	return vector->data + vector->tsize * index;
}

static void
vector_destroy(struct vector *vector)
{
	vector->size = 0;
	vector->capacity = 0;
	vector->tsize = 0;
	free(vector->data);
}

static void
vector_resize(struct vector *vector, size_t size)
{
	vector_ensure_capacity(vector, size);
	vector->size = size;
}

static void
vector_resize_with(struct vector *vector, size_t size, void *data)
{
	size_t n;
	void *ptr;

	vector_ensure_capacity(vector, size);
	ptr = vector->data;
	n = vector->size;

	while (n++ < size) {
		bcopy(data, ptr, vector->tsize);
		ptr += vector->tsize;
	}

	vector->size = size;
}

static void
vector_init_with(struct vector *vector, size_t tsize, size_t size, void *data)
{
	vector_init(vector, tsize);
	vector_resize_with(vector, size, data);
}

struct pair {
	size_t first;
	size_t second;
};

struct task {
	size_t nedges;
	size_t nvertices;
	struct vector directed;
	struct vector undirected;
	struct vector position;
};

static void
task_init(struct task *task)
{
	bzero(task, sizeof(*task));
	vector_init(&task->directed, sizeof(struct vector));
	vector_init(&task->undirected, sizeof(struct pair));
	vector_init(&task->position, sizeof(int));
}

static void
task_destroy(struct task *task)
{
	size_t n;

	vector_destroy(&task->position);
	vector_destroy(&task->undirected);

	for (n = 0; n < task->directed.size; n++)
		vector_destroy(vector_at(&task->directed, n));

	vector_destroy(&task->directed);
}

static void
task_read(struct task *task, FILE *fp)
{
	struct vector *vector;
	struct vector empty;
	size_t edge;
	size_t type, from, to;
	struct pair p;

	vector_init(&empty, sizeof(size_t));

	fscanf(fp, "%lu %lu", &task->nvertices, &task->nedges);

	vector_resize_with(&task->directed, task->nvertices + 1, &empty);
	vector_resize(&task->position, task->nvertices + 1);

	for (edge = 0; edge < task->nedges; edge++) {
		fscanf(fp, "%lu %lu %lu", &type, &from, &to);
		if (type == 1) {
			vector = vector_at(&task->directed, from);
			vector_push(vector, &to);
		} else {
			p = (struct pair){from, to};
			vector_push(&task->undirected, &p);
		}
	}
}

static bool
task_topsort(struct task *task)
{
	struct vector *vector;
	struct vector queue;
	struct vector ideg;
	size_t *p, *i;
	size_t u, n;
	size_t zero = 0;
	size_t idx = 0;
	int *pos;
	int position = 1;
	bool retval = false;

	vector_init(&queue, sizeof(size_t));
	vector_init_with(&ideg, sizeof(size_t), task->nvertices + 1, &zero);

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			(*(int *)vector_at(&ideg, *p))++;
		}
	}

	for (u = 1; u <= task->nvertices; u++) {
		p = vector_at(&ideg, u);
		if (*p == 0)
			vector_push(&queue, &u);
	}

	if (queue.size == 0) {
		retval = false;
		goto out;
	}

	while (idx < queue.size) {
		p = vector_at(&queue, idx);
		idx++;
		pos = vector_at(&task->position, *p);
		*pos = position++;

		vector = vector_at(&task->directed, *p);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			i = vector_at(&ideg, *p);
			if (--(*i) == 0)
				vector_push(&queue, p);
		}
	}

	retval = true;

out:
	vector_destroy(&queue);
	vector_destroy(&ideg);
	return retval;
}

static void
task_write(struct task *task, FILE *fp)
{
	struct pair *pair;
	struct vector *vector;
	size_t *p;
	size_t u, n;

	if (!task_topsort(task))
		goto no;

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			if (*(int *)vector_at(&task->position, u) >=
			    *(int *)vector_at(&task->position, *p))
				goto no;
		}
	}

	fprintf(fp, "YES\n");

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			fprintf(fp, "%lu %lu\n", u, *p);
		}
	}

	for (n = 0; n < task->undirected.size; n++) {
		pair = vector_at(&task->undirected, n);
		if (*(int *)vector_at(&task->position, pair->first) <
		    *(int *)vector_at(&task->position, pair->second)) {
			fprintf(fp, "%lu %lu\n", pair->first, pair->second);
		} else {
			fprintf(fp, "%lu %lu\n", pair->second, pair->first);
		}
	}

	return;

no:
	fprintf(fp, "NO\n");
}

int
main(void)
{
	struct task task;
	size_t ntests;
	size_t n;

	fscanf(stdin, "%lu", &ntests);

	for (n = 0; n < ntests; n++) {
		task_init(&task);
		task_read(&task, stdin);
		task_write(&task, stdout);
		task_destroy(&task);
	}

	return 0;
}


#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define __cmp(x, y, op)                  \
	({                               \
		__typeof((x)) __x = (x); \
		__typeof((y)) __y = (y); \
		__x op __y ? __x : __y;  \
	})

#define max(x, y) __cmp(x, y, >)

static void *
xrealloc(void *ptr, size_t size)
{
	void *retval;

	retval = realloc(ptr, size);
	return retval;
}

static void
bcopy(const void *src, void *dest, size_t n)
{
	memcpy(dest, src, n);
}

static void
bzero(void *s, size_t n)
{
	memset(s, 0, n);
}

struct vector {
	size_t size;
	size_t capacity;
	size_t tsize;
	void *data;
};

static void
vector_init(struct vector *vector, size_t tsize)
{
	bzero(vector, sizeof(*vector));
	vector->tsize = tsize;
}

static void
vector_ensure_capacity(struct vector *vector, size_t capacity)
{
	if (vector->capacity >= capacity)
		return;

	vector->data = xrealloc(vector->data, vector->tsize * capacity);
	vector->capacity = capacity;
}

static void
vector_push(struct vector *vector, void *element)
{
	if (vector->size >= vector->capacity)
		vector_ensure_capacity(vector, max(2 * vector->capacity, 1UL));

	bcopy(element, vector->data + vector->tsize * vector->size,
	    vector->tsize);
	vector->size++;
}

static void *
vector_at(struct vector *vector, size_t index)
{
	return vector->data + vector->tsize * index;
}

static void
vector_destroy(struct vector *vector)
{
	vector->size = 0;
	vector->capacity = 0;
	vector->tsize = 0;
	free(vector->data);
}

static void
vector_resize(struct vector *vector, size_t size)
{
	vector_ensure_capacity(vector, size);
	vector->size = size;
}

static void
vector_resize_with(struct vector *vector, size_t size, void *data)
{
	size_t n;
	void *ptr;

	vector_ensure_capacity(vector, size);
	ptr = vector->data;
	n = vector->size;

	while (n++ < size) {
		bcopy(data, ptr, vector->tsize);
		ptr += vector->tsize;
	}

	vector->size = size;
}

static void
vector_init_with(struct vector *vector, size_t tsize, size_t size, void *data)
{
	vector_init(vector, tsize);
	vector_resize_with(vector, size, data);
}

struct pair {
	size_t first;
	size_t second;
};

struct task {
	size_t nedges;
	size_t nvertices;
	struct vector directed;
	struct vector undirected;
	struct vector position;
};

static void
task_init(struct task *task)
{
	bzero(task, sizeof(*task));
	vector_init(&task->directed, sizeof(struct vector));
	vector_init(&task->undirected, sizeof(struct pair));
	vector_init(&task->position, sizeof(int));
}

static void
task_destroy(struct task *task)
{
	size_t n;

	vector_destroy(&task->position);
	vector_destroy(&task->undirected);

	for (n = 0; n < task->directed.size; n++)
		vector_destroy(vector_at(&task->directed, n));

	vector_destroy(&task->directed);
}

static void
task_read(struct task *task, FILE *fp)
{
	struct vector *vector;
	struct vector empty;
	size_t edge;
	size_t type, from, to;
	struct pair p;

	vector_init(&empty, sizeof(size_t));

	fscanf(fp, "%lu %lu", &task->nvertices, &task->nedges);

	vector_resize_with(&task->directed, task->nvertices + 1, &empty);
	vector_resize(&task->position, task->nvertices + 1);

	for (edge = 0; edge < task->nedges; edge++) {
		fscanf(fp, "%lu %lu %lu", &type, &from, &to);
		if (type == 1) {
			vector = vector_at(&task->directed, from);
			vector_push(vector, &to);
		} else {
			p = (struct pair){from, to};
			vector_push(&task->undirected, &p);
		}
	}
}

static bool
task_topsort(struct task *task)
{
	struct vector *vector;
	struct vector queue;
	struct vector ideg;
	size_t *p, *i;
	size_t u, n;
	size_t zero = 0;
	size_t idx = 0;
	int *pos;
	int position = 1;
	bool retval = false;

	vector_init(&queue, sizeof(size_t));
	vector_init_with(&ideg, sizeof(size_t), task->nvertices + 1, &zero);

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			(*(int *)vector_at(&ideg, *p))++;
		}
	}

	for (u = 1; u <= task->nvertices; u++) {
		p = vector_at(&ideg, u);
		if (*p == 0)
			vector_push(&queue, &u);
	}

	if (queue.size == 0) {
		retval = false;
		goto out;
	}

	while (idx < queue.size) {
		p = vector_at(&queue, idx);
		idx++;
		pos = vector_at(&task->position, *p);
		*pos = position++;

		vector = vector_at(&task->directed, *p);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			i = vector_at(&ideg, *p);
			if (--(*i) == 0)
				vector_push(&queue, p);
		}
	}

	retval = true;

out:
	vector_destroy(&queue);
	vector_destroy(&ideg);
	return retval;
}

static void
task_write(struct task *task, FILE *fp)
{
	struct pair *pair;
	struct vector *vector;
	size_t *p;
	size_t u, n;

	if (!task_topsort(task))
		goto no;

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			if (*(int *)vector_at(&task->position, u) >=
			    *(int *)vector_at(&task->position, *p))
				goto no;
		}
	}

	fprintf(fp, "YES\n");

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			fprintf(fp, "%lu %lu\n", u, *p);
		}
	}

	for (n = 0; n < task->undirected.size; n++) {
		pair = vector_at(&task->undirected, n);
		if (*(int *)vector_at(&task->position, pair->first) <
		    *(int *)vector_at(&task->position, pair->second)) {
			fprintf(fp, "%lu %lu\n", pair->first, pair->second);
		} else {
			fprintf(fp, "%lu %lu\n", pair->second, pair->first);
		}
	}

	return;

no:
	fprintf(fp, "NO\n");
}

int
main(void)
{
	struct task task;
	size_t ntests;
	size_t n;

	fscanf(stdin, "%lu", &ntests);

	for (n = 0; n < ntests; n++) {
		task_init(&task);
		task_read(&task, stdin);
		task_write(&task, stdout);
		task_destroy(&task);
	}

	return 0;
}


#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define __cmp(x, y, op)                  \
	({                               \
		__typeof((x)) __x = (x); \
		__typeof((y)) __y = (y); \
		__x op __y ? __x : __y;  \
	})

#define max(x, y) __cmp(x, y, >)

static void *
xrealloc(void *ptr, size_t size)
{
	void *retval;

	retval = realloc(ptr, size);
	assert(retval != NULL);

	return retval;
}

static void
bcopy(const void *src, void *dest, size_t n)
{
	memcpy(dest, src, n);
}

static void
bzero(void *s, size_t n)
{
	memset(s, 0, n);
}

struct vector {
	size_t size;
	size_t capacity;
	size_t tsize;
	void *data;
};

static void
vector_init(struct vector *vector, size_t tsize)
{
	bzero(vector, sizeof(*vector));
	vector->tsize = tsize;
}

static void
vector_ensure_capacity(struct vector *vector, size_t capacity)
{
	if (vector->capacity >= capacity)
		return;

	vector->data = xrealloc(vector->data, vector->tsize * capacity);
	vector->capacity = capacity;
}

static void
vector_push(struct vector *vector, void *element)
{
	if (vector->size >= vector->capacity)
		vector_ensure_capacity(vector, max(2 * vector->capacity, 1UL));

	bcopy(element, vector->data + vector->tsize * vector->size,
	    vector->tsize);
	vector->size++;
}

static void *
vector_at(struct vector *vector, size_t index)
{
	if (vector->size <= index)
		return NULL;
	return vector->data + vector->tsize * index;
}

static void
vector_destroy(struct vector *vector)
{
	vector->size = 0;
	vector->capacity = 0;
	vector->tsize = 0;
	free(vector->data);
}

static void
vector_resize(struct vector *vector, size_t size)
{
	vector_ensure_capacity(vector, size);
	vector->size = size;
}

static void
vector_resize_with(struct vector *vector, size_t size, void *data)
{
	size_t n;
	void *ptr;

	vector_ensure_capacity(vector, size);
	ptr = vector->data;
	n = vector->size;

	while (n++ < size) {
		bcopy(data, ptr, vector->tsize);
		ptr += vector->tsize;
	}

	vector->size = size;
}

static void
vector_init_with(struct vector *vector, size_t tsize, size_t size, void *data)
{
	vector_init(vector, tsize);
	vector_resize_with(vector, size, data);
}

struct pair {
	size_t first;
	size_t second;
};

struct task {
	size_t nedges;
	size_t nvertices;
	struct vector directed;
	struct vector undirected;
	struct vector position;
};

static void
task_init(struct task *task)
{
	bzero(task, sizeof(*task));
	vector_init(&task->directed, sizeof(struct vector));
	vector_init(&task->undirected, sizeof(struct pair));
	vector_init(&task->position, sizeof(int));
}

static void
task_destroy(struct task *task)
{
	size_t n;

	vector_destroy(&task->position);
	vector_destroy(&task->undirected);

	for (n = 0; n < task->directed.size; n++)
		vector_destroy(vector_at(&task->directed, n));

	vector_destroy(&task->directed);
}

static void
task_read(struct task *task, FILE *fp)
{
	struct vector *vector;
	struct vector empty;
	size_t edge;
	size_t type, from, to;
	struct pair p;

	vector_init(&empty, sizeof(size_t));

	fscanf(fp, "%lu %lu", &task->nvertices, &task->nedges);

	vector_resize_with(&task->directed, task->nvertices + 1, &empty);
	vector_resize(&task->position, task->nvertices + 1);

	for (edge = 0; edge < task->nedges; edge++) {
		fscanf(fp, "%lu %lu %lu", &type, &from, &to);
		if (type == 1) {
			vector = vector_at(&task->directed, from);
			vector_push(vector, &to);
		} else {
			p = (struct pair){from, to};
			vector_push(&task->undirected, &p);
		}
	}
}

static bool
task_topsort(struct task *task)
{
	struct vector *vector;
	struct vector queue;
	struct vector ideg;
	size_t *p, *i;
	size_t u, n;
	size_t zero = 0;
	size_t idx = 0;
	int *pos;
	int position = 1;
	bool retval = false;

	vector_init(&queue, sizeof(size_t));
	vector_init_with(&ideg, sizeof(size_t), task->nvertices + 1, &zero);

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			(*(int *)vector_at(&ideg, *p))++;
		}
	}

	for (u = 1; u <= task->nvertices; u++) {
		p = vector_at(&ideg, u);
		if (*p == 0)
			vector_push(&queue, &u);
	}

	if (queue.size == 0) {
		retval = false;
		goto out;
	}

	while (idx < queue.size) {
		p = vector_at(&queue, idx);
		idx++;
		pos = vector_at(&task->position, *p);
		*pos = position++;

		vector = vector_at(&task->directed, *p);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			i = vector_at(&ideg, *p);
			if (--(*i) == 0)
				vector_push(&queue, p);
		}
	}

	retval = true;

out:
	vector_destroy(&queue);
	vector_destroy(&ideg);
	return retval;
}

static void
task_write(struct task *task, FILE *fp)
{
	struct pair *pair;
	struct vector *vector;
	size_t *p;
	size_t u, n;

	if (!task_topsort(task))
		goto no;

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			if (*(int *)vector_at(&task->position, u) >=
			    *(int *)vector_at(&task->position, *p))
				goto no;
		}
	}

	fprintf(fp, "YES\n");

	for (u = 1; u <= task->nvertices; u++) {
		vector = vector_at(&task->directed, u);
		for (n = 0; n < vector->size; n++) {
			p = vector_at(vector, n);
			fprintf(fp, "%lu %lu\n", u, *p);
		}
	}

	for (n = 0; n < task->undirected.size; n++) {
		pair = vector_at(&task->undirected, n);
		if (*(int *)vector_at(&task->position, pair->first) <
		    *(int *)vector_at(&task->position, pair->second)) {
			fprintf(fp, "%lu %lu\n", pair->first, pair->second);
		} else {
			fprintf(fp, "%lu %lu\n", pair->second, pair->first);
		}
	}

	return;

no:
	fprintf(fp, "NO\n");
}

int
main(void)
{
	struct task task;
	size_t ntests;
	size_t n;

	fscanf(stdin, "%lu", &ntests);

	for (n = 0; n < ntests; n++) {
		task_init(&task);
		task_read(&task, stdin);
		task_write(&task, stdout);
		task_destroy(&task);
	}

	return 0;
}


let inputString = "";
let currentLine = 0;
process.stdin.on("data", (data) => {
  inputString += data;
});
process.stdin.on("end", function () {
  inputString = inputString
    .trim()
    .split("\n")
    .map((str) => str.trim());
  main();
});
function readLine() {
  return inputString[currentLine++];
}
function main() {
  let t = +readLine();
  while (t--) {
    let [v, e] = readLine()
      .split(" ")
      .map((n) => parseInt(n));
    const result = [];
    const queue = [];
    const list = {};
    const indegrees = Array(v + 1).fill(0);
    const pairs = [];
    const positions = [];

    for (let i = 0; i < e; i++) {
      let [directed, src, destination] = readLine()
        .split(" ")
        .map((n) => parseInt(n));
      pairs.push([directed, src, destination]);
      if (directed) {
        if (!list[src]) list[src] = [destination];
        else list[src].push(destination);
        indegrees[destination]++;
      }
    }

    for (let i = 1; i <= v; i++) {
      if (indegrees[i] === 0) {
        queue.push(i);
      }
    }

    let index = 0;
    while (queue.length) {
      const u = queue.shift();
      result.push(u);
      positions[u] = index;
      index++;
      if (list[u]) {
        for (let i = 0; i < list[u].length; i++) {
          const v = list[u][i];
          if (--indegrees[v] === 0) {
            queue.push(v);
          }
        }
      }
    }

    if (result.length < v) {
      console.log("NO");
      continue;
    } else {
      console.log("YES");
      pairs.forEach(([directed, src, destination]) => {
        if (directed) {
          console.log(`${src} ${destination}`);
        } else {
          if (positions[src] < positions[destination]) {
            console.log(`${src} ${destination}`);
          } else {
            console.log(`${destination} ${src}`);
          }
        }
      });
    }
  }
}


let inputString = "";
let currentLine = 0;
process.stdin.on("data", (data) => {
  inputString += data;
});
process.stdin.on("end", function () {
  inputString = inputString
    .trim()
    .split("\n")
    .map((str) => str.trim());
  main();
});
function readLine() {
  return inputString[currentLine++];
}
function main() {
  let t = +readLine();
  while (t--) {
    let [v, e] = readLine()
      .split(" ")
      .map((n) => parseInt(n));
    const result = [];
    const queue = [];
    const list = {};
    const indegrees = Array(v + 1).fill(0);
    const pairs = [];

    for (let i = 0; i < e; i++) {
      let [directed, src, destination] = readLine()
        .split(" ")
        .map((n) => parseInt(n));
      pairs.push([directed, src, destination]);
      if (directed) {
        if (!list[src]) list[src] = [destination];
        else list[src].push(destination);
        indegrees[destination]++;
      }
    }

    for (let i = 1; i <= v; i++) {
      if (indegrees[i] === 0) {
        queue.push(i);
      }
    }

    while (queue.length) {
      const u = queue.shift();
      result.push(u);
      if (list[u]) {
        for (let i = 0; i < list[u].length; i++) {
          const v = list[u][i];
          if (--indegrees[v] === 0) {
            queue.push(v);
          }
        }
      }
    }

    const resultMap = result.reduce((obj, num, index) => {
      obj[num] = index;
      return obj;
    }, {});

    if (result.length < v) {
      console.log("NO");
    } else {
      console.log("YES");
      pairs.forEach(([directed, src, destination]) => {
        if (directed) {
          console.log(`${src} ${destination}`);
        } else {
          if (resultMap[src] < resultMap[destination]) {
            console.log(`${src} ${destination}`);
          } else {
            console.log(`${destination} ${src}`);
          }
        }
      });
    }
  }
}


let inputString = "";
let currentLine = 0;
process.stdin.on("data", (data) => {
  inputString += data;
});
process.stdin.on("end", function () {
  inputString = inputString
    .trim()
    .split("\n")
    .map((str) => str.trim());
  main();
});
function readLine() {
  return inputString[currentLine++];
}
function main() {
  let t = +readLine();
  while (t--) {
    let [v, e] = readLine()
      .split(" ")
      .map((n) => parseInt(n));
    const queue = [];
    const list = {};
    const indegrees = Array(v + 1).fill(0);
    const directedpairs = [];
    const nonDirectedpairs = [];
    const positions = [];

    for (let i = 0; i < e; i++) {
      let [directed, src, destination] = readLine()
        .split(" ")
        .map((n) => parseInt(n));
      if (directed) {
        if (!list[src]) list[src] = [destination];
        else list[src].push(destination);

        indegrees[destination]++;
        directedpairs.push([src, destination]);
      } else {
        nonDirectedpairs.push([src, destination]);
      }
    }

    for (let i = 1; i <= v; i++) {
      if (indegrees[i] === 0) {
        queue.push(i);
      }
    }

    let index = 0;
    while (queue.length) {
      const u = queue.shift();
      positions[u] = index;
      index++;
      if (list[u]) {
        for (let i = 0; i < list[u].length; i++) {
          const v = list[u][i];
          if (--indegrees[v] === 0) {
            queue.push(v);
          }
        }
      }
    }

    if (index < v) {
      console.log("NO");
      continue;
    } else {
      console.log("YES");
      for (let i = 0; i < directedpairs.length; i++) {
        let [src, destination] = directedpairs[i];
        console.log(`${src} ${destination}`);
      }

      for (let i = 0; i < nonDirectedpairs.length; i++) {
        let [src, destination] = nonDirectedpairs[i];
        if (positions[src] < positions[destination]) {
          console.log(`${src} ${destination}`);
        } else {
          console.log(`${destination} ${src}`);
        }
      }
    }
  }
}


let inputString = "";
let currentLine = 0;
process.stdin.on("data", (data) => {
  inputString += data;
});
process.stdin.on("end", function () {
  inputString = inputString
    .trim()
    .split("\n")
    .map((str) => str.trim());
  main();
});
function readLine() {
  return inputString[currentLine++];
}
function main() {
  let t = +readLine();
  while (t--) {
    let [v, e] = readLine()
      .split(" ")
      .map((n) => parseInt(n));
    const queue = [];
    const graph = {};
    const indegrees = Array(v + 1).fill(0);
    const directedpairs = [];
    const nonDirectedpairs = [];
    const positions = [];

    for (let i = 0; i < e; i++) {
      let [directed, src, destination] = readLine()
        .split(" ")
        .map((n) => parseInt(n));
      if (directed) {
        if (!graph[src]) graph[src] = [destination];
        else graph[src].push(destination);
        directedpairs.push([src, destination]);
        indegrees[destination]++;
      } else {
        nonDirectedpairs.push([src, destination]);
      }
    }

    for (let i = 1; i <= v; i++) {
      if (indegrees[i] === 0) {
        queue.push(i);
      }
    }

    let index = 0;
    while (queue.length) {
      const u = queue.shift();
      positions[u] = index;
      index++;
      if (graph[u]) {
        for (let i = 0; i < graph[u].length; i++) {
          const v = graph[u][i];
          if (--indegrees[v] === 0) {
            queue.push(v);
          }
        }
      }
    }
    if (index !== v) {
      console.log("NO");
      continue;
    } else {
      console.log("YES");
      for (let i = 0; i < directedpairs.length; i++) {
        let [src, destination] = directedpairs[i];
        console.log(`${src} ${destination}`);
      }

      for (let i = 0; i < nonDirectedpairs.length; i++) {
        let [src, destination] = nonDirectedpairs[i];
        if (positions[src] < positions[destination]) {
          console.log(`${src} ${destination}`);
        } else {
          console.log(`${destination} ${src}`);
        }
      }
    }
  }
}


let inputString = "";
let currentLine = 0;
process.stdin.on("data", (data) => {
  inputString += data;
});
process.stdin.on("end", function () {
  inputString = inputString
    .trim()
    .split("\n")
    .map((str) => str.trim());
  main();
});
function readLine() {
  return inputString[currentLine++];
}
function main() {
  let t = +readLine();
  while (t--) {
    let [v, e] = readLine()
      .split(" ")
      .map((n) => parseInt(n));
    const queue = [];
    const graph = {};
    const indegrees = Array(v + 1).fill(0);
    const directedpairs = [];
    const nonDirectedpairs = [];
    const positions = [];

    let [di, ndi] = [0, 0];
    for (let i = 0; i < e; i++) {
      let [directed, src, destination] = readLine()
        .split(" ")
        .map((n) => parseInt(n));
      if (directed) {
        if (!graph[src]) graph[src] = [destination];
        else graph[src].push(destination);
        directedpairs[di] = [src, destination];
        indegrees[destination]++;
        di++;
      } else {
        nonDirectedpairs[ndi] = [src, destination];
        ndi++;
      }
    }

    for (let i = 1; i <= v; i++) {
      if (indegrees[i] === 0) {
        queue.push(i);
      }
    }

    let index = 0;
    while (queue.length) {
      const u = queue.pop();
      positions[u] = index;
      index++;
      if (graph[u]) {
        for (let i = 0; i < graph[u].length; i++) {
          const v = graph[u][i];
          if (--indegrees[v] === 0) {
            queue.push(v);
          }
        }
      }
    }
    if (index !== v) {
      console.log("NO");
      continue;
    } else {
      console.log("YES");
      for (let i = 0; i < directedpairs.length; i++) {
        let [src, destination] = directedpairs[i];
        console.log(`${src} ${destination}`);
      }

      for (let i = 0; i < nonDirectedpairs.length; i++) {
        let [src, destination] = nonDirectedpairs[i];
        if (positions[src] < positions[destination]) {
          console.log(`${src} ${destination}`);
        } else {
          console.log(`${destination} ${src}`);
        }
      }
    }
  }
}


let inputString = "";
let currentLine = 0;
process.stdin.on("data", (data) => {
  inputString += data;
});
process.stdin.on("end", function () {
  inputString = inputString
    .trim()
    .split("\n")
    .map((str) => str.trim());
  main();
});
function readLine() {
  return inputString[currentLine++];
}
function main() {
  let t = +readLine();
  while (t--) {
    let [v, e] = readLine()
      .split(" ")
      .map((n) => parseInt(n));
    const queue = [];
    const graph = {};
    const indegrees = Array(v + 1).fill(0);
    const directedpairs = [];
    const nonDirectedpairs = [];
    const positions = [];

    for (let i = 0; i < e; i++) {
      let [directed, src, destination] = readLine()
        .split(" ")
        .map((n) => parseInt(n));
      if (directed) {
        if (!graph[src]) graph[src] = [destination];
        else graph[src].push(destination);
        directedpairs.push([src, destination]);
        indegrees[destination]++;
      } else {
        nonDirectedpairs.push([src, destination]);
      }
    }

    for (let i = 1; i <= v; i++) {
      if (indegrees[i] === 0) {
        queue.push(i);
      }
    }

    let index = 0;
    while (queue.length) {
      const u = queue.pop();
      positions[u] = index;
      index++;
      if (graph[u]) {
        for (let i = 0; i < graph[u].length; i++) {
          const v = graph[u][i];
          if (--indegrees[v] === 0) {
            queue.push(v);
          }
        }
      }
    }
    if (index !== v) {
      console.log("NO");
      continue;
    } else {
      console.log("YES");
      for (let i = 0; i < directedpairs.length; i++) {
        let [src, destination] = directedpairs[i];
        console.log(`${src} ${destination}`);
      }

      for (let i = 0; i < nonDirectedpairs.length; i++) {
        let [src, destination] = nonDirectedpairs[i];
        if (positions[src] < positions[destination]) {
          console.log(`${src} ${destination}`);
        } else {
          console.log(`${destination} ${src}`);
        }
      }
    }
  }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Directing_Edges_1385E
{
    class Program
    {

        static List<int>[] graph;
        static List<int> undirected;
        static int n, m, time;
        static bool dag;
        static Stack<int> sort;

        static void DFS()
        {
            int[] d = new int[n+1];
            int[] f = new int[n+1];
            dag = false;
            time = 0;
            for (int i = 1; i < n+1; i++)
            {
                if (d[i] == 0)
                {
                    DFS_TopoligiclaSort(i, d, f);
                    if (dag)
                        return;
                }
            }

        }

        static void DFS_TopoligiclaSort(int vertex, int[] d, int[] f)
        {
            time++;
            d[vertex] = time;
            foreach (var x in graph[vertex])
            {
                if (d[x] == 0)
                {
                    DFS_TopoligiclaSort(x, d, f);
                }
                else
                {
                    if(f[x] == 0)
                    {
                        dag = true;
                        return;
                    }
                }
            }

            time++;
            f[vertex] = time;
            sort.Push(vertex);

        }

        static void Main(string[] args)
        {
            int testCases = int.Parse(Console.ReadLine());
            int[] input;
            sort = new Stack<int>();
            for (int i = 0; i < testCases; i++)
            {
                input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                n = input[0]; m = input[1];
                graph = new List<int>[n+1];
                undirected = new List<int>();
                for (int j = 1; j < n +1; j++)
                {
                    graph[j] = new List<int>();
                }
                for (int j = 0; j < m; j++)
                {
                    input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                    if(input[0] == 0)
                    {
                        undirected.Add(input[1]);
                        undirected.Add(input[2]);
                    }
                    else
                    {
                        graph[input[1]].Add(input[2]);
                    }
                }
                DFS();
                if (dag)
                    Console.WriteLine("NO");
                else
                {
                    int[] temp = new int[n + 1];
                    time = 0;
                    Console.WriteLine("YES");
                    while (sort.Count > 0)
                        temp[sort.Pop()] = time++;
                    for (int j = 0; j < undirected.Count; j+=2)
                    {
                        int aux1 = undirected[j], aux2 = undirected[j + 1];
                        if (temp[aux1] < temp[aux2]) Console.WriteLine(aux1 + " " + aux2);
                        else Console.WriteLine(aux2 + " " + aux1);
                    }
                    for (int j = 1; j < n+1; j++)
                    {
                        foreach (var x in graph[j])
                        {
                            Console.WriteLine(j+ " " +x);
                        }
                    }
                }
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Directing_Edges_1385E
{
    class Program
    {

        static List<int>[] graph;
        static List<int> undirected;
        static int n, m, time;
        static bool dag;
        static Stack<int> sort;

        static void DFS()
        {
            int[] d = new int[n+1];
            int[] f = new int[n+1];
            sort = new Stack<int>();
            dag = false;
            time = 0;
            for (int i = 1; i < n+1; i++)
            {
                if (d[i] == 0)
                {
                    DFS_TopoligiclaSort(i, d, f);
                    if (dag)
                        return;
                }
            }
        }

        static void DFS_TopoligiclaSort(int vertex, int[] d, int[] f)
        {
            time++;
            d[vertex] = time;
            foreach (var x in graph[vertex])
            {
                if (d[x] == 0)
                {
                    DFS_TopoligiclaSort(x, d, f);
                }
                else
                {
                    if(f[x] == 0)
                    {
                        dag = true;
                        return;
                    }
                }
            }
            time++;
            f[vertex] = time;
            sort.Push(vertex);
        }

        static void Main(string[] args)
        {
            int testCases = int.Parse(Console.ReadLine());
            int[] input;
            sort = new Stack<int>();
            for (int i = 0; i < testCases; i++)
            {
                input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                n = input[0]; m = input[1];
                graph = new List<int>[n+1];
                undirected = new List<int>();
                for (int j = 1; j < n +1; j++)
                {
                    graph[j] = new List<int>();
                }
                for (int j = 0; j < m; j++)
                {
                    input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                    if(input[0] == 0)
                    {
                        undirected.Add(input[1]);
                        undirected.Add(input[2]);
                    }
                    else
                    {
                        graph[input[1]].Add(input[2]);
                    }
                }
                DFS();
                if (dag)
                    Console.WriteLine("NO");
                else
                {
                    int[] temp = new int[n + 1];
                    int pos = 0;
                    Console.WriteLine("YES");
                    while (sort.Count > 0)
                        temp[sort.Pop()] = pos++;
                    for (int j = 0; j < undirected.Count; j+=2)
                    {
                        int aux1 = undirected[j], aux2 = undirected[j + 1];
                        if (temp[aux1] < temp[aux2]) Console.WriteLine(aux1 + " " + aux2);
                        else Console.WriteLine(aux2 + " " + aux1);
                    }
                    for (int j = 1; j < n+1; j++)
                    {
                        foreach (var x in graph[j])
                        {
                            Console.WriteLine(j+ " " +x);
                        }
                    }
                }
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Directing_Edges_1385E
{
    class Program
    {

        static List<int>[] graph;
        static List<int> undirected;
        static int n, m, time;
        static bool dag;
        static Stack<int> sort;

        static void DFS()
        {
            int[] d = new int[n+1];
            int[] f = new int[n+1];
            dag = false;
            time = 0;
            for (int i = 1; i < n+1; i++)
            {
                if (d[i] == 0)
                {
                    DFS_TopoligiclaSort(i, d, f);
                    if (dag)
                        return;
                }
            }

        }

        static void DFS_TopoligiclaSort(int vertex, int[] d, int[] f)
        {
            time++;
            d[vertex] = time;
            foreach (var x in graph[vertex])
            {
                if (d[x] == 0)
                {
                    DFS_TopoligiclaSort(x, d, f);
                }
                else
                {
                    if(f[x] == 0)
                    {
                        dag = true;
                        return;
                    }
                }
            }

            time++;
            f[vertex] = time;
            sort.Push(vertex);

        }

        static void Main(string[] args)
        {
            int testCases = int.Parse(Console.ReadLine());
            int[] input;
            sort = new Stack<int>();
            for (int i = 0; i < testCases; i++)
            {
                input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                n = input[0]; m = input[1];
                graph = new List<int>[n+1];
                undirected = new List<int>();
                for (int j = 1; j < n +1; j++)
                {
                    graph[j] = new List<int>();
                }
                for (int j = 0; j < m; j++)
                {
                    input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                    if(input[0] == 0)
                    {
                        undirected.Add(input[1]);
                        undirected.Add(input[2]);
                    }
                    else
                    {
                        graph[input[1]].Add(input[2]);
                    }
                }
                DFS();
                if (dag)
                    Console.WriteLine("NO");
                else
                {
                    int[] temp = new int[n + 1];
                    int pos = 0;
                    Console.WriteLine("YES");
                    while (sort.Count > 0)
                        temp[sort.Pop()] = pos++;
                    for (int j = 0; j < undirected.Count; j+=2)
                    {
                        int aux1 = undirected[j], aux2 = undirected[j + 1];
                        if (temp[aux1] < temp[aux2]) Console.WriteLine(aux1 + " " + aux2);
                        else Console.WriteLine(aux2 + " " + aux1);
                    }
                    for (int j = 1; j < n+1; j++)
                    {
                        foreach (var x in graph[j])
                        {
                            Console.WriteLine(j+ " " +x);
                        }
                    }
                }
            }
        }
    }
}using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Directing_Edges_1385E
{
    class Program
    {

        static List<int>[] graph;
        static List<int> undirected;
        static int n, m, time;
        static bool dag;
        static Stack<int> sort;

        static void DFS()
        {
            int[] d = new int[n+1];
            int[] f = new int[n+1];
            dag = false;
            time = 0;
            for (int i = 1; i < n+1; i++)
            {
                if (d[i] == 0)
                {
                    DFS_TopoligiclaSort(i, d, f);
                    if (dag)
                        return;
                }
            }

        }

        static void DFS_TopoligiclaSort(int vertex, int[] d, int[] f)
        {
            time++;
            d[vertex] = time;
            foreach (var x in graph[vertex])
            {
                if (d[x] == 0)
                {
                    DFS_TopoligiclaSort(x, d, f);
                }
                else
                {
                    if(f[x] == 0)
                    {
                        dag = true;
                        return;
                    }
                }
            }

            time++;
            f[vertex] = time;
            sort.Push(vertex);

        }

        static void Main(string[] args)
        {
            int testCases = int.Parse(Console.ReadLine());
            int[] input;
            sort = new Stack<int>();
            for (int i = 0; i < testCases; i++)
            {
                input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                n = input[0]; m = input[1];
                graph = new List<int>[n+1];
                undirected = new List<int>();
                for (int j = 1; j < n +1; j++)
                {
                    graph[j] = new List<int>();
                }
                for (int j = 0; j < m; j++)
                {
                    input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                    if(input[0] == 0)
                    {
                        undirected.Add(input[1]);
                        undirected.Add(input[2]);
                    }
                    else
                    {
                        graph[input[1]].Add(input[2]);
                    }
                }
                DFS();
                if (dag)
                    Console.WriteLine("NO");
                else
                {
                    int[] temp = new int[n + 1];
                    int pos = 0;
                    Console.WriteLine("YES");
                    while (sort.Count > 0)
                        temp[sort.Pop()] = pos++;
                    for (int j = 0; j < undirected.Count; j+=2)
                    {
                        int aux1 = undirected[j], aux2 = undirected[j + 1];
                        if (temp[aux1] < temp[aux2]) Console.WriteLine(aux1 + " " + aux2);
                        else Console.WriteLine(aux2 + " " + aux1);
                    }
                    for (int j = 1; j < n+1; j++)
                    {
                        foreach (var x in graph[j])
                        {
                            Console.WriteLine(j+ " " +x);
                        }
                    }
                }
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Directing_Edges_1385E
{
    class Program
    {

        static List<int>[] graph;
        static List<int> undirected;
        static int n, m, time;
        static bool dag;
        static Stack<int> sort;

        static void DFS()
        {
            int[] d = new int[n+1];
            int[] f = new int[n+1];
            dag = false;
            time = 0;
            for (int i = 1; i < n+1; i++)
            {
                if (d[i] == 0)
                {
                    DFS_TopoligiclaSort(i, d, f);
                    if (dag)
                        return;
                }
            }

        }

        static void DFS_TopoligiclaSort(int vertex, int[] d, int[] f)
        {
            time++;
            d[vertex] = time;
            foreach (var x in graph[vertex])
            {
                if (d[x] == 0)
                {
                    DFS_TopoligiclaSort(x, d, f);
                }
                else
                {
                    if(f[x] == 0)
                    {
                        dag = true;
                        return;
                    }
                }
            }

            time++;
            f[vertex] = time;
            sort.Push(vertex);

        }

        static void Main(string[] args)
        {
            int testCases = int.Parse(Console.ReadLine());
            int[] input;
            sort = new Stack<int>();
            for (int i = 0; i < testCases; i++)
            {
                input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                n = input[0]; m = input[1];
                graph = new List<int>[n+1];
                undirected = new List<int>();
                for (int j = 1; j < n +1; j++)
                {
                    graph[j] = new List<int>();
                }
                for (int j = 0; j < m; j++)
                {
                    input = Array.ConvertAll(Console.ReadLine().Split(), x => int.Parse(x));
                    if(input[0] == 0)
                    {
                        undirected.Add(input[1]);
                        undirected.Add(input[2]);
                    }
                    else
                    {
                        graph[input[1]].Add(input[2]);
                    }
                }
                DFS();
                if (dag)
                    Console.WriteLine("NO");
                else
                {
                    int[] temp = new int[n + 1];
                    int pos = 0;
                    Console.WriteLine("YES");
                    while (sort.Count > 0)
                        temp[sort.Pop()] = pos++;
                    for (int j = 0; j < undirected.Count; j+=2)
                    {
                        int aux1 = undirected[j], aux2 = undirected[j + 1];
                        if (temp[aux1] < temp[aux2]) Console.WriteLine(aux1 + " " + aux2);
                        else Console.WriteLine(aux2 + " " + aux1);
                    }
                    for (int j = 1; j < n+1; j++)
                    {
                        foreach (var x in graph[j])
                        {
                            Console.WriteLine(j+ " " +x);
                        }
                    }
                }
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using CompLib.Util;

public class Program
{
    public void Solve()
    {
        var sc = new Scanner();
        int t = sc.NextInt();
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) {AutoFlush = false});
        for (int i = 0; i < t; i++)
        {
            Q(sc);
        }

        Console.Out.Flush();
    }

    void Q(Scanner sc)
    {
        int n = sc.NextInt();
        int m = sc.NextInt();

        List<(int t, int num)>[] dir = new List<(int t, int num)>[n];
        List<(int f, int t, int num)> unDir = new List<(int f, int t, int num)>();

        for (int i = 0; i < n; i++)
        {
            dir[i] = new List<(int t, int num)>();
        }

        for (int i = 0; i < m; i++)
        {
            int t = sc.NextInt();
            int x = sc.NextInt() - 1;
            int y = sc.NextInt() - 1;
            if (t == 1)
            {
                dir[x].Add((y, i));
            }
            else
            {
                unDir.Add((x, y, i));
            }
        }

        int[] sorted = new int[n];
        for (int i = 0; i < n; i++)
        {
            sorted[i] = i;
        }

        // 入ってくる辺が無い頂点
        var q = new Queue<int>();
        // iに入ってくる辺
        var cnt = new int[n];
        for (int i = 0; i < n; i++)
        {
            foreach ((int t, int num) e in dir[i])
            {
                cnt[e.t]++;
            }
        }

        for (int i = 0; i < n; i++)
        {
            if (cnt[i] == 0) q.Enqueue(i);
        }

        for (int i = 0; i < n; i++)
        {
            if (q.Count <= 0)
            {
                Console.WriteLine("NO");
                return;
            }

            var d = q.Dequeue();
            sorted[i] = d;
            foreach ((int t, int num) e in dir[d])
            {
                cnt[e.t]--;
                if (cnt[e.t] == 0)
                {
                    q.Enqueue(e.t);
                }
            }
        }

        int[] index = new int[n];
        for (int i = 0; i < n; i++)
        {
            index[sorted[i]] = i;
        }
        string[] ans = new string[m];

        Console.WriteLine("YES");

        for (int i = 0; i < n; i++)
        {
            foreach ((int t, int num) e in dir[i])
            {
                ans[e.num] = $"{i + 1} {e.t + 1}";
            }
        }

        foreach ((int f, int t, int num) e in unDir)
        {
            if (index[e.f] < index[e.t])
            {
                ans[e.num] = $"{e.f + 1} {e.t + 1}";
            }
            else
            {
                ans[e.num] = $"{e.t + 1} {e.f + 1}";
            }
        }

        Console.WriteLine(string.Join("\n", ans));
        // N頂点M辺のグラフ

        // 無向辺に向きつけて閉路が無いようにする

        // DAG
        //
    }

    public static void Main(string[] args) => new Program().Solve();
}

namespace CompLib.Util
{
    using System;
    using System.Linq;

    class Scanner
    {
        private string[] _line;
        private int _index;
        private const char Separator = ' ';

        public Scanner()
        {
            _line = new string[0];
            _index = 0;
        }

        public string Next()
        {
            if (_index >= _line.Length)
            {
                string s;
                do
                {
                    s = Console.ReadLine();
                } while (s.Length == 0);

                _line = s.Split(Separator);
                _index = 0;
            }

            return _line[_index++];
        }

        public int NextInt() => int.Parse(Next());
        public long NextLong() => long.Parse(Next());
        public double NextDouble() => double.Parse(Next());
        public decimal NextDecimal() => decimal.Parse(Next());
        public char NextChar() => Next()[0];
        public char[] NextCharArray() => Next().ToCharArray();

        public string[] Array()
        {
            string s = Console.ReadLine();
            _line = s.Length == 0 ? new string[0] : s.Split(Separator);
            _index = _line.Length;
            return _line;
        }

        public int[] IntArray() => Array().Select(int.Parse).ToArray();
        public long[] LongArray() => Array().Select(long.Parse).ToArray();
        public double[] DoubleArray() => Array().Select(double.Parse).ToArray();
        public decimal[] DecimalArray() => Array().Select(decimal.Parse).ToArray();
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using CompLib.Util;

public class Program
{
    public void Solve()
    {
        var sc = new Scanner();
        int t = sc.NextInt();
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) {AutoFlush = false});
        for (int i = 0; i < t; i++)
        {
            Q(sc);
        }

        Console.Out.Flush();
    }

    void Q(Scanner sc)
    {
        int n = sc.NextInt();
        int m = sc.NextInt();

        List<(int t, int num)>[] dir = new List<(int t, int num)>[n];
        List<(int f, int t, int num)> unDir = new List<(int f, int t, int num)>();

        for (int i = 0; i < n; i++)
        {
            dir[i] = new List<(int t, int num)>();
        }

        for (int i = 0; i < m; i++)
        {
            int t = sc.NextInt();
            int x = sc.NextInt() - 1;
            int y = sc.NextInt() - 1;
            if (t == 1)
            {
                dir[x].Add((y, i));
            }
            else
            {
                unDir.Add((x, y, i));
            }
        }

        int[] index = new int[n];
        for (int i = 0; i < n; i++)
        {
            index[i] = i;
        }

        // 入ってくる辺が無い頂点
        var q = new Queue<int>();
        // iに入ってくる辺
        var cnt = new int[n];
        for (int i = 0; i < n; i++)
        {
            foreach ((int t, int num) e in dir[i])
            {
                cnt[e.t]++;
            }
        }

        for (int i = 0; i < n; i++)
        {
            if (cnt[i] == 0) q.Enqueue(i);
        }

        for (int i = 0; i < n; i++)
        {
            if (q.Count <= 0)
            {
                Console.WriteLine("NO");
                return;
            }

            var d = q.Dequeue();
            index[i] = d;
            foreach ((int t, int num) e in dir[d])
            {
                cnt[e.t]--;
                if (cnt[e.t] == 0)
                {
                    q.Enqueue(e.t);
                }
            }
        }

        string[] ans = new string[m];

        Console.WriteLine("YES");

        for (int i = 0; i < n; i++)
        {
            foreach ((int t, int num) e in dir[i])
            {
                ans[e.num] = $"{i + 1} {e.t + 1}";
            }
        }

        foreach ((int f, int t, int num) e in unDir)
        {
            if (index[e.f] < index[e.t])
            {
                ans[e.num] = $"{e.f + 1} {e.t + 1}";
            }
            else
            {
                ans[e.num] = $"{e.t + 1} {e.f + 1}";
            }
        }

        Console.WriteLine(string.Join("\n", ans));
        // N頂点M辺のグラフ

        // 無向辺に向きつけて閉路が無いようにする

        // DAG
        //
    }

    public static void Main(string[] args) => new Program().Solve();
}

namespace CompLib.Util
{
    using System;
    using System.Linq;

    class Scanner
    {
        private string[] _line;
        private int _index;
        private const char Separator = ' ';

        public Scanner()
        {
            _line = new string[0];
            _index = 0;
        }

        public string Next()
        {
            if (_index >= _line.Length)
            {
                string s;
                do
                {
                    s = Console.ReadLine();
                } while (s.Length == 0);

                _line = s.Split(Separator);
                _index = 0;
            }

            return _line[_index++];
        }

        public int NextInt() => int.Parse(Next());
        public long NextLong() => long.Parse(Next());
        public double NextDouble() => double.Parse(Next());
        public decimal NextDecimal() => decimal.Parse(Next());
        public char NextChar() => Next()[0];
        public char[] NextCharArray() => Next().ToCharArray();

        public string[] Array()
        {
            string s = Console.ReadLine();
            _line = s.Length == 0 ? new string[0] : s.Split(Separator);
            _index = _line.Length;
            return _line;
        }

        public int[] IntArray() => Array().Select(int.Parse).ToArray();
        public long[] LongArray() => Array().Select(long.Parse).ToArray();
        public double[] DoubleArray() => Array().Select(double.Parse).ToArray();
        public decimal[] DecimalArray() => Array().Select(decimal.Parse).ToArray();
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;

namespace Directing_Edges
{
    internal class Program
    {
        private static readonly StreamReader reader = new StreamReader(Console.OpenStandardInput(1024*10), Encoding.ASCII, false, 1024*10);
        private static readonly StreamWriter writer = new StreamWriter(Console.OpenStandardOutput(1024*10), Encoding.ASCII, 1024*10);

        private static List<Tuple<int, int>> ans;

        private static List<int>[] d;

        private static int[] f;
        private static int[] p;

        private static void Main(string[] args)
        {
            var thread = new Thread(() =>
                                        {
                                            int t = Next();
                                            for (int i = 0; i < t; i++)
                                            {
                                                bool f = Solve();
                                                writer.WriteLine(f ? "YES" : "NO");

                                                if (f)
                                                {
                                                    foreach (var an in ans)
                                                    {
                                                        writer.Write(an.Item1 + 1);
                                                        writer.Write(' ');
                                                        writer.WriteLine(an.Item2 + 1);
                                                    }
                                                }
                                            }
                                        }, 32*1024*1024);

            thread.Start();
            thread.Join();
            writer.Flush();
        }

        private static bool Solve()
        {
            int n = Next();
            int m = Next();

            d = new List<int>[n];
            var s = new List<Tuple<int, int>>();

            ans = new List<Tuple<int, int>>();
            p = new int[n];
            var lev = new int[n];
            for (int i = 0; i < n; i++)
            {
                d[i] = new List<int>(2);
                p[i] = i;
            }
            var cnts = new int[n];
            for (int i = 0; i < m; i++)
            {
                int t = Next();
                int a = Next() - 1;
                int b = Next() - 1;

                if (t == 1)
                {
                    d[b].Add(a);
                    cnts[a]++;
                    cnts[b]++;
                    ans.Add(new Tuple<int, int>(a, b));

                    int pa = GP(a);
                    int pb = GP(b);
                    if (pa != pb)
                        p[pa] = pb;
                }
                else
                {
                    s.Add(new Tuple<int, int>(a, b));
                }
            }

            f = new int[n];
            for (int i = 0; i < n; i++)
            {
                if (f[i] == 0)
                {
                    if (Dfs(i, i + 1))
                        return false;
                }
            }

            var q = new Queue<int>();
            for (int i = 0; i < n; i++)
            {
                if (cnts[i] == d[i].Count)
                {
                    q.Enqueue(i);
                }
            }

            while (q.Count > 0)
            {
                int i = q.Dequeue();
                foreach (int j in d[i])
                {
                    cnts[j]--;
                    if (cnts[j] == d[j].Count)
                    {
                        q.Enqueue(j);
                        lev[j] = 1 + lev[i];
                    }
                }
            }

            foreach (var i in s)
            {
                int pa = GP(i.Item1);
                int pb = GP(i.Item2);
                if (pa == pb)
                {
                    ans.Add(lev[i.Item1] < lev[i.Item2] ? new Tuple<int, int>(i.Item2, i.Item1) : i);
                }
                else
                {
                    ans.Add(pa > pb ? i : new Tuple<int, int>(i.Item2, i.Item1));
                }
            }

            return true;
        }

        private static int GP(int i)
        {
            if (i == p[i])
                return i;
            return p[i] = GP(p[i]);
        }

        private static bool Dfs(int to, int p)
        {
            if (d[to].Count == 0)
                return false;
            f[to] = p;
            foreach (int i in d[to])
            {
                if (f[i] == p)
                    return true;

                if (f[i] == 0 && Dfs(i, p))
                    return true;
            }
            return false;
        }

        private static int Next()
        {
            int c;
            int res = 0;
            do
            {
                c = reader.Read();
                if (c == -1)
                    return res;
            } while (c < '0' || c > '9');
            res = c - '0';
            while (true)
            {
                c = reader.Read();
                if (c < '0' || c > '9')
                    return res;
                res *= 10;
                res += c - '0';
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;

namespace Directing_Edges
{
    internal class Program
    {
        private static readonly StreamReader reader = new StreamReader(Console.OpenStandardInput(1024*10), Encoding.ASCII, false, 1024*10);
        private static readonly StreamWriter writer = new StreamWriter(Console.OpenStandardOutput(1024*10), Encoding.ASCII, 1024*10);

        private static List<Tuple<int, int>> ans;
        private static List<int>[] d;
        private static int[] f;
        private static int[] p;

        private static void Main(string[] args)
        {
            var thread = new Thread(() =>
                                        {
                                            int t = Next();
                                            for (int i = 0; i < t; i++)
                                            {
                                                bool solve = Solve();
                                                writer.WriteLine(solve ? "YES" : "NO");

                                                if (solve)
                                                {
                                                    foreach (var an in ans)
                                                    {
                                                        writer.Write(an.Item1 + 1);
                                                        writer.Write(' ');
                                                        writer.WriteLine(an.Item2 + 1);
                                                    }
                                                }
                                            }
                                        }, 32*1024*1024);

            thread.Start();
            thread.Join();
            writer.Flush();
        }

        private static bool Solve()
        {
            int n = Next();
            int m = Next();

            d = new List<int>[n];
            var s = new List<Tuple<int, int>>();

            ans = new List<Tuple<int, int>>();
            p = new int[n];
            var lev = new int[n];
            for (int i = 0; i < n; i++)
            {
                d[i] = new List<int>(2);
                p[i] = i;
            }
            var cnts = new int[n];
            for (int i = 0; i < m; i++)
            {
                int t = Next();
                int a = Next() - 1;
                int b = Next() - 1;

                if (t == 1)
                {
                    d[b].Add(a);
                    cnts[a]++;
                    cnts[b]++;
                    ans.Add(new Tuple<int, int>(a, b));

                    int pa = GP(a);
                    int pb = GP(b);
                    if (pa != pb)
                        p[pa] = pb;
                }
                else
                {
                    s.Add(new Tuple<int, int>(a, b));
                }
            }

            f = new int[n];
            for (int i = 0; i < n; i++)
            {
                if (f[i] == 0)
                {
                    if (Dfs(i, i + 2))
                        return false;
                }
            }

            var q = new Queue<int>();
            for (int i = 0; i < n; i++)
            {
                if (cnts[i] == d[i].Count)
                {
                    q.Enqueue(i);
                }
            }

            while (q.Count > 0)
            {
                int i = q.Dequeue();
                foreach (int j in d[i])
                {
                    cnts[j]--;
                    if (cnts[j] == d[j].Count)
                    {
                        q.Enqueue(j);
                        lev[j] = 1 + lev[i];
                    }
                }
            }

            foreach (var i in s)
            {
                int pa = GP(i.Item1);
                int pb = GP(i.Item2);
                if (pa == pb)
                {
                    ans.Add(lev[i.Item1] < lev[i.Item2] ? new Tuple<int, int>(i.Item2, i.Item1) : (lev[i.Item1] > lev[i.Item2] ? i : (i.Item1 > i.Item2 ? i : new Tuple<int, int>(i.Item2, i.Item1))));
                }
                else
                {
                    ans.Add(pa > pb ? i : new Tuple<int, int>(i.Item2, i.Item1));
                }
            }

            return true;
        }

        private static int GP(int i)
        {
            if (i == p[i])
                return i;
            return p[i] = GP(p[i]);
        }

        private static bool Dfs(int to, int pp)
        {
            if (d[to].Count == 0)
                return false;
            f[to] = pp;
            foreach (int i in d[to])
            {
                if (f[i] == pp)
                    return true;

                if (f[i] == 0 && Dfs(i, pp))
                    return true;
            }
            f[to] = pp - 1;
            return false;
        }

        private static int Next()
        {
            int c;
            int res = 0;
            do
            {
                c = reader.Read();
                if (c == -1)
                    return res;
            } while (c < '0' || c > '9');
            res = c - '0';
            while (true)
            {
                c = reader.Read();
                if (c < '0' || c > '9')
                    return res;
                res *= 10;
                res += c - '0';
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;

namespace Directing_Edges
{
    internal class Program
    {
        private static readonly StreamReader reader = new StreamReader(Console.OpenStandardInput(1024*10), Encoding.ASCII, false, 1024*10);
        private static readonly StreamWriter writer = new StreamWriter(Console.OpenStandardOutput(1024*10), Encoding.ASCII, 1024*10);

        private static List<Tuple<int, int>> ans;
        private static List<int>[] d;
        private static int[] f;
        private static int[] p;

        private static void Main(string[] args)
        {
            var thread = new Thread(() =>
                                        {
                                            int t = Next();
                                            for (int i = 0; i < t; i++)
                                            {
                                                bool solve = Solve();
                                                writer.WriteLine(solve ? "YES" : "NO");

                                                if (solve)
                                                {
                                                    foreach (var an in ans)
                                                    {
                                                        writer.Write(an.Item1 + 1);
                                                        writer.Write(' ');
                                                        writer.WriteLine(an.Item2 + 1);
                                                    }
                                                }
                                            }
                                        }, 32*1024*1024);

            thread.Start();
            thread.Join();
            writer.Flush();
        }

        private static bool Solve()
        {
            int n = Next();
            int m = Next();

            d = new List<int>[n];
            var s = new List<Tuple<int, int>>();

            ans = new List<Tuple<int, int>>();
            p = new int[n];
            var lev = new int[n];
            for (int i = 0; i < n; i++)
            {
                d[i] = new List<int>(2);
                p[i] = i;
            }
            var cnts = new int[n];
            for (int i = 0; i < m; i++)
            {
                int t = Next();
                int a = Next() - 1;
                int b = Next() - 1;

                if (t == 1)
                {
                    d[b].Add(a);
                    cnts[a]++;
                    cnts[b]++;
                    ans.Add(new Tuple<int, int>(a, b));

                    int pa = GP(a);
                    int pb = GP(b);
                    if (pa != pb)
                        p[pa] = pb;
                }
                else
                {
                    s.Add(new Tuple<int, int>(a, b));
                }
            }

            f = new int[n];
            for (int i = 0; i < n; i++)
            {
                if (f[i] == 0)
                {
                    if (Dfs(i, i + 1))
                        return false;
                }
            }

            var q = new Queue<int>();
            for (int i = 0; i < n; i++)
            {
                if (cnts[i] == d[i].Count)
                {
                    q.Enqueue(i);
                }
            }

            while (q.Count > 0)
            {
                int i = q.Dequeue();
                foreach (int j in d[i])
                {
                    cnts[j]--;
                    if (cnts[j] == d[j].Count)
                    {
                        q.Enqueue(j);
                        lev[j] = 1 + lev[i];
                    }
                }
            }

            foreach (var i in s)
            {
                int pa = GP(i.Item1);
                int pb = GP(i.Item2);
                if (pa == pb)
                {
                    ans.Add(lev[i.Item1] < lev[i.Item2] ? new Tuple<int, int>(i.Item2, i.Item1) : (lev[i.Item1] > lev[i.Item2] ? i : (i.Item1 > i.Item2 ? i : new Tuple<int, int>(i.Item2, i.Item1))));
                }
                else
                {
                    ans.Add(pa > pb ? i : new Tuple<int, int>(i.Item2, i.Item1));
                }
            }

            return true;
        }

        private static int GP(int i)
        {
            if (i == p[i])
                return i;
            return p[i] = GP(p[i]);
        }

        private static bool Dfs(int to, int pp)
        {
            if (d[to].Count == 0)
                return false;
            f[to] = pp;
            foreach (int i in d[to])
            {
                if (f[i] == pp)
                    return true;

                if (f[i] == 0 && Dfs(i, pp))
                    return true;
            }
            return false;
        }

        private static int Next()
        {
            int c;
            int res = 0;
            do
            {
                c = reader.Read();
                if (c == -1)
                    return res;
            } while (c < '0' || c > '9');
            res = c - '0';
            while (true)
            {
                c = reader.Read();
                if (c < '0' || c > '9')
                    return res;
                res *= 10;
                res += c - '0';
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    List<int>[] g1;
    List<int> top;
    int[] colour;
    int cnt;
    bool Fun(int x)
    {
        colour[x] = 1;
        foreach (int e in g1[x])
            if (colour[e] == 0)
            {
                if (Fun(e))
                    return true;
            }
            else if (colour[e] == 1)
                return true;
        colour[x] = 2;
        top.Add(x);
        return false;
    }

    public void Solve()
    {
        for (int tt = ReadInt(); tt > 0; tt--)
        {
            int n = ReadInt();
            int m = ReadInt();

            g1 = Init<List<int>>(n);
            var g2 = new List<Tuple<int, int>>();
            for (int i = 0; i < m; i++)
            {
                int t = ReadInt();
                int u = ReadInt() - 1;
                int v = ReadInt() - 1;
                if (t == 1)
                    g1[u].Add(v);
                else
                    g2.Add(Tuple.Create(u, v));
            }

            cnt = 1;
            top = new List<int>();
            colour = new int[n];
            bool f = false;
            for (int i = 0; i < n; i++)
                if (colour[i] == 0 && Fun(i))
                    f = true;

            if (f)
            {
                Write("NO");
                continue;
            }

            var o = new int[n];
            top.Reverse();
            for (int i = 0; i < top.Count; i++)
                o[top[i]] = i + 1;
            cnt = top.Count + 1;

            Write("YES");
            foreach (var t in g2)
            {
                bool z;
                if (o[t.Item1] > 0)
                {
                    if (o[t.Item2] > 0)
                    {
                        if (o[t.Item1] < o[t.Item2])
                            z = true;
                        else
                            z = false;
                    }
                    else
                    {
                        o[t.Item2] = cnt++;
                        z = true;
                    }
                }
                else
                {
                    if (o[t.Item2] > 0)
                    {
                        o[t.Item1] = cnt++;
                        z = false;
                    }
                    else
                    {
                        z = true;
                        o[t.Item1] = cnt++;
                        o[t.Item2] = cnt++;
                    }
                }

                if (z)
                    Write(t.Item1 + 1, t.Item2 + 1);
                else
                    Write(t.Item2 + 1, t.Item1 + 1);
            }
            for (int i = 0; i < n; i++)
                foreach (int e in g1[i])
                    Write(i + 1, e + 1);

        }
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            new Solver().Solve();
            //var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            //thread.Start();
            //thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i]; } return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array)writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++)ret[i] = new T(); return ret; }
    #endregion
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    List<int>[] g1;
    List<int> top;
    int[] colour;
    int cnt;
    bool Fun(int x)
    {
        colour[x] = 1;
        foreach (int e in g1[x])
            if (colour[e] == 0)
            {
                if (Fun(e))
                    return true;
            }
            else if (colour[e] == 1)
                return true;
        colour[x] = 2;
        top.Add(x);
        return false;
    }

    public void Solve()
    {
        for (int tt = ReadInt(); tt > 0; tt--)
        {
            int n = ReadInt();
            int m = ReadInt();

            g1 = Init<List<int>>(n);
            var g2 = new List<Tuple<int, int>>();
            for (int i = 0; i < m; i++)
            {
                int t = ReadInt();
                int u = ReadInt() - 1;
                int v = ReadInt() - 1;
                if (t == 1)
                    g1[u].Add(v);
                else
                    g2.Add(Tuple.Create(u, v));
            }

            cnt = 1;
            top = new List<int>();
            colour = new int[n];
            bool f = false;
            for (int i = 0; i < n; i++)
                if (colour[i] == 0 && Fun(i))
                    f = true;

            if (f)
            {
                Write("NO");
                continue;
            }

            var o = new int[n];
            top.Reverse();
            for (int i = 0; i < top.Count; i++)
                o[top[i]] = i + 1;
            cnt = top.Count + 1;

            Write("YES");
            foreach (var t in g2)
            {
                bool z;
                if (o[t.Item1] > 0)
                {
                    if (o[t.Item2] > 0)
                    {
                        if (o[t.Item1] < o[t.Item2])
                            z = true;
                        else
                            z = false;
                    }
                    else
                    {
                        o[t.Item2] = cnt++;
                        z = true;
                    }
                }
                else
                {
                    if (o[t.Item2] > 0)
                    {
                        o[t.Item1] = cnt++;
                        z = false;
                    }
                    else
                    {
                        z = true;
                        o[t.Item1] = cnt++;
                        o[t.Item2] = cnt++;
                    }
                }

                if (z)
                    Write(t.Item1 + 1, t.Item2 + 1);
                else
                    Write(t.Item2 + 1, t.Item1 + 1);
            }
            for (int i = 0; i < n; i++)
                foreach (int e in g1[i])
                    Write(i + 1, e + 1);

        }
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            //new Solver().Solve();
            var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            thread.Start();
            thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i]; } return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array)writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++)ret[i] = new T(); return ret; }
    #endregion
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CodeforcesRound656Div3.Extensions;
using CodeforcesRound656Div3.Questions;

namespace CodeforcesRound656Div3.Questions
{
    public class QuestionE : AtCoderQuestionBase
    {
        public override IEnumerable<object> Solve(TextReader inputStream)
        {
            var tests = inputStream.ReadInt();

            for (int t = 0; t < tests; t++)
            {
                var (n, m) = inputStream.ReadValue<int, int>();
                var graph = Enumerable.Repeat(0, n).Select(_ => new List<int>()).ToArray();
                var indirectedEdges = new List<Edge>();
                var inDegrees = new int[n];

                for (int i = 0; i < m; i++)
                {
                    var (type, from, to) = inputStream.ReadValue<int, int, int>();
                    from--;
                    to--;

                    if (type == 0)
                    {
                        indirectedEdges.Add(new Edge(from, to));
                    }
                    else
                    {
                        inDegrees[to]++;
                        graph[from].Add(to);
                    }
                }

                var sorted = TopologicalSort(graph, inDegrees);

                if (sorted == null)
                {
                    yield return "NO";
                }
                else
                {
                    yield return "YES";

                    var indices = new int[n];
                    for (int i = 0; i < indices.Length; i++)
                    {
                        indices[sorted[i]] = i;
                    }

                    foreach (var edge in indirectedEdges)
                    {
                        var fromIndex = indices[edge.From];
                        var toIndex = indices[edge.To];

                        var from = edge.From + 1;
                        var to = edge.To + 1;

                        if (fromIndex < toIndex)
                        {
                            yield return $"{from} {to}";
                        }
                        else
                        {
                            yield return $"{to} {from}";
                        }
                    }
                }
            }
        }

        List<int> TopologicalSort(List<int>[] edges, int[] inDegrees)
        {
            var sorted = new List<int>();
            var queue = new Queue<int>();

            for (int i = 0; i < inDegrees.Length; i++)
            {
                if (inDegrees[i] == 0)
                {
                    queue.Enqueue(i);
                }
            }

            while (queue.Count > 0)
            {
                var current = queue.Dequeue();
                sorted.Add(current);

                foreach (var to in edges[current])
                {
                    inDegrees[to]--;
                    if (inDegrees[to] == 0)
                    {
                        queue.Enqueue(to);
                    }
                }
            }

            if (sorted.Count == inDegrees.Length)
            {
                return sorted;
            }
            else
            {
                return null;
            }
        }

        [StructLayout(LayoutKind.Auto)]
        struct Edge
        {
            public int From { get; }
            public int To { get; }

            public Edge(int from, int to)
            {
                From = from;
                To = to;
            }

            public override string ToString() => $"{nameof(From)}: {From}, {nameof(To)}: {To}";
        }
    }
}

namespace CodeforcesRound656Div3
{
    class Program
    {
        static void Main(string[] args)
        {
            IAtCoderQuestion question = new QuestionE();
            var answers = question.Solve(Console.In);

            var writer = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            Console.SetOut(writer);
            foreach (var answer in answers)
            {
                Console.WriteLine(answer);
            }
            Console.Out.Flush();
        }
    }
}

#region Base Class

namespace CodeforcesRound656Div3.Questions
{

    public interface IAtCoderQuestion
    {
        IEnumerable<object> Solve(string input);
        IEnumerable<object> Solve(TextReader inputStream);
    }

    public abstract class AtCoderQuestionBase : IAtCoderQuestion
    {
        public IEnumerable<object> Solve(string input)
        {
            var stream = new MemoryStream(Encoding.Unicode.GetBytes(input));
            var reader = new StreamReader(stream, Encoding.Unicode);

            return Solve(reader);
        }

        public abstract IEnumerable<object> Solve(TextReader inputStream);
    }
}

#endregion

#region Extensions

namespace CodeforcesRound656Div3.Extensions
{
    public static class StringExtensions
    {
        public static string Join<T>(this IEnumerable<T> source) => string.Concat(source);
        public static string Join<T>(this IEnumerable<T> source, string separator) => string.Join(separator, source);
    }

    public static class TextReaderExtensions
    {
        public static int ReadInt(this TextReader reader) => int.Parse(ReadString(reader));
        public static long ReadLong(this TextReader reader) => long.Parse(ReadString(reader));
        public static double ReadDouble(this TextReader reader) => double.Parse(ReadString(reader));
        public static string ReadString(this TextReader reader) => reader.ReadLine();

        public static int[] ReadIntArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(int.Parse).ToArray();
        public static long[] ReadLongArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(long.Parse).ToArray();
        public static double[] ReadDoubleArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(double.Parse).ToArray();
        public static string[] ReadStringArray(this TextReader reader, char separator = ' ') => reader.ReadLine().Split(separator);

        // Supports primitive type only.
        public static T1 ReadValue<T1>(this TextReader reader) => (T1)Convert.ChangeType(reader.ReadLine(), typeof(T1));

        public static (T1, T2) ReadValue<T1, T2>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            return (v1, v2);
        }

        public static (T1, T2, T3) ReadValue<T1, T2, T3>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            return (v1, v2, v3);
        }

        public static (T1, T2, T3, T4) ReadValue<T1, T2, T3, T4>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            return (v1, v2, v3, v4);
        }

        public static (T1, T2, T3, T4, T5) ReadValue<T1, T2, T3, T4, T5>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
            return (v1, v2, v3, v4, v5);
        }

        public static (T1, T2, T3, T4, T5, T6) ReadValue<T1, T2, T3, T4, T5, T6>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
            var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6));
            return (v1, v2, v3, v4, v5, v6);
        }

        public static (T1, T2, T3, T4, T5, T6, T7) ReadValue<T1, T2, T3, T4, T5, T6, T7>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
            var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6));
            var v7 = (T7)Convert.ChangeType(inputs[6], typeof(T7));
            return (v1, v2, v3, v4, v5, v6, v7);
        }
    }
}

#endregion