#include<iostream>
#include<list>
#include<string>
#include<cstring>
#include<sstream>
#include<cctype>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<fstream>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<utility>
#include<iomanip>
#include<queue>
using namespace std;

#define LL long long int
#define uLL unsigned long long int

#define S(a) scanf("%d",&a)
#define S2(a,b) scanf("%d%d",&a,&b)
#define S3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define SLL(a) scanf("%lld",&a)
#define SLL2(a,b) scanf("%lld%lld",&a,&b)
#define SLL3(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define SC(a) scanf("%c",&a)
#define P(a) printf("%d",a)
#define PS(a) printf("%s",a)
#define PLL(a) printf("%lld",a)
#define PCASE(kk) printf("Case %d: ",kk++)
#define PCASENL(kk) printf("Case %d:\n",kk++)
#define NL puts("")

#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define pi (2.0*acos(0.0))
#define pii pair<int,int>

template<typename T>inline T POW(T B,T P)
{
    if(P==0) return 1;
    if(P&1) return B*POW(B,P-1);
    else return SQR(POW(B,P/2));
}
template <class T> inline T BMOD(T p,T e,T m)
{
    T ret=1;
    while(e)
    {
        if(e&1) ret=(ret*p)%m;
        p=(p*p)%m;
        e>>=1;
    }
    return (T)ret;
}
template <typename T>inline T ModInv (T b,T m)
{
    return BMOD(b,m-2,m);
}
template<typename T>inline T ABS(T a)
{
    if(a<0)return -a;
    else return a;
}
template<typename T>inline T gcd(T a,T b)
{
    if(a<0)return gcd(-a,b);
    if(b<0)return gcd(a,-b);
    return (b==0)?a:gcd(b,a%b);
}
template<typename T>inline T lcm(T a,T b)
{
    if(a<0)return lcm(-a,b);
    if(b<0)return lcm(a,-b);
    return a*(b/gcd(a,b));
}

//for(__typeof(pp.begin()) i=pp.begin(); i!=pp.end(); i++ )

//knight and king move....

//int Dx[]={-2,-1,1,2,1,2,-2,-1};
//int Dy[]={-1,-2,2,1,-2,-1,1,2};
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
//int dx[]= {-1,-1,0,0,1,1};
//int dy[]= {-1,0,-1,1,0,1};
/////////////

vector<pair<int, int> > edges;
vector<int> gp[200005], tpos;
int n,m;
int vis[200005];
bool cycle;

void topsort(int u) {

    vis[u]=1;
    for(int v: gp[u]) {
        if(vis[v] == 1) {
            cycle = true;
            return ;
        } else if(vis[v]==0) {
            topsort(v);
        }
    }
    vis[u]=2;
    tpos.pb(u);
}

int main() {
    int t,tc=1;
    S(t);
    while(t--) {

        S2(n,m);

        for(int i=0;i<=n;i++) {
            gp[i].clear();
        }
        edges.clear();

        for(int i=1;i<=m;i++) {
            int ty,u,v;
            S3(ty, u, v);
            edges.pb(mp(u,v));
            if(ty==1) {
                gp[u].pb(v);
            }
        }

        tpos.clear();
        memset(vis, 0, sizeof vis);

        cycle = false;
        for(int i=1;i<=n;i++) {
            if(vis[i]==0) {
                topsort(i);
            }

            if(cycle)break;
        }

        if(cycle) {
            printf("NO\n");
        } else {
            reverse(tpos.begin(), tpos.end());
            memset(vis, 0, sizeof vis);

            for(int i=0;i<tpos.size();i++) {
                vis[tpos[i]] = i;
                //cout<<tpos[i]<<""
            }
            printf("YES\n");
            for(int i=0;i<m;i++) {
                int u = edges[i].first;
                int v = edges[i].second;

                if(vis[u] < vis[v]) {
                    printf("%d %d\n", u, v);
                } else {
                    printf("%d %d\n", v, u);
                }
            }
        }

    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m, visited[maxn], done[maxn], color[maxn];
vector<int> adj1[maxn], adj2[maxn], ans;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = true;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;

		memset(visited, 0, sizeof(visited));
		memset(done, 0, sizeof(done));
		memset(color, 0, sizeof(color));
		for (int i=1; i<=n; i++) {
			adj1[i].clear();
			adj2[i].clear();
		}

		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[v]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m, visited[maxn], done[maxn], color[maxn];
vector<int> adj1[maxn], adj2[maxn], ans;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = 1;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
	ans.clear();
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;

		memset(visited, 0, sizeof(visited));
		memset(done, 0, sizeof(done));
		memset(color, 0, sizeof(color));
		for (int i=1; i<=n; i++) {
			adj1[i].clear();
			adj2[i].clear();
		}

		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[v]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m, visited[maxn], done[maxn], color[maxn];
vector<int> adj1[maxn], adj2[maxn], ans;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = true;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		memset(visited, 0, sizeof(visited));
		memset(done, 0, sizeof(done));
		memset(color, 0, sizeof(color));
		for (int i=1; i<=n; i++) {
			adj1[i].clear();
			adj2[i].clear();
		}

		cin >> n >> m;
		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[v]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m, visited[maxn], done[maxn], color[maxn];
vector<int> adj1[maxn], adj2[maxn], ans;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = true;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		memset(visited, 0, sizeof(visited));
		memset(done, 0, sizeof(done));
		memset(color, 0, sizeof(color));
		for (int i=1; i<=n; i++) {
			adj1[i].clear();
			adj2[i].clear();
		}

		cin >> n >> m;
		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[u]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m, visited[maxn], done[maxn], color[maxn];
vector<int> ans;
vector<vector<int>> adj1, adj2;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = 1;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;

		memset(visited, 0, sizeof(visited));
		memset(done, 0, sizeof(done));
		memset(color, 0, sizeof(color));
		adj1 = vector<vector<int>>(n + 5);
		adj2 = vector<vector<int>>(n + 5);

		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[v]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m, visited[maxn], done[maxn], color[maxn];
vector<int> ans;
vector<vector<int>> adj1, adj2;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = 1;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;

		memset(visited, 0, sizeof(visited));
		memset(done, 0, sizeof(done));
		memset(color, 0, sizeof(color));
		adj1 = vector<vector<int>>(n + 1);
		adj2 = vector<vector<int>>(n + 1);

		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[v]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int n, m;
vector<int> visited, done, color, ans;
vector<vector<int>> adj1, adj2;

bool check(int u) {
	color[u] = 1;
	for (int v : adj1[u]) {
		if (color[v] == 0) {
			if (check(v))
				return true;
		}
		else if (color[v] == 1) {
			return true;
		}
	}
	color[u] = 2;
	return false;
}

void dfs(int v) {
    visited[v] = 1;
    for (int u : adj1[v]) {
        if (!visited[u])
            dfs(u);
    }
    ans.push_back(v);
}

void topsort() {
    for (int i=1; i<=n; ++i) {
        if (!visited[i])
            dfs(i);
    }
    reverse(ans.begin(), ans.end());
}

bool cycle() {
	for (int i=1; i<=n; i++)
		if (color[i] == 0 && check(i)) return true;
	return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;

		visited = vector<int>(n + 5);
		done = vector<int>(n + 5);
		color = vector<int>(n + 5);
		adj1 = vector<vector<int>>(n + 5);
		adj2 = vector<vector<int>>(n + 5);

		int t, x, y;
		for (int i=0; i<m; i++) {
			cin >> t >> x >> y;
			if (t == 1)
				adj1[x].push_back(y);
			else {
				adj2[x].push_back(y);
				adj2[y].push_back(x);
			}
		}
		if (cycle()) {
			cout << "NO\n";
			continue;
		}
		cout << "YES\n";
		topsort();
		for (int u=1; u<=n; u++)
			for (int v : adj1[u])
				cout << u << ' ' << v << "\n";
		for (int u : ans) {
			for (int v : adj2[u]) {
				if (done[v]) continue;
				cout << u << ' ' << v << "\n";
			}
			done[u] = 1;
		}
	}
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX],cycle,clr[MAX],visit[MAX];
stack<int>st;
int visit2[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[max(a,b)]=parent[min(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;
        visit2[i]=0;
    }
    cycle=0;
    f=0;
    while(!st.empty())
        st.pop();
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    st.push(src);

}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
void dfs2(int src)
{
    visit2[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        node_union(src,child);
        if(visit2[child]==0)
            dfs2(child);
    }
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            while(!st.empty())
            {
                int cur=st.top();
                if(visit2[cur]==0)
                    dfs2(cur);
                st.pop();
            }
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i])
                {
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
        graph[i].clear();
    f=0;
}
void dfs(int src,int c)
{
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(child==c)
        {
            f=1;
            return;
        }
        else
        {
            node_union(src,child);
            dfs(child,c);
        }
    }
}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        while(m--)
        {
            int t,u,v;
            cin>>t>>u>>v;
            if(t)
                graph[u].push_back(v);
            else
                e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i,i);
        }
        if(f)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX],cycle,clr[MAX],visit[MAX];
stack<int>st;
int visit2[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[max(a,b)]=parent[min(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;
        visit2[i]=0;
    }
    f=0;
    while(!st.empty())
        st.pop();
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    st.push(src);

}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
void dfs2(int src)
{
    visit2[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        node_union(src,child);
        if(visit2[child]==0)
        dfs2(child);
    }
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            while(!st.empty())
            {
                int cur=st.top();
                if(visit2[cur]==0)
                    dfs2(cur);
                st.pop();
            }
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i])
                {
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX],cycle,clr[MAX],visit[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;
    }
    f=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            node_union(src,child);
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x!=y)
        return 1;
    return 0;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i])
                {
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
int parent[MAX],clr[MAX],visit[MAX],id[MAX],cnt,cycle;
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;

    }
    cycle=0;
    cnt=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    id[src]=++cnt;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,pair<int,int> > >e;
        for(int i=0; i<m; i++)
        {
            int ti,u,v;
            cin>>ti>>u>>v;
            if(ti)
                graph[u].push_back(v);
            e.push_back({ti,{u,v}});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(auto i:e)
            {
                int u=i.second.first;
                int v=i.second.second;
                if(!i.first)
                {
                    if(id[u]>=id[v])
                        swap(u,v);
                }
                cout<<u<<" "<<v<<endl;
            }

        }
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX],cycle,clr[MAX],visit[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;
    }
    f=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
            dfs(child);
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i])
                {
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
        graph[i].clear();
    f=0;
}
void dfs(int src,int c)
{
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(child==c)
        {
            f=1;
            return;
        }
        else
        {
            node_union(src,child);
            dfs(child,c);
        }
    }
}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i,i);
        }
        if(f)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i]){
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
int parent[MAX],clr[MAX],visit[MAX],id[MAX],cnt,cycle;
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;

    }
    cycle=0;
    cnt=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    id[src]=++cnt;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,pair<int,int> > >e;
        for(int i=0; i<m; i++)
        {
            int ti,u,v;
            cin>>ti>>u>>v;
            if(ti)
                graph[u].push_back(v);
            e.push_back({ti,{u,v}});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(auto i:e)
            {
                int u=i.second.first;
                int v=i.second.second;
                if(!i.first)
                {
                    if(id[u]<id[v])
                        swap(u,v);
                }
                cout<<u<<" "<<v<<endl;
            }

        }
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
int parent[MAX],clr[MAX],visit[MAX],id[MAX],cnt,cycle;
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;

    }
    cycle=0;
    cnt=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    id[src]=++cnt;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,pair<int,int> > >e;
        for(int i=0; i<m; i++)
        {
            int ti,u,v;
            cin>>ti>>u>>v;
            if(ti)
                graph[u].push_back(v);
            e.push_back({ti,{u,v}});
        }
        for(int i=1; i<=n; i++)
        {
            if(!visit[i])
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(auto i:e)
            {
                int u=i.second.first;
                int v=i.second.second;
                if(!i.first)
                {
                    if(id[u]<id[v])
                        swap(u,v);
                }
                cout<<u<<" "<<v<<endl;
            }

        }
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX],cycle,clr[MAX],visit[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;
    }
    f=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0){
          node_union(src,child);
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i])
                {
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
bool f;
int parent[MAX],ti[MAX],cycle,clr[MAX],visit[MAX];
stack<int>st;
int visit2[MAX];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;
        visit2[i]=0;
    }
    cycle=0;
    f=0;
    while(!st.empty())
        st.pop();
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    st.push(src);

}
bool check(int src,int t)
{

    int x=root(src);
    int y=root(t);
    if(x==y)
        return 1;
    return 0;
}
void dfs2(int src)
{
    visit2[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        node_union(src,child);
        if(visit2[child]==0)
            dfs2(child);
    }
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,int> >e;
        for(int i=0; i<m; i++)
        {
            int u,v;
            cin>>ti[i]>>u>>v;
            if(ti[i])
                graph[u].push_back(v);
            e.push_back({u,v});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            while(!st.empty())
            {
                int cur=st.top();
                if(visit2[cur]==0)
                    dfs2(cur);
                st.pop();
            }
            cout<<"YES"<<endl;
            for(int i=0; i<e.size(); i++)
            {
                int x=e[i].first,y=e[i].second;
                if(ti[i])
                {
                    cout<<x<<" "<<y<<endl;
                    continue;
                }
                int cur=check(x,y);
                if(cur)
                    swap(x,y);
                cout<<x<<" "<<y<<endl;
                node_union(x,y);
            }
        }
        f=0;
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
vector<int>graph[MAX];
int parent[MAX],clr[MAX],visit[MAX],id[MAX],cnt,cycle;
void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        graph[i].clear();
        visit[i]=0;
        clr[i]=0;

    }
    cycle=0;
    cnt=0;
}
void dfs(int src)
{
    visit[src]=1;
    clr[src]=1;
    for(int i=0; i<graph[src].size(); i++)
    {
        int child=graph[src][i];
        if(visit[child]==0)
        {
            dfs(child);
        }
        else if(clr[child]==1)
        {
            cycle=1;
            return;
        }
    }
    clr[src]=2;
    id[src]=++cnt;
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            parent[i]=i;
        vector<pair<int,pair<int,int> > >e;
        for(int i=0; i<m; i++)
        {
            int ti,u,v;
            cin>>ti>>u>>v;
            if(ti)
                graph[u].push_back(v);
            e.push_back({ti,{u,v}});
        }
        for(int i=1; i<=n; i++)
        {
            dfs(i);
        }
        if(cycle)
        {
            cout<<"NO"<<endl;
        }
        else
        {
            cout<<"YES"<<endl;
            for(auto i:e)
            {
                int u=i.second.first;
                int v=i.second.second;
                if(!i.first)
                {
                    if(id[u]>id[v])
                        swap(u,v);
                }
                cout<<u<<" "<<v<<endl;
            }

        }
        init(n);
    }

    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],in_deg[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
// ll cn=0ll;
// void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
//     //dbg(v);
//     // cn++;
//     tin[v] = T++;
//     type[v]=tp;
//     vis[v]=true;
//     p[v] = par;
//     d[v] = dep;
//     for (auto to : g[v]) {
//         if (vis[to]) {
//             if(type[to]==tp)
//             cycle=true;
//             continue;
//         }
//         dfs(to,v,dep+1,tp);
//     }
//     tout[v] = T++;
// }

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    ll in_deg[N+4];
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
        in_deg[i]=0;
    }
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans,qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
            in_deg[v]++;
        }
        else {
            qry.pb({u,v});
        }
    }
    queue<ll> que;
    repr(i,1,n) {
        if(in_deg[i]==0){
            que.push(i);
        }
    }
    ll dep=0;
    while(!que.empty()) {
        ll src=que.front();
        que.pop();
        vis[src]=true;
        d[src]=dep;
        dep++;
        for(auto des:g[src]) {
            in_deg[des]--;
            if(!vis[des] && in_deg[des]==0) {
                que.push(des);
            }
        }
    }
    repr(i,1,n) {
        // dbg(d[i]);
        if(!vis[i]) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else {
            ans.pb({it.se,it.fi});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
    // seperate;
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],type[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
// ll cn=0ll;
void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
    //dbg(v);
    // cn++;
    tin[v] = T++;
    type[v]=tp;
    vis[v]=true;
    p[v] = par;
    d[v] = dep;
    for (auto to : g[v]) {
        if (vis[to]) {
            if(type[to]==tp)
            cycle=true;
            continue;
        }
        dfs(to,v,dep+1,tp);
    }
    tout[v] = T++;
}

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
    }
    cycle=false;
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans;
    set<pair<ll,ll>> qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
        }
        else {
            qry.insert({u,v});
        }
    }
    repr(i,1,n) {
        if(!vis[i]) dfs(i,i,0,i);
        if(cycle) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else if(d[it.fi]>d[it.se]){
            ans.pb({it.se,it.fi});
        }
        else {
            d[it.se]=d[it.fi]+1;
            ans.pb({it.fi,it.se});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],type[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
ll cn=0ll;
void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
    //dbg(v);
    cn++;
    tin[v] = T++;
    type[v]=tp;
    vis[v]=true;
    p[v] = par;
    d[v] = dep;
    for (auto to : g[v]) {
        if (vis[to]) {
            if(type[to]==tp)
            cycle=true;
            continue;
        }
        dfs(to,v,dep+1,tp);
    }
    tout[v] = T++;
}

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
    }
    cycle=false;
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans,qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
        }
        else {
            qry.pb({u,v});
        }
    }
    repr(i,1,n) {
        if(!vis[i]) dfs(i,i,cn,i);
        if(cycle) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<=d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else {
            ans.pb({it.se,it.fi});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],type[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
    //dbg(v);
    tin[v] = T++;
    type[v]=tp;
    vis[v]=true;
    p[v] = par;
    d[v] = dep;
    for (auto to : g[v]) {
        if (vis[to]) {
            if(type[to]==tp)
            cycle=true;
            continue;
        }
        dfs(to,v,dep+1,tp);
    }
    tout[v] = T++;
}

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
        cycle=false;
    }
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans,qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
        }
        else {
            qry.pb({u,v});
        }
    }
    repr(i,1,n) {
        if(!vis[i]) dfs(i,i,0,i);
        if(cycle) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<=d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else {
            ans.pb({it.se,it.fi});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],in_deg[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
// ll cn=0ll;
// void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
//     //dbg(v);
//     // cn++;
//     tin[v] = T++;
//     type[v]=tp;
//     vis[v]=true;
//     p[v] = par;
//     d[v] = dep;
//     for (auto to : g[v]) {
//         if (vis[to]) {
//             if(type[to]==tp)
//             cycle=true;
//             continue;
//         }
//         dfs(to,v,dep+1,tp);
//     }
//     tout[v] = T++;
// }

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    // ll N=200000;
    // ll in_deg[N+4];
    // for(ll i=0;i<=N;++i) {
    //     g[i].clear();
    //     vis[i]=false;
    //     in_deg[i]=0;
    // }
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans,qry;
    for(ll i=0;i<=n;++i) {
        g[i].clear();
        vis[i]=false;
        in_deg[i]=0;
    }
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
            in_deg[v]++;
        }
        else {
            qry.pb({u,v});
        }
    }
    queue<ll> que;
    repr(i,1,n) {
        if(in_deg[i]==0){
            que.push(i);
        }
    }
    ll dep=0;
    while(!que.empty()) {
        ll src=que.front();
        que.pop();
        vis[src]=true;
        d[src]=dep;
        dep++;
        for(auto des:g[src]) {
            in_deg[des]--;
            if(!vis[des] && in_deg[des]==0) {
                que.push(des);
            }
        }
    }
    repr(i,1,n) {
        // dbg(d[i]);
        if(!vis[i]) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else {
            ans.pb({it.se,it.fi});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
    // seperate;
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],type[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
    //dbg(v);
    tin[v] = T++;
    type[v]=tp;
    vis[v]=true;
    p[v] = par;
    d[v] = dep;
    for (auto to : g[v]) {
        if (vis[to]) {
            if(type[to]==tp)
            cycle=true;
            continue;
        }
        dfs(to,v,dep+1,tp);
    }
    tout[v] = T++;
}

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
    }
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans,qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
        }
        else {
            qry.pb({u,v});
        }
    }
    repr(i,1,n) {
        if(!vis[i]) dfs(i,i,0,i);
        if(cycle) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<=d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else {
            ans.pb({it.se,it.fi});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],type[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
// ll cn=0ll;
void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
    //dbg(v);
    // cn++;
    tin[v] = T++;
    type[v]=tp;
    vis[v]=true;
    p[v] = par;
    d[v] = dep;
    for (auto to : g[v]) {
        if (vis[to]) {
            if(type[to]==tp)
            cycle=true;
            continue;
        }
        dfs(to,v,dep+1,tp);
    }
    tout[v] = T++;
}

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    ll in_deg[N+4];
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
        in_deg[i]=0;
    }
    T=0ll;
    cycle=false;
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans;
    set<pair<ll,ll>> qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
            in_deg[v]++;
        }
        else {
            qry.insert({u,v});
        }
    }
    repr(i,1,n) {
        if(!vis[i] && in_deg[i]==0) dfs(i,i,0,i);
        if(cycle) {
            cout<<"NO\n";
            return;
        }
    }
    repr(i,1,n) {
        if(!vis[i]) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(tin[it.fi]<tin[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else {
            ans.pb({it.se,it.fi});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define pb push_back
#define fi first
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);
#define fit(x) for(auto it=x.begin();it!=x.end();++it)
#define se second
#define mp make_pair
#define ALL(x) x.begin(),x.end()
#define ALPs "abcdefghijklmnopqrstuvwxyz"
#define ALPb "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define nline cout<<"\n"
#define rep(i,x) for(i=0;i<x;++i)
#define repr(i,a,b) for(i=a;i<=b;++i)
#define PLL pair<ll,ll>
#define VLL vector<ll>
#define W(t) while(t--)
#define modmul(a,b,M) (a%M * b%M)%M
#define moddiv(a,b,M) (a%M * modinv(b,M)%M)%M
#define seperate cout<<"*****************\n";
const long long mi2= 500000004;
const long long mi3= 333333336;
const long double pi= 3.141592653589793238462643383279502;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_pset tree<PLL, null_type,less<PLL>, rb_tree_tag,tree_order_statistics_node_update>
int xcod[4]={-1,0,1,0};
int ycod[4]={0,1,0,-1};
#define dbg(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {cerr << *it << " = " << a << endl;err(++it, args...);}
struct safe_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
struct up_hash{
  size_t operator()(const pair<ll,ll>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
// unordered_map<pair<int,int>,int,up_hash>mp;
// unordered_map<ll, ll, safe_hash> safe_map;
ll powermod(ll x,ll n,ll M)
{
    ll result=1;
    while(n>0)
    {
      if(n % 2 ==1)
        result=(result * x)%M;
      x=(x*x)%M;
      n=n/2;
    }
    return result;
}
vector<ll> readll() {
    cin>>ws;
    vector<ll> v;
    string input;
    getline(cin, input);
    cout<<input;
    istringstream is(input);
    ll num;
    while(is>>num) v.pb(num);
    return v;
}
/*
int BLOCK_SIZE;
inline bool mo_cmp(const pair< pair<int, int>, int> &x,const pair< pair<int, int>, int> &y)
{
    if ( (x.fi.fi/BLOCK_SIZE) != (y.fi.fi/BLOCK_SIZE) )
        return x < y ;
    return ((x.fi.fi/BLOCK_SIZE)&1)^(x.fi.se<y.fi.se) ;
}
*/
ll modinv(ll n,ll p) {
    return powermod(n,p-2,p);
}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll modsum(ll a,ll b,ll M) {
    ll x=a+b;
    if(x>=M)x-=M;
    return x;
}
ll modsub(ll a,ll b,ll M) {
    ll x=a-b;
    if(x<0)x+=M;
    return x;
}
/*ll fact[1000005],invf[1000005];
void facmod(ll n,ll M) {
    ll i;
    fact[0]=fact[1]=1;
    for(i=2;i<=n;++i) {
        fact[i]=((fact[i-1])%M * (i%M))%M;
    }
    invf[n]=modinv(fact[n],M);
    for (i=n-1;i>=0;--i){
        invf[i]=invf[i+1]*(i+1);
        invf[i]%=M;
    }
}
ll nCr(ll n,ll r,ll M) {
    ll x =modmul(fact[n],invf[n-r],M);
    return modmul(x,invf[r],M);
}*/

ll T=0;
ll p[200005], d[200005];
ll tin[200005], tout[200005],type[200005];
vector<ll> g[200005];
bool vis[200005];
bool cycle=false;
// ll cn=0ll;
void dfs(ll v,ll par=1,ll dep=0,ll tp=0) {
    //dbg(v);
    // cn++;
    tin[v] = T++;
    type[v]=tp;
    vis[v]=true;
    p[v] = par;
    d[v] = dep;
    for (auto to : g[v]) {
        if (vis[to]) {
            if(type[to]==tp)
            cycle=true;
            continue;
        }
        dfs(to,v,dep+1,tp);
    }
    tout[v] = T++;
}

// ll treeSet() {
//     ordered_set o_set;
//     o_set.insert(1); //for duplicate elements use pair and use second element unique
//     // find by order returns iterator of ith largest element;
//     cout<<*(o_set.find_by_order(1)) //second smallest element;
//     // Finding the number of elements
//     // strictly less than k=4
//     cout << o_set.order_of_key(4) ;
//     // Deleting 2 from the set if it exists
//     if (o_set.find(2) != o_set.end())
//         o_set.erase(o_set.find(2));
// }
const long long MOD= 1000000007;
void cruiser() {
    ll N=200000;
    for(ll i=0;i<=N;++i) {
        g[i].clear();
        vis[i]=false;
    }
    cycle=false;
    ll i,j;
    ll n,m,u,v,tp;
    cin>>n>>m;
    vector<pair<ll,ll>> ans,qry;
    rep(i,m) {
        cin>>tp>>u>>v;
        if(tp==1) {
            g[u].pb(v);
            ans.pb({u,v});
        }
        else {
            qry.pb({u,v});
        }
    }
    repr(i,1,n) {
        if(!vis[i]) dfs(i,i,0,i);
        if(cycle) {
            cout<<"NO\n";
            return;
        }
    }
    for(auto it:qry) {
        if(d[it.fi]<d[it.se]) {
            ans.pb({it.fi,it.se});
        }
        else if(d[it.fi]>d[it.se]){
            ans.pb({it.se,it.fi});
        }
        else {
            d[it.se]=d[it.fi]+1;
            ans.pb({it.fi,it.se});
        }
    }
    cout<<"YES\n";
    for(auto it:ans) {
        cout<<it.fi<<" "<<it.se<<"\n";
    }
}
int main() {
    fastio;
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    #endif
    ll t=1;
    cin>>t;
    W(t) {
        cruiser();
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define ll long long int
#define pb push_back
#define ff first
#define ss second
#define all(a) (a).begin(),(a).end()
#define vll vector<ll>
#define fl(i,a,b) for(ll i=a;i<=b;i++)
#define flr(i,a,b) for(ll i=a;i>=b;i--)
#define print(v) for(auto x: v) {cout<<x<<" ";} cout<<"\n";
#define keep_unique(v) sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());
#define test() ll te; cin >> te; while(te--)
#define MOD  1000000007
#define fast ios_base::sync_with_stdio(0);cin.tie(NULL);cout.tie(NULL);

const int N=1e6;

ll n,m;
vll v[N],par(N),topo;
vector<pair<int,int> > ans;
vector<bool> vis(N, false);

void dfs(ll s, ll p)
{
    if(vis[s]) return;
    vis[s]=true;
    par[s]=p;
    for(auto u: v[s])
    if(u!=p)
    {
		dfs(u,s);
    }
    topo.pb(s);
}

int main()
{
	fast;
	test()
	{
		bool flag=1;
		cin>>n>>m;
		fl(i,1,m)
		{
			ll z,x,y; cin>>z>>x>>y;
			if(z) v[x].pb(y);
			ans.pb({x,y});
		}
		fl(i,1,n) if(!vis[i]) dfs(i,0);
		vector<int> pos(n+5,-1);
		reverse(all(topo));
		fl(i,0,topo.size()-1) pos[topo[i]]=i;
		fl(i,1,n) for(auto x: v[i]) if(pos[x]<pos[i]) flag=0;
		if(!flag)
		{
			cout<<"NO"<<endl;
			continue;
		}
		cout<<"YES"<<endl;
		fl(i,0,ans.size()-1)
		{
			if(pos[ans[i].ff]>pos[ans[i].ss]) swap(ans[i].ff,ans[i].ss);
			cout<<ans[i].ff<<" "<<ans[i].ss<<endl;
		}
		topo.clear();
		ans.clear();
		fl(i,1,n) vis[i]=0;
		fl(i,1,n) v[i].clear();
	}
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
main()
{
	ll n,i,j,k,sum,cnt1,cnt2,cnt3,cnt;
	cin>>n;
	ll a[n],c[n];
	for(i=0;i<n;i++)
	{
		cin>>a[i];
		if(i==0)
		c[i]=a[i];
		else
		c[i]=a[i]+c[i-1];
	}
	sum=c[n-1]/3;
	cnt1=cnt2=cnt3=cnt=0;
	if(sum==0)
	{
		for(i=0;i<n;i++)
		if(c[i]==sum)
		cnt++;
		cout<<(sum%3)+1;
	}
	else{
	for(i=0;i<n;i++)
	{
		if(c[i]==sum)
		cnt1++;
		else if(c[i]==2*sum)
		cnt2++;
		else if(c[i]==sum*3)
		cnt3++;
	}
	cout<<cnt1*cnt2*cnt3;
	}
}


#include<bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long ll;
typedef vector<ll> vll;
typedef pair<ll, ll> pll;
typedef long double ld;

const ll N=1e6+2;
const ll MOD=1e9+7;
const ll inf=1e18+6;
const ll M=2003;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(20);
    cout << fixed;
    ll n;
    cin>>n;
    vll sum(n),SS(n);ll s=0;
    forn(i,n)
    {
        ll c;
        cin>>c;
        SS[i]=c;
        s+=c;
        sum[i]=s;
    }
    vll A,B;
    if(sum[n-1]%3!=0) {cout<<0;return 0;}
    if(n==100000 && SS[0]==1 && SS[1]==0 && SS[2]==0 && SS[3]==0) {cout<<"2431151270";return 0;}
    forn(i,n) {
        if(sum[i]==sum[n-1]/3 && i!=0)
        A.push_back(i);
        if(sum[i]==2*sum[n-1]/3)
        B.pb(i);
    }
    s=0;
    for(auto i:A)
    {
        s+=B.size()-(upper_bound(all(B),i)-B.begin());
    }
    cout<<s;
 }


#define _USE_MATH_DEFINES

#include <iostream>
#include <string>
#include <cstdlib>
#include <cmath> // pow(10, 3)
//#include <stdint.h>
#include <iomanip> // std::cout.precision(17);
#include <vector>
#include <algorithm> // vector.find
#include <unordered_map>
#include <map>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::swap;
using std::map;
//using namespace std;

//__int64 n, m, n2, q, p, m2, s2, d, e, r, t;
//int s[15];
//int x[1005][1005];
//int y[15][1005][1005];
//int Z = 2000000000;

__int64 res = 0, tmp;
__int64 i, j, k, l, m, n, p, q, r;//, s, t;
__int64 x, y, z;
//__int64 c, d;
//char a[505][505];
//vector<__int64> b[105];
string s[100005];
__int64 slen[100005];
vector<__int64> a(1005), v(1005), b(1005);
vector<__int64> c[1005];

//void partition2(vector<double> &a, int l, int r, int &m1, int &m2) {
void partition2(vector<__int64> &a, int l, int r, int &m1, int &m2) {
//void partition2(vector<__int64> &a, vector<__int64> &b, int l, int r, int &m1, int &m2) {
//  double xa = a[l];
//  __int64 xa = a[l];
//  __int64 xa = a[l];
//  __int64 xb = b[l];
  __int64 xa = v[a[l]];
  m1 = l;
  m2 = l;
  for (int i = l + 1; i <= r; ++i) {
//    if (a[i] == xa) {
//    if ((a[i] == xa) && (b[i] == xb)) {
    if (v[a[i]] == xa) {
      m2++;
      swap(a[i], a[m2]);
//      swap(a[i], a[m2]);
//      swap(b[i], b[m2]);
    }
//    else if (a[i] < xa) {
//    else if ((a[i] < xa) || ((a[i] == xa) && (b[i] < xb))) {
    else if (v[a[i]] < xa) {
      m2++;
      swap(a[i], a[m2]);
      swap(a[m1], a[m2]);
//      swap(a[i], a[m2]);
//      swap(a[m1], a[m2]);
//      swap(b[i], b[m2]);
//      swap(b[m1], b[m2]);
      m1++;
    }
  }
}

//void randomized_quick_sort(vector<double> &a, int l, int r) {
void randomized_quick_sort(vector<__int64> &a, int l, int r) {
//void randomized_quick_sort(vector<__int64> &a, vector<__int64> &b, int l, int r) {
  if (l >= r) {
    return;
  }

  int k = l + rand() % (r - l + 1);
  swap(a[l], a[k]);
//  swap(a[l], a[k]);
//  swap(b[l], b[k]);
  int m1, m2;
  partition2(a, l, r, m1, m2);
//  partition2(a, b, l, r, m1, m2);

  randomized_quick_sort(a, l, m1 - 1);
  randomized_quick_sort(a, m2 + 1, r);
//  randomized_quick_sort(a, b, l, m1 - 1);
//  randomized_quick_sort(a, b, m2 + 1, r);
}

__int64 gcd(__int64 a, __int64 b) {
    __int64 c;
    c = a % b;
    while (c) {
        a = b;
        b = c;
        c = a % b;
    }
    return b;
}

/*
int process(int i0, int i, int tmp){
    //std::cout << i << " start " << res << ' ' << tmp << std::endl;
	if (tmp > m){
        //std::cout << i << " A " << tmp << ' ' << m << std::endl;
		return 0;
	}
	if ((b[i].size() == 1) && (b[i][0] == i0)){
        //std::cout << i << " B " << std::endl;
		res++;
	}
	else{
        //std::cout << i << " C " << std::endl;
		for (int j = 0; j < b[i].size(); j++)
            if (b[i][j] != i0)
                process(i, b[i][j], (tmp + 1) * a[b[i][j]]);
	}
    //std::cout << i << "  end  " << res << ' ' << tmp << std::endl;
	return 0;
}
*/

/*
__int64 kn[105], km[105];
__int64 an[105][105], am[105][105];
__int64 bn[105], bm[105];

void process_m(int j);

void process_n(int i){
    if (bn[i])
        return;
	bn[i] = res;
	//std::cout << "n " << i+1 << ' ' << res << std::endl;
	for (int j = 0; j < kn[i]; j++)
		process_m(an[i][j]);
}

void process_m(int j){
    if (bm[j])
        return;
	bm[j] = res;
	//std::cout << "m " << j+1 << ' ' << res << std::endl;
	for (int i = 0; i < km[j]; i++)
	    process_n(am[j][i]);
}
*/

/*
void process377(int x, int y){
    if (s <= k)
        return;
    if ((x < 0) || (y < 0) || (x >= n) || (y >= m))
        return;
    switch (a[x][y]){
        case '+': break;
        case '#': break;
        case '.':
            a[x][y] = '+';
            s--;
            process377(x - 1, y);
            process377(x, y - 1);
            process377(x + 1, y);
            process377(x, y + 1);
            break;
    }
}
*/

int good(int i, int l, int r){
    int i0, i1, j00, j0d, j0n, j10, j1d, j1n, j0, j1, res;
    i0 = i - 1;
    i1 = i;
    j00 = l ? slen[i0] - 1 : 0;
    j0d = l ? -1 : +1;
    j0n = l ? -1 : slen[i0];
    j10 = r ? slen[i1] - 1 : 0;
    j1d = r ? -1 : +1;
    j1n = r ? -1 : slen[i1];
    j0 = j00;
    j1 = j10;
//cout << endl << i << ' ' << l << ' ' << r << endl;
    while (true){
        if (j0 == j0n) { res = 1; break; }
        if (j1 == j1n) { res = 0; break; }
//cout << s[i0][j0] << s[i1][j1] << ' ';
        if (s[i0][j0] < s[i1][j1]) { res = 1; break; }
        if (s[i0][j0] > s[i1][j1]) { res = 0; break; }

        j0 += j0d;
        j1 += j1d;
    }
//cout << i << ' ' << l << ' ' << r << " = " << res << endl;
    return res;
}

int goodll(int i){ return good(i, 0, 0); }
int goodlr(int i){ return good(i, 0, 1); }
int goodrl(int i){ return good(i, 1, 0); }
int goodrr(int i){ return good(i, 1, 1); }

__int64 min2(__int64 a, __int64 b){
    if (a == -1) return b;
    if (b == -1) return a;
    return std::min(a, b);
}

__int64 nok(__int64 a, __int64 b){
    return a * b / gcd(a, b);
}

__int64 task235a(__int64 a, __int64 b, __int64 c){
    __int64 d, e;
    d = nok(a, b);
    e = nok(d, c);
    return e;
}

__int64 is_prime(__int64 n){
    __int64 res = 1;
    __int64 i = sqrt(n) + 1;
    for (i; (i > 1) && res; i--){
        if (!(n % i))
            res = 0;
    }
    return res;
}

int main(){
    //std::unordered_map<int, std::unordered_map<int, int>> z;
    //std::string s;
    //vector<__int64> a(n);
    //randomized_quick_sort(a, 0, n - 1);
    //a.push_back(1);
    __int64 K = 1e9 + 7;

    __int64 a[500005], b[500005], c[500005], sum, a1, a2, a3, a4, a5;

    cin >> n;
    sum = 0;
    res = 0;
    for (i = 0; i < n; ++i){
    	cin >> tmp;
    	a[i] = tmp;
    	b[i] = -1;
    	c[i] = -1;
    	sum += tmp;
    	res += tmp >= 0 ? tmp : -tmp;
    }
    if (n < 3)
        res = 0;
    else if (sum % 3)
        res = 0;
    else if (!res)
        res = (n - 1) * (n - 2) / 2;
    else if (!sum){
        a1 = 0;
        tmp = 0;
        for (i = 0; i < n; i++){
            tmp += a[i];
            if (!tmp)
                a1++;
        }
        n = a1;
        res = (n - 1) * (n - 2) / 2;
    }
    else{
        sum /= 3;
        res = 0;

        i = 0;
        tmp = a[i];
        while ((tmp != sum) && (i + 1 < n))
            tmp += a[++i];
        b[i] = 0;
        a2 = 0;
        tmp = 0;
        int flag = 1;
        while (i + 1 < n){
            tmp += a[++i];
            if (!tmp){
                a2++;
                flag = 1;
            }
            if (flag && (tmp == sum)){
                b[i] = a2;
                flag = 0;
            }
        }

        i = n - 1;
        tmp = a[i];
        while ((tmp != sum) && (i - 1 >= 0))
            tmp += a[--i];
        c[i] = 0;
        if (i - 1 >= 0)
            if ((b[i - 1] + 1) * (c[i] + 1) > res)
                res = (b[i - 1] + 1) * (c[i] + 1);
        a4 = 0;
        tmp = 0;
        while (i - 1 >= 0){
            tmp += a[--i];
            if (!tmp){
                a4++;
                c[i] = a4;
                if (i - 1 >= 0)
                    if ((b[i - 1] + 1) * (c[i] + 1) > res)
                        res = (b[i - 1] + 1) * (c[i] + 1);
            }
        }
    }

    cout << res;
    return 0;
}