#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;++i)
#define rep(i,n) REP(i,0,n)
#define ALL(x) x.begin(),x.end()
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define pb push_back
#define fst first
#define snd second

using namespace std;

typedef long long ll;
typedef pair<int,int> ii;

inline bool LT(double a,double b) { return !equals(a,b) && a < b; }
inline bool LTE(double a,double b) { return equals(a,b) || a < b; }

struct Edge {
  int s,t;
  ll c;
};

const bool debug = 0;

#define MAX 100001
int V,E;
vector<Edge> edges;
vector<vector<Edge>> sG, eG;
ll mini[2][MAX];

const string HA = "HAPPY";
const string SA = "SAD";
const string SO = "SOSO";

int par[MAX];
int find(int x) {
  if( x == par[x] ) return x;
  return par[x] = find(par[x]);
}
void unite(int x,int y) {
  x = find(x), y = find(y);
  if( x != y ) par[x] = y;
}

struct Data {
  int cur;
  ll v;
  bool operator < ( const Data &d ) const {
    if( v != d.v ) return v > d.v;
    return cur < d.cur;
  }
};

void dijkstra(int sp, vector<vector<Edge>> &G) {
  int flag = sp;
  rep(i,V) mini[flag][i] = LLONG_MAX;
  mini[flag][sp] = 0;
  priority_queue<Data> Q;
  Q.push((Data){sp,0});
  while( !Q.empty() ) {
    Data d = Q.top(); Q.pop();
    rep(i,(int)G[d.cur].size()) {
      Edge &e = G[d.cur][i];
      if( mini[flag][e.t] > d.v + e.c ) {
	mini[flag][e.t] = d.v + e.c;
	Q.push((Data){e.t, mini[flag][e.t]});
      }
    }
  }
}

typedef vector<ii>   vii;
typedef vector<int>   vi;
const int DFS_WHITE = -1; // unvisited
const int DFS_BLACK =  1; // visited



struct EdgeH { int src,dst,w; };
const int MAX_V = MAX; //
int V2,E2; //
vector<EdgeH> G[MAX_V]; // undirected graph
vector<int> dfs_num,dfs_low,dfs_parent,articulation_vertex;
int dfsNumberCounter, dfsRoot, rootChildren;
set<ii> ban;

#define UNVISITED -1
void articulationPointAndBridge(int u){
  dfs_low[u] = dfs_num[u] = dfsNumberCounter++;
  rep(j,(int)G[u].size()){
    EdgeH &v = G[u][j];
    if( dfs_num[v.dst] == UNVISITED ) {
      dfs_parent[v.dst] = u;
      if( u == dfsRoot ) rootChildren++;

      articulationPointAndBridge(v.dst);

      if( dfs_low[v.dst] >= dfs_num[u] ) articulation_vertex[u] = true;
      if( dfs_low[v.dst] >  dfs_num[u] ) {
        //printf("Edge (%d,%d) is a bridge\n",u,v.dst);
	ban.insert(ii(u,v.dst));
	ban.insert(ii(v.dst,u));
      }
      dfs_low[u] = min(dfs_low[u],dfs_low[v.dst]);
    } else if( v.dst != dfs_parent[u] ) {
      dfs_low[u] = min(dfs_low[u],dfs_num[v.dst]);
    }
  }
}

void calculateArticulationPointAndBridge(){
  dfsNumberCounter = 0;
  dfs_num.assign(V2,UNVISITED);
  dfs_low.assign(V2,0);
  dfs_parent.assign(V2,0);
  articulation_vertex.assign(V2,0);
  
  //printf("Bridges:\n");
  rep(i,V2) {
    if( dfs_num[i] == UNVISITED ) {
      dfsRoot = i, rootChildren = 0;
      articulationPointAndBridge(i);
      articulation_vertex[dfsRoot] = ( rootChildren > 1 );
    }
  }
  
  //printf("Articulation Points:\n");
  //rep(i,V2) if( articulation_vertex[i] ) printf("Vertex %d\n",i);
}




void constructMinGraph(ll default_mini, set<ii> &S) {
  rep(i,E) {
    Edge &e = edges[i];
    if( mini[0][e.s] == LLONG_MAX ) continue;
    if( mini[1][e.t] == LLONG_MAX ) continue;
    if( mini[0][e.s] + e.c + mini[1][e.t] == default_mini ) {
      if( debug ) {
	cout << "  ADD (" << e.s << ", " << e.t << ")" << endl;
      }
      S.insert(ii(e.s, e.t));
      G[e.s].pb((EdgeH){e.s, e.t, (int)e.c});
      G[e.t].pb((EdgeH){e.t, e.s, (int)e.c});
    }
  }
  V2 = V;
}

map<ii,int> mini_mp;
void solve() {
  dijkstra(0,sG);
  dijkstra(1,eG);
  sG.clear();
  eG.clear();

  if( debug ) {
    cout << "* min dist info -- from source" << endl;
    rep(i,V) {
      cout << "  - mini[0][" << i << "] = " << mini[0][i] << endl;
    }
    cout << "* min dist info -- from dst" << endl;
    rep(i,V) {
      cout << "  - mini[1][" << i << "] = " << mini[1][i] << endl;
    }    
  }
  
  ll default_mini = mini[0][1];
  if( debug ) {
    cout << "* default mini = " << default_mini << endl;
    cout << "* grahp construction for max flow" << endl;
  }
  set<ii> S;
  constructMinGraph(default_mini, S);
  calculateArticulationPointAndBridge();
  
  rep(i,E) {
    Edge &e = edges[i];
    if( find(0) != find(e.s) ) {
      puts(SO.c_str());
      continue;
    }
    if( mini[0][e.t] != LLONG_MAX && mini[1][e.s] != LLONG_MAX ) {
      ll cost = mini[0][e.t] + e.c + mini[1][e.s];
      if( cost <  default_mini ) { puts(HA.c_str()); continue; }
      if( cost == default_mini ) { puts(SO.c_str()); continue; }
    }

    if( mini_mp[ii(e.s,e.t)] != e.c ) {
      puts(SO.c_str());
      continue;
    }
    
    if( !S.count(ii(e.s,e.t)) ) {
      puts(SO.c_str());
      continue;
    }

    if( !ban.count(ii(e.s, e.t)) ) {
      puts(SO.c_str());
      continue;
    }
    
    puts(SA.c_str());
  }
}

int main() {
  scanf("%d%d",&V,&E);
  int a,b,c;
  sG.resize(V);
  eG.resize(V);
  rep(i,V) par[i] = i;
  rep(i,E) {
    scanf("%d%d%d",&a,&b,&c);
    --a, --b;
    if( mini_mp.count(ii(a,b)) ) {
      mini_mp[ii(a,b)] = min(mini_mp[ii(a,b)], c);
    }  else {
      mini_mp[ii(a,b)] = c;
    }
    edges.pb((Edge){a,b,c});
    sG[a].pb((Edge){a,b,c});
    eG[b].pb((Edge){b,a,c});
    unite(a,b);
  }
  solve();
  return 0;
}



Measured memory_bytes: 48660