#include <bits/stdc++.h>
using namespace std;
struct Edge {
  int from, to, next;
} edge[2 * 100005];
int head[105], edgenum;
int Low[105], DFN[105], Stack[105];
int Index, top;
int Belong[105], block;
bool Instack[105];
int bridge;
vector<int> bcc[105];
void addedge(int u, int v) {
  Edge E = {u, v, head[u]};
  edge[edgenum] = E;
  head[u] = edgenum++;
  Edge E2 = {v, u, head[v]};
  edge[edgenum] = E2;
  head[v] = edgenum++;
}
void Tarjan(int u, int pre) {
  int v;
  Low[u] = DFN[u] = ++Index;
  Stack[top++] = u;
  Instack[u] = true;
  for (int i = head[u]; ~i; i = edge[i].next) {
    v = edge[i].to;
    if (v == pre) continue;
    if (!DFN[v]) {
      Tarjan(v, u);
      if (Low[u] > Low[v]) Low[u] = Low[v];
      if (Low[v] > Low[u]) bridge++;
    } else if (Instack[v] && Low[u] > DFN[v])
      Low[u] = DFN[v];
  }
  if (Low[u] == DFN[u]) {
    block++;
    bcc[block].clear();
    do {
      v = Stack[--top];
      Instack[v] = false;
      Belong[v] = block;
      bcc[block].push_back(v);
    } while (v != u);
  }
}
void work(int l, int r) {
  memset(DFN, 0, sizeof(DFN));
  memset(Instack, false, sizeof(Instack));
  Index = top = block = bridge = 0;
  for (int i = l; i <= r; i++)
    if (!DFN[i]) Tarjan(i, i);
}
vector<int> G[105];
void suodian() {
  for (int i = 1; i <= block; i++) G[i].clear();
  for (int i = 0; i < edgenum; i += 2) {
    int u = Belong[edge[i].from], v = Belong[edge[i].to];
    if (u == v) continue;
    G[u].push_back(v), G[v].push_back(u);
  }
}
void init() {
  edgenum = 0;
  memset(head, -1, sizeof(head));
}
int n, m, vis[105], siz[105], f[105];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
void Union(int x, int y) {
  int fx = find(x), fy = find(y);
  if (fx == fy) return;
  if (fx > fy) swap(fx, fy);
  f[fx] = fy;
}
bool dfs(int u) {
  vis[u] = 1;
  bool ok = true;
  for (int i = 0; i < G[u].size(); i++) {
    int v = G[u][i];
    if (vis[v]) continue;
    if (bcc[v].size() > 1) ok = false;
    if (dfs(v) == false) ok = false;
  }
  return ok;
}
set<int> myset;
bool solve() {
  int i, u, v;
  init();
  for (i = 1; i <= n; i++) f[i] = i;
  while (m--) {
    scanf("%d %d", &u, &v);
    addedge(u, v);
    Union(u, v);
  }
  myset.clear();
  for (i = 1; i <= n; i++) myset.insert(find(i));
  if (myset.size() > 1) return false;
  work(1, n);
  suodian();
  memset(vis, 0, sizeof vis);
  memset(siz, 0, sizeof siz);
  for (i = 0; i < edgenum; i += 2)
    siz[Belong[edge[i].from]] += (Belong[edge[i].from] == Belong[edge[i].to]);
  for (i = 1; i <= block; i++)
    if (!vis[i] && bcc[i].size() > 1 && bcc[i].size() == siz[i])
      if (dfs(i)) return true;
  return false;
}
int main() {
  while (~scanf("%d %d", &n, &m)) solve() ? puts("FHTAGN!") : puts("NO");
  return 0;
}
