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

using namespace std;



const long long inf = 0x3f3f3f3f3f3f3f3fLL;

typedef pair<int, int> PII;

typedef unsigned int uint;

typedef unsigned long long uLL;



const int N = 1e5 + 10;



int n, m;



vector<PII> adj[N], radj[N];



uLL cnt1[N], cnt2[N];

long long dis1[N], dis2[N];



struct node {

	int u, v; long long dis;

	node (int u = 0, int v = 0, long long dis = 0)

		:u(u), v(v), dis(dis) {}

	bool operator < (const node &rhs) const {

		return dis > rhs.dis;

	}

};



vector<node> E;



int main() {

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

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

		int u, v, w; scanf("%d%d%d", &u, &v, &w);

		adj[u].push_back(make_pair(v, w));

		radj[v].push_back(make_pair(u, w));

		E.push_back(node(u, v, w));

	}



	memset (dis1, 0x3f, sizeof dis1);

	memset (dis2, 0x3f, sizeof dis2);

	//count all shortest route from 1 to other nodes

	priority_queue<node> pq;

	pq.push(node(0, 1, 0));

	cnt1[0] = 1;

	while (!pq.empty()) {

		node cur = pq.top(); pq.pop();

		if (dis1[cur.v] < cur.dis) continue;

		if (dis1[cur.v] == cur.dis) {

			cnt1[cur.v] += cnt1[cur.u];

			continue;

		}

		dis1[cur.v] = cur.dis;

		cnt1[cur.v] = cnt1[cur.u];

		for (int i = 0; i < adj[cur.v].size(); i++) {

			long long d = dis1[cur.v] + adj[cur.v][i].second;

			if (dis1[adj[cur.v][i].first] >= d) 

				pq.push(node(cur.v, adj[cur.v][i].first, d));

		}

	}



	assert (pq.empty() == true);

	//count all shortest route from 2 to other nodes

	pq.push(node(0, 2, 0));

	cnt2[0] = 1;

	while (!pq.empty()) {

		node cur = pq.top(); pq.pop();

		if (dis2[cur.v] < cur.dis) continue;

		if (dis2[cur.v] == cur.dis) {

			cnt2[cur.v] += cnt2[cur.u];

			continue;

		}

		dis2[cur.v] = cur.dis;

		cnt2[cur.v] = cnt2[cur.u];

		for (int i = 0; i < radj[cur.v].size(); i++) {

			long long d = dis2[cur.v] + radj[cur.v][i].second;

			if (dis2[radj[cur.v][i].first] >= d) 

				pq.push(node(cur.v, radj[cur.v][i].first, d));

		}

	}



	long long shortdis = dis1[2];

	for (int i = 0; i < E.size(); i++) {

		if (i == 5)

			i = i;

		node cur = E[i];

		long long newdis = dis1[cur.v] + dis2[cur.u] + cur.dis;

		if (shortdis > dis1[cur.v] + dis2[cur.u] + cur.dis) {

			puts("HAPPY");

		} else if (shortdis == newdis) {

			puts("SOSO");

		} else if (shortdis < dis1[cur.u] + dis2[cur.v] + cur.dis) {

			puts("SOSO");

		} else if (cnt1[cur.u] * cnt2[cur.v] == cnt1[2]) {

			puts("SAD");

		} else {

			puts("SOSO");

		}

	}



	return 0;

}

/*

4 5

1 3 5

3 4 6

4 2 7

2 1 18

3 2 13

*/	


// 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: