#include <bits/stdc++.h>

using namespace std;

namespace {
    template<typename K, typename V>
    ostream& operator<<(ostream& os, const pair<K, V>& p) {
        return os << "(" << p.first << "," << p.second << ")";
    }
    typedef long long ll;
    const ll INF = 1LL << 56;
    int N, M;

    struct Edge {
        int from, to; ll cost;
        Edge(int from, int to, ll cost) : from(from), to(to), cost(cost) {}
        bool operator<(const Edge& e) const {
            if (from == e.from) {
                return to == e.to ? cost < e.cost : to < e.to;
            } else {
                return from < e.from;
            }
        }
        bool operator==(const Edge& e) {
            return to == e.to and from == e.from and cost == e.cost;
        }
    };
    ostream& operator<<(ostream& os, const Edge& e) {
        return os << "Edge(" << e.from << "," << e.to << "," << e.cost << ")";
    }
    /** output whole vector. ex) vector<int>{1, 2, 3} -> '1 2 3'. */
    template<typename T>
    ostream& operator<<(ostream& os, const vector<T>& xs) {
       if (xs.empty()) return os;
       os << xs[0];
       for (auto i = 1; i < xs.size(); i++) os << ' ' << xs[i];
       return os;
    }
    vector<vector<Edge>> G, RG;
    vector<Edge> es;
    map<Edge, int> X;

    vector<pair<int, int>> findBridges(const vector<vector<Edge>>& G) {
        int V = N;
        vector<int> dfs_order(V, -1);
        vector<int> lowlink(V, 0);
        int c = 0;
        vector<pair<int, int>> bridges;
        function<void(int, int)> dfs = [&](int v, int prev) {
            dfs_order[v] = c++;
            lowlink[v] = dfs_order[v];
            for (auto& e : G[v]) {
                auto next = e.to;
                if (next == prev) continue;
                if (dfs_order[next] >= 0) {
                    // already visited. this 'e' is backedge.
                    lowlink[v] = min(lowlink[v], dfs_order[next]);
                } else {
                    dfs(next, v);
                    lowlink[v] = min(lowlink[v], lowlink[next]);
                }
                if (dfs_order[v] < lowlink[next]) {
                    auto l = min(v, next);
                    auto g = max(v, next);
                    bridges.emplace_back(l, g);
                }
            }
        };
        dfs(0, -1);
        return bridges;
    }

    void input() {
        cin >> N >> M;
        G.resize(N);
        RG.resize(N);
        for (int i = 0; i < M; i++) {
            int a, b; ll c;
            cin >> a >> b >> c;
            a--; b--;
            Edge e(a, b, c);
            if (X.count(e)) {
                X[e]++;
            } else {
                G[a].emplace_back(a, b, c);
                RG[b].emplace_back(b, a, c);
                X[e] = 1;
            }
            es.emplace_back(a, b, c);
        }
    }

    struct S {
        int v; ll cost;
        S(int v, ll cost) : v(v), cost(cost) {}
        bool operator<(const S& s) const {
            return cost > s.cost;
        }
    };

    void dijkstra(const vector<vector<Edge>>& G, int start, vector<ll>& D, vector<vector<Edge>>& prev) {
        priority_queue<S> PQ;
        PQ.emplace(start, 0);
        D[start] = 0;
        while (not PQ.empty()) {
            auto cur = PQ.top(); PQ.pop();
            for (auto& e : G[cur.v]) {
                auto next = e.to;
                auto ncost = D[cur.v] + e.cost;
                if (D[next] > ncost) {
                    prev[next].clear();
                    prev[next].push_back(e);
                    D[next] = ncost;
                    PQ.emplace(next, ncost);
                } else if (D[next] == ncost) {
                    prev[next].push_back(e);
                }
            }
        }
    }

    void solve() {
        vector<ll> D(N, INF);
        vector<ll> RD(N, INF);
        vector<vector<Edge>> prev(N, vector<Edge>());
        vector<vector<Edge>> rprev(N, vector<Edge>());
        dijkstra(G, 0, D, prev);
        dijkstra(RG, 1, RD, rprev);

        vector<vector<Edge>> shortest_paths(N, vector<Edge>());
        vector<bool> used(N, false);
        function<void(int)> dfs = [&](int v) {
            if (prev[v].empty()) {
                //assert(v == 0);
                return;
            }
            if (used[v]) return;
            used[v] = true;
            for (auto e : prev[v]) {
                shortest_paths[e.from].push_back(e);
                shortest_paths[e.to].emplace_back(e.to, e.from, -1);
                dfs(e.from);
            }
        };
        dfs(1);
        //cout << shortest_paths << endl;

        auto _bridges = findBridges(shortest_paths);
        //cout << _bridges << endl;
        set<pair<int, int>> bridges;
        for (auto b : _bridges) { bridges.insert(b); }

        for (int i = 0; i < M; i++) {
            auto e = es[i];
            if (D[e.from] + e.cost + RD[e.to] == D[1]) {
                if (
                    (bridges.count(make_pair(e.from, e.to)) 
                     or bridges.count(make_pair(e.to, e.from)))
                     and X[e] <= 1) {
                    cout << "SAD" << endl;
                } else {
                    cout << "SOSO" << endl;
                }
            } else {
                auto ncost = D[e.to] + e.cost + RD[e.from];
                if (ncost < D[1]) {
                    cout << "HAPPY" << endl;
                } else {
                    cout << "SOSO" << endl;
                }
            }
        }
    }
}

int main() {
    input(); solve();
    return 0;
}

Measured memory_bytes: 57528