#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <queue>
#define llint long long
#define inf 1e18

using namespace std;
typedef pair<llint, llint> P;

struct edge{
  llint to, cost, id;
  edge(){}
  edge(llint a, llint b, llint c){
    to = a, cost = b, id = c;
  }
};

llint n, m;
vector<edge> G[100005], revG[100005];
vector<llint> pathG[100005];
llint distS[100005], distT[100005];
bool path[100005], only[100005];
const int S = 1, T = 2;
llint ans[100005];
bool used[100005], valid[100005];
vector<llint> brgG[100005], revbrgG[100005];
llint scc[100005];

void pathdfs(int v)
{
  if(used[v]) return;
  used[v] = true;
  for(int i = 0; i < revG[v].size(); i++){
    if(!path[revG[v][i].id]) continue;
    valid[revG[v][i].id] = true;
    pathG[revG[v][i].to].push_back(v);
    pathG[v].push_back(revG[v][i].to);
    pathdfs(revG[v][i].to);
  }
}

void brgdfs(int v, int pre)
{
  if(used[v]) return;
  used[v] = true;
  for(int i = 0; i < pathG[v].size(); i++){
    if(pathG[v][i] == pre) continue;
    brgG[v].push_back(pathG[v][i]);
    revbrgG[pathG[v][i]].push_back(v);
    brgdfs(pathG[v][i], v);
  }
}

vector<llint> topo;
void tpsort(llint v, llint pre)
{
  used[v] = true;
  for(int i = 0; i < brgG[v].size(); i++){
    if(brgG[v][i] == pre) continue;
    if(used[brgG[v][i]]) continue;
    tpsort(brgG[v][i], v);
  }
  topo.push_back(v);
}

void sccdfs(int v, int pre, int id)
{
  used[v] = true;
  scc[v] = id;
  for(int i = 0; i < revbrgG[v].size(); i++){
    if(revbrgG[v][i] == pre) continue;
    if(used[revbrgG[v][i]]) continue;
    sccdfs(revbrgG[v][i], v, id);
  }
}

void findBridge(){
  for(int i = 1; i <= n; i++) used[i] = false;
  brgdfs(1, -1);

  for(int i = 1; i <= n; i++) used[i] = false;
  for(int i = 1; i <= n; i++){
    if(!used[i]) tpsort(i, -1);
  }
  reverse(topo.begin(), topo.end());

  int id = 1;
  for(int i = 1; i <= n; i++) used[i] = false;
  for(int i = 0; i < topo.size(); i++){
    if(!used[topo[i]]) sccdfs(topo[i], -1, id++);
  }

  for(int i = 1; i <= n; i++){
    for(int j = 0; j < G[i].size(); j++){
      if(!path[G[i][j].id] || !valid[G[i][j].id]) continue;
      if(scc[i] != scc[G[i][j].to]) only[G[i][j].id] = true;
    }
  }
}

void dijkstra(vector<edge> G[], llint S, llint dist[])
{
  for(int i = 1; i <= n; i++) used[i] = false;
  for(int i = 1; i <= n; i++) dist[i] = inf;
  used[S] = 0, dist[S] = 0;

  priority_queue<P, vector<P>, greater<P> > Q;
  Q.push(make_pair(0LL, S));
  while(Q.size()){
    llint d = Q.top().first;
    llint v = Q.top().second;
    Q.pop();
    if(dist[v] < d)  continue;
    for(int i = 0; i < G[v].size(); i++){
      llint u = G[v][i].to;
      if(dist[u] > dist[v] + G[v][i].cost){
        dist[u] = dist[v] + G[v][i].cost;
        Q.push(make_pair(dist[u], u));
      }
    }
  }
}

int main(void)
{
  cin >> n >> m;
  llint a, b, c;
  for(int i = 1; i <= m; i++){
    cin >> a >> b >> c;
    G[a].push_back(edge(b, c, i));
    revG[b].push_back(edge(a, c, i));
  }

  dijkstra(G, 1, distS);
  dijkstra(revG, 2, distT);

  for(int i = 1; i <= n; i++){
    for(int j = 0; j < G[i].size(); j++){
      if(distS[i] + G[i][j].cost == distS[G[i][j].to]){
        path[G[i][j].id] = true;
      }
    }
  }

  for(int i = 1; i <= n; i++) used[i] = false;
  pathdfs(T);
  findBridge();

  for(int i = 1; i <= n; i++){
    for(int j = 0; j < G[i].size(); j++){
      if(!path[G[i][j].id]){
        if(distS[T] > distS[G[i][j].to] + G[i][j].cost + distT[i]) ans[G[i][j].id] = 1;
        else ans[G[i][j].id] = 0;
      }
      else{
        if(only[G[i][j].id]) ans[G[i][j].id] = -1;
        else ans[G[i][j].id] = 0;
      }
    }
  }

  for(int i = 1;i <= m; i++){
    if(ans[i] == 1) cout << "HAPPY";
    if(ans[i] == 0) cout << "SOSO";
    if(ans[i] == -1) cout << "SAD";
    cout << endl;
  }
  return 0;
}



Measured memory_bytes: 44068