import java.util.*
fun main(args: Array<String>?): Unit {
    val (n, m) = readLine()!!.trim().split(' ').map(String::toInt)
    val edges = Array(m){
        val (a, b, c) = readLine()!!.trim().split( ' ').map(String::toInt)
        Edge(it, a - 1, b - 1, c)
    }
    solve(n, m, edges)
}
fun solve(n: Int, m: Int, edges: Array<Edge>) {
    val nodes = Array(n){ arrayListOf<Edge>()}
    for (e in edges){
        nodes[e.from].add(e)
    }
    val minFromStart = LongArray(n){Long.MAX_VALUE shr 2}.also{it[0] = 0}
    val queue = PriorityQueue<Pair<Int, Long>>(compareBy(Pair<*, Long>::second)).also{it.add(Pair(0, 0))}
    while (queue.isNotEmpty()) {
        val (current, cost) = queue.poll()
        if (minFromStart[current] == cost) {
            for (e in nodes[current]) if (minFromStart[e.to] > e.cost + cost) {
                minFromStart[e.to] = e.cost + cost
                queue.add(Pair(e.to, e.cost + cost))
            }
        }
    }
    for (i in nodes.indices) nodes[i] = arrayListOf()
    for (e in edges){
        nodes[e.to].add(e)
    }
    val minToGoal = LongArray(n){Long.MAX_VALUE shr 2}.also{it[1] = 0}
    queue.add(Pair(1, 0))
    while(queue.isNotEmpty()) {
        val (current, cost) = queue.poll()
        if (minToGoal[current] == cost) {
            for (e in nodes[current]) if (minToGoal[e.from] > e.cost + cost) {
                minToGoal[e.from] = e.cost + cost
                queue.add((Pair(e.from, e.cost + cost)))
            }
        }
    }
    val isBottleNeck = markBottleNeckEdge(n, m, edges, minFromStart, minToGoal)
    for (e in edges) {
        if (isBottleNeck[e.id]) {
            println("SAD")
        }else if (minFromStart[e.to] + minToGoal[e.from] + e.cost < minFromStart[1]){
            println("HAPPY")
        }else {
            println("SOSO")
        }
    }
}
fun markBottleNeckEdge(n: Int, m: Int, edges: Array<Edge>, minCostFromStart: LongArray, minCostToGoal: LongArray): BooleanArray {
    val nodes = Array(n){arrayListOf<FlowEdge>()}
    val minCost = minCostFromStart[1]
    for (e in edges) if (minCostFromStart[e.from] + e.cost + minCostToGoal[e.to] == minCost) {
        nodes[e.from].add(FlowEdge(e.id, e.to, nodes[e.to].size, true))
        nodes[e.to].add(FlowEdge(e.id, e.from, nodes[e.from].size - 1, false))
    }
    val prevEdge = Array(n){null as FlowEdge?}
    val queue: Queue<Int> = ArrayDeque()
    queue.add(0)
    while(queue.isNotEmpty() && queue.peek() != 1) {
        for (e in nodes[queue.poll()]) if (e.hasFlow && prevEdge[e.to] == null) {
            prevEdge[e.to] = e
            queue.add(e.to)
        }
    }
    var last = 1
    while (last != 0) {
        val e = prevEdge[last]!!
        val r = nodes[e.to][e.pair]
        e.hasFlow = false
        r.hasFlow = true
        last = r.to
    }
    queue.clear()
    queue.add(0)
    prevEdge.fill(null)
    prevEdge[0] = nodes.first().first()
    val visited = ArrayDeque<Int>().also{it.add(0)}
    while(queue.isNotEmpty() && queue.peek() != 1) {
        for (e in nodes[queue.poll()]) if (e.hasFlow && prevEdge[e.to] == null) {
            prevEdge[e.to] = e
            queue.add(e.to)
            visited.add(e.to)
        }
    }
    if (queue.isNotEmpty()) {
        return BooleanArray(m){false}
    }
    val result = BooleanArray(m){false}
    var bottleNeck = -1
    for (v in visited) {
        for (e in nodes[v]) {
            if (!e.hasFlow && prevEdge[e.to] == null) {
                bottleNeck = e.id
            }
        }
    }
    while(bottleNeck != -1) {
        visited.clear()
        queue.clear()
        result[bottleNeck] = true
        prevEdge[edges[bottleNeck].to] = nodes.first().first()
        queue.add(edges[bottleNeck].to)
        visited.add(edges[bottleNeck].to)
        bottleNeck = -1
        while(queue.isNotEmpty()) {
            for (e in nodes[queue.poll()]) if (e.hasFlow && prevEdge[e.to] == null) {
                prevEdge[e.to] = e
                queue.add(e.to)
                visited.add(e.to)
            }
        }
        for (v in visited) {
            for (e in nodes[v]) {
                if (!e.hasFlow && prevEdge[e.to] == null && edges[e.id].to == e.to) {
                    bottleNeck = e.id
                }
            }
        }
    }
    return result
}
class Edge(val id: Int, val from: Int, val to: Int, val cost: Int)
class FlowEdge(val id: Int, val to: Int, val pair: Int, var hasFlow: Boolean)


Measured memory_bytes: 134868