#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
 
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
 
#include <complex>
 
#include <functional>
#include <cassert>
 
typedef long long ll;
using namespace std;
 
#define debug(x) cerr << #x << " = " << (x) << endl;
 
 
#define mod 1000000007 //1e9+7(prime number)
#define INF 1000000000 //1e9
#define LLINF 2000000000000000000LL //2e18
#define SIZE 100010

/* Bridges */

int bridges_dfs(int now, int path, vector<vector<pair<int,int> > > &way,
                vector<int> &visited, vector<int> &sum, vector<bool> &bridges_flag){
  int res_sum = 0;
  
  visited[now] = 1;

  for(int i=0;i<way[now].size();i++){
    pair<int,int> p = way[now][i];
    if(p.second == path) continue;

    if(visited[p.first] == 1){
      sum[p.first]--;
      sum[now]++;
      bridges_flag[p.second] = false;
    }else if(visited[p.first] == 0){
      int res = bridges_dfs(p.first, p.second, way, visited, sum, bridges_flag);
      res_sum += res;
      if(res > 0){
        bridges_flag[p.second] = false;
      }
    }
  }

  visited[now] = 2;
  return res_sum + sum[now];
}

//無向辺 & 多重辺考慮
vector<bool> bridges(int n, const vector<pair<int,int> > &path){
  vector<vector<pair<int,int> > >  way(n);
  vector<int> visited(n,0), sum(n,0);
  vector<bool> bridges_flag(path.size(), true);

  for(int i=0;i<path.size();i++){
    way[path[i].first].push_back({path[i].second,i});
    way[path[i].second].push_back({path[i].first,i});
  }

  bridges_dfs(0, -1, way, visited, sum, bridges_flag);

  return bridges_flag;
}

 
int main(){
  int n, m;
  int a[SIZE], b[SIZE], c[SIZE];
  vector<int> way[SIZE], rway[SIZE];
   
  scanf("%d%d",&n,&m);
 
  for(int i=0;i<m;i++){
    scanf("%d%d%d",a+i, b+i, c+i);
    a[i]--; b[i]--;
 
    way[a[i]].push_back(i);
    rway[b[i]].push_back(i);
  }
 
  //Dijkstra
  priority_queue<pair<ll,int> > pq;
  bool visited[SIZE] = {}, rvisited[SIZE];
  ll cost[SIZE], rcost[SIZE];
   
  pq.push({0,0});
 
  while(pq.size()){
    auto p = pq.top();
    pq.pop();
 
    int now = p.second;
    ll cur_cost = p.first;
 
    if(visited[now]) continue;
    visited[now] = true;
    cost[now] = -cur_cost;
 
    for(int i=0;i<way[now].size();i++){
      int id = way[now][i];
      pq.push({cur_cost - c[id], b[id]});
    }
  }
 
  pq.push({0,1});
   
  while(pq.size()){
    auto p = pq.top();
    pq.pop();
 
    int now = p.second;
    ll cur_cost = p.first;
 
    if(rvisited[now]) continue;
    rvisited[now] = true;
    rcost[now] = -cur_cost;
 
    for(int i=0;i<rway[now].size();i++){
      int id = rway[now][i];
      pq.push({cur_cost - c[id], a[id]});
    }
  }
 
  vector<pair<int,int> > Graph;
  vector<int> pathID;
  bool visited2[SIZE] = {};
 
  pq.push({cost[1], 1});
   
  while(pq.size()){
    auto p = pq.top();
    pq.pop();
 
    int now = p.second;
    ll cur_cost = p.first;
 
    if(visited2[now]) continue;
    visited2[now] = true;
     
    for(int i=0;i<rway[now].size();i++){
      int id = rway[now][i];
      if(cur_cost - c[id] == cost[a[id]]){
        pq.push({cost[a[id]], a[id]});
        Graph.push_back({a[id], b[id]});
        pathID.push_back(id);
      }
    }
  }
 
  auto res = bridges(n, Graph);
  bool isBridge[SIZE] = {};
 
  for(int i=0;i<res.size();i++){
    int id = pathID[i];
    isBridge[id] = res[i];
  }
   
  for(int i=0;i<m;i++){
    if(isBridge[i]){
      puts("SAD");
    }else if(visited[b[i]] && rvisited[a[i]] && cost[b[i]] + rcost[a[i]] + c[i] < cost[1]){
      puts("HAPPY");
    }else{
      puts("SOSO");
    }
  }
   
  return 0;
}



Measured memory_bytes: 35168