#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <algorithm>
#include <bitset>
#include <complex>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <cassert>
#include <functional>

typedef long long ll;
using namespace std;

#ifndef LOCAL
#define debug(...) ;
#else
#define debug(...) cerr << __LINE__ << " : " << #__VA_ARGS__ << " = " << _tostr(__VA_ARGS__) << endl;

template<typename T>
ostream &operator<<(ostream &out, const vector<T> &v);

template<typename T1, typename T2>
ostream &operator<<(ostream &out, const pair<T1, T2> &p) {
  out << "{" << p.first << ", " << p.second << "}";
  return out;
}

template<typename T>
ostream &operator<<(ostream &out, const vector<T> &v) {
  out << '{';
  for (const T &item : v) out << item << ", ";
  out << "\b\b}";
  return out;
}

void _tostr_rec(ostringstream &oss) {
  oss << "\b\b \b";
}

template<typename Head, typename... Tail>
void _tostr_rec(ostringstream &oss, Head &&head, Tail &&... tail) {
  oss << head << ", ";
  _tostr_rec(oss, forward<Tail>(tail)...);
}

template<typename... T>
string _tostr(T &&... args) {
  ostringstream oss;
  int size = sizeof...(args);
  if (size > 1) oss << "{";
  _tostr_rec(oss, forward<T>(args)...);
  if (size > 1) oss << "}";
  return oss.str();
}
#endif

#define mod 1000000007 //1e9+7(prime number)
#define INF 1000000000 //1e9
#define LLINF 2000000000000000000LL //2e18
#define SIZE 200010

/* Bridges & 2-edge-connected Components */

struct Bridges {
  vector<pair<int, int>> edges;
  vector<vector<pair<int, int>>> G;

  vector<int> cmp, isBridge; //圧縮後に属するComponent番号, 橋であるか
  vector<pair<int, int>> cmpEdges; //圧縮後のedge

  int idx, cmpIdx;
  vector<int> ord, inSt;
  stack<int> roots, st;

  Bridges(int N): G(N, vector<pair<int, int>>()), cmp(N), idx(0), cmpIdx(0), ord(N, -1), inSt(N, 0) {}

  void add_edge(int u, int v) {
    G[u].push_back({v, edges.size()});
    G[v].push_back({u, edges.size()});
    edges.push_back({u, v});
    isBridge.push_back(false);
  }

  void dfs(int now, int eid = -1) {
    ord[now] = idx++;
    roots.push(now);
    st.push(now);
    inSt[now] = true;

    for (auto e : G[now]) {
      int to = e.first;
      if (ord[to] == -1)
        dfs(to, e.second);
      else if (eid != e.second && inSt[to])
        while (ord[roots.top()] > ord[to]) roots.pop();
    }
    if (now == roots.top()) {
      while (1) {
        int w = st.top();
        st.pop();
        inSt[w] = false;
        cmp[w] = cmpIdx;
        if (now == w) break;
      }
      if (eid != -1) isBridge[eid] = true;
      roots.pop();
      cmpIdx++;
    }
  }

  void build() {
    for (int i = 0; i < (int)ord.size(); i++)
      if (ord[i] == -1)
        dfs(i);

    for (int i = 0; i < (int)edges.size(); i++) {
      if (isBridge[i])
        cmpEdges.push_back({cmp[edges[i].first], cmp[edges[i].second]});
    }
  }
};

int a[SIZE], b[SIZE], c[SIZE];
vector<int> way[SIZE], rway[SIZE];

int main() {
  int n, m;

  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 < (int)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 < (int)rway[now].size(); i++) {
      int id = rway[now][i];
      pq.push({cur_cost - c[id], a[id]});
    }
  }

  vector<pair<int, int>> Graph;
  Bridges bridges(n);
  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 < (int)rway[now].size(); i++) {
      int id = rway[now][i];
      if (cur_cost - c[id] == cost[a[id]]) {
        pq.push({cost[a[id]], a[id]});
        bridges.add_edge(a[id], b[id]);
        pathID.push_back(id);
      }
    }
  }

  bridges.build();

  bool isBridge[SIZE] = {};

  for (int i = 0; i < (int)pathID.size(); i++) {
    int id = pathID[i];
    isBridge[id] = bridges.isBridge[i];
    debug(id, isBridge[id]);
  }

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