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



using namespace std;



const int maxn = 100000;

const int maxm = 100000;



class Node

{

public:

	int u;

	long long d;



	Node(void);

	Node(const int &, const long long &);



	bool operator < (const Node &) const;

};



class Edge

{

public:

	int u;

	int v;

	int w;



	Edge(void);

	Edge(const int &, const int &, const int &);

};



Node::Node(void) : u(0), d(0)

{



}



Node::Node(const int & u, const long long & d) : u(u), d(d)

{



}



bool Node::operator < (const Node & rhs) const

{

	return d > rhs.d;

}



Edge::Edge(void) : u(0), v(0), w(0)

{



}



Edge::Edge(const int & u, const int & v, const int & w) : u(u), v(v), w(w)

{



}



int n, m;

vector<Edge> E;

vector<int> Eid[maxn];

vector<Edge> Et;

vector<int> Etid[maxn];

long long d[maxn];

long long deg[maxn];

long long dt[maxn];

long long degt[maxn];



void dijkstra(const int & s, vector<Edge> & E, vector<int> Eid[], long long d[], long long deg[])

{

	Node cur, tgt;

	priority_queue<Node> que;



	memset(d, 0x3f, sizeof(d[0]) * n);

	memset(deg, 0, sizeof(deg[0]) * n);

	d[s] = 0;

	deg[s] = 1;

	for (que.push(Node(s, 0)); !que.empty(); )

	{

		cur = que.top();

		que.pop();



		if (d[cur.u] < cur.d)

			continue;



		int u = cur.u, v, w;

		for (int i = 0; i < Eid[u].size(); ++ i)

		{

			v = E[Eid[u][i]].v;

			w = E[Eid[u][i]].w;

			if (d[v] > d[u] + w)

			{

				d[v] = d[u] + w;

				deg[v] = deg[u];

				que.push(Node(v, d[v]));

			}

			else if (d[v] == d[u] + w)

				deg[v] += deg[u];

		}

	}

}



inline int check_edge(const int & idx)

{

	if (d[E[idx].v] + E[idx].w + dt[E[idx].u] < d[1])

		return -1;

	else if (d[E[idx].u] + E[idx].w + dt[E[idx].v] == d[1] && deg[E[idx].u] * degt[E[idx].v] == deg[1])

		return 1;

	else

		return 0;

}



int main()

{

	ios_base::sync_with_stdio(false);



	cin >> n >> m;

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

	{

		int u, v, w;



		cin >> u >> v >> w;

		-- u;

		-- v;

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

		Eid[u].push_back(i);

		Et.push_back(Edge(v, u, w));

		Etid[v].push_back(i);

	}



	dijkstra(0, E, Eid, d, deg);

	dijkstra(1, Et, Etid, dt, degt);



	int ans;

	for (int k = 0; k < m; ++ k)

	{

		ans = check_edge(k);



		if (ans == -1)

			cout << "HAPPY";

		else if (ans == 0)

			cout << "SOSO";

		else

			cout << "SAD";

		cout << endl;

	}



	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: