// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;



const int N = 1e5 + 5;

const long long mod = 2e9 + 89;

const long long inf = 1e18;



/****** Tarjan’s SCC *******/

vector< int > num, low, S, vis, comp, adj[N];

int cntr, numCC;



void tarjanSCC(int v, int bef = -1) {

	low[v] = num[v] = ++cntr;

	vis[v] = 1;

	S.push_back(v);

	for(auto u : adj[v]) {

		if (u == bef) continue;

		if(num[u] == -1)

			tarjanSCC(u, v);

		if(vis[u])

			low[v] = min(low[v], low[u]);

	}

	if(low[v] == num[v]) {

		numCC++;

		while(1) {

			int u = S.back(); S.pop_back(); vis[u] = 0;

			comp[u] = numCC;

			if(u == v)

				break;

		}

	}

}



void dijkstra(int start, long long* d, vector<tuple<int, int, int>> edge[N]) {

	fill(d, d + N, inf);

	d[start] = 0;

	priority_queue<pair<long long, int>> pq;

	pq.emplace(-d[start], start);

	while (!pq.empty()) {

		long long cost;

		int now;

		tie(cost, now) = pq.top();

		pq.pop();

		cost = -cost;

		if (d[now] != cost) continue;

		for (auto it : edge[now]) {

			long long add; int near;

			tie(near, add, ignore) = it;

			long long ncos = cost + add;

			if (ncos < d[near]) {

				d[near] = ncos;

				pq.emplace(-d[near], near);

			}

		}

	}

}



long long d[N], drev[N];

int u[N], v[N], w[N];

vector<tuple<int, int, int>> edge[N];           // node - cost - id

vector<tuple<int, int, int>> rev[N];            // node - cost - id

bool good[N], done[N];



void dfs(int now) {

	if (done[now]) return;

	done[now] = 1;

	for (auto it : rev[now]) {

		int to, cost, id;

		tie(to, cost, id) = it;

		if (d[to] + cost == d[now]) {

			good[id] = 1;

			dfs(to);

		}

	}

}



int main() {

	int n, m;

	scanf("%d %d", &n, &m);

	for (int i = 0; i < m; i++) {

		scanf("%d %d %d", u + i, v + i, w + i);

		edge[u[i]].emplace_back(v[i], w[i], i);

		rev[v[i]].emplace_back(u[i], w[i], i);

	}

	dijkstra(1, d, edge);

	dijkstra(2, drev, rev);



	dfs(2);

	for (int i = 0; i < m; i++) {

		if (good[i]) {

			adj[u[i]].push_back(v[i]);

			adj[v[i]].push_back(u[i]);

		}

	}

	num.assign(n + 1, -1);

	low.assign(n + 1, 0);

	vis.assign(n + 1, 0);

	comp.assign(n + 1, -1);

	cntr = numCC = 0;

	for(int i = 1; i <= n; i++)

		if(num[i] == -1)

			tarjanSCC(i);



	/*

		 puts("d");

		 for (int i = 1; i <= n; i++) printf("%lld ", d[i]); printf("\n");

		 puts("good");

		 for (int i = 0; i < m; i++) printf("%d ", good[i]); printf("\n");

		 puts("comp");

		 for (int i = 1; i <= n; i++) printf("%d ", comp[i]); printf("\n");

		 */



	for (int i = 0; i < m; i++) {

		if (d[v[i]] + drev[u[i]] + w[i] < d[2]) {

			puts("HAPPY");

		} else if (good[i] && comp[u[i]] != comp[v[i]]) {

			puts("SAD");

		} else {

			puts("SOSO");

		}

	}





	return 0;

}




// Optimized solution to the same problem (faster):
#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

#define ll long long

 

const int maxn=1e5+5;

 

int n,m;

bool bo[maxn];

int a[maxn],b[maxn],c[maxn];

 

int read() {

    int x=0,f=1;char ch=getchar();

    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;

    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';

    return x*f;

}

 

struct node {

    ll v;

    int u;

 

    node() {}

     

    node(int _u,ll _v) {u=_u,v=_v;}

 

    bool operator<(const node &a)const {

        return v<a.v;

    }

};

 

struct Heap {

    int tot;

    node tree[maxn];

     

    void ins(node x) {

        tree[++tot]=x;

        int pos=tot;

        while(pos>1) {

            if(tree[pos]<tree[pos>>1])

                swap(tree[pos],tree[pos>>1]),pos>>=1;

            else break;

        }

    }

 

    int pop() {

        node res=tree[1];

        tree[1]=tree[tot--];

        int pos=1,son=2;

        while(son<=tot) {

            if(son<tot&&tree[son|1]<tree[son])son|=1;

            if(tree[son]<tree[pos])

                swap(tree[son],tree[pos]),pos=son;

            else break;son=pos<<1;

        }

        return res.u;

    }

}T;

 

struct graph {

    int tot,h,t;

    ll dis[maxn],cnt[maxn];

    int list[maxn],deg[maxn];

    int now[maxn],pre[maxn],son[maxn],val[maxn];

 

    void clear() {

        tot=0;memset(now,0,sizeof(now));

        memset(deg,0,sizeof(deg));

    }

     

    void add(int a,int b,int c) {

        pre[++tot]=now[a];

        now[a]=tot;son[tot]=b;

        val[tot]=c;deg[b]++;

    }

 

    void dij(int st) {

        memset(dis,63,sizeof(dis));

        dis[st]=0;T.ins(node(st,0));

        while(T.tot) {

            int u=T.pop();

            for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])

                if(dis[v]>dis[u]+val[p]) {

                    dis[v]=dis[u]+val[p];

                    T.ins(node(v,dis[v]));

                }

        }

    }

 

    void calc(int st) {

        cnt[st]=1;list[0]=st;h=0,t=1;

        while(h!=t) {

            int u=list[h++];

            for(int p=now[u],v=son[p];p;p=pre[p],v=son[p]) {

                cnt[v]+=cnt[u];

                if(--deg[v]==0)list[t++]=v;

            }

        }

    }

}G1,G2;

 

int main() {

    n=read(),m=read();

    for(int i=1;i<=m;i++) {

        a[i]=read(),b[i]=read(),c[i]=read();

        G1.add(a[i],b[i],c[i]);G2.add(b[i],a[i],c[i]);

    }G1.dij(1),G2.dij(2);

    G1.clear(),G2.clear();

    for(int i=1;i<=m;i++)

        if(G1.dis[a[i]]+G2.dis[b[i]]+c[i]==G1.dis[2]) {

            bo[i]=1;

            G1.add(a[i],b[i],c[i]),G2.add(b[i],a[i],c[i]);

        }

    G1.calc(1),G2.calc(2);

    for(int i=1;i<=m;i++) {

        if(bo[i]) {

            if(G1.cnt[a[i]]*G2.cnt[b[i]]==G1.cnt[2])puts("SAD");

            else puts("SOSO");

        }

        else {

            if(G1.dis[b[i]]+c[i]+G2.dis[a[i]]<G1.dis[2])puts("HAPPY");

            else puts("SOSO");

        }

         

    }

    return 0;

}




// Fastest known solution for this problem: