...Once upon a time a man came to the sea. The sea was stormy and dark. The man started to call for the little mermaid to appear but alas, he only woke up Cthulhu...

Whereas on the other end of the world Pentagon is actively collecting information trying to predict the monster's behavior and preparing the secret super weapon. Due to high seismic activity and poor weather conditions the satellites haven't yet been able to make clear shots of the monster. The analysis of the first shot resulted in an undirected graph with *n* vertices and *m* edges. Now the world's best minds are about to determine whether this graph can be regarded as Cthulhu or not.

To add simplicity, let's suppose that Cthulhu looks from the space like some spherical body with tentacles attached to it. Formally, we shall regard as Cthulhu such an undirected graph that can be represented as a set of three or more rooted trees, whose roots are connected by a simple cycle.

It is guaranteed that the graph contains no multiple edges and self-loops.
The first line contains two integers — the number of vertices *n* and the number of edges *m* of the graph (1 ≤ *n* ≤ 100, 0 ≤ *m* ≤ <img align="middle" class="tex-formula" src="https://espresso.codeforces.com/b6fbba87a6e66854e5728f67cc384b75c4bcf131.png" style="max-width: 100.0%;max-height: 100.0%;"/>).

Each of the following *m* lines contains a pair of integers *x* and *y*, that show that an edge exists between vertices *x* and *y* (1 ≤ *x*, *y* ≤ *n*, *x* ≠ *y*). For each pair of vertices there will be at most one edge between them, no edge connects a vertex to itself.
6 6
6 3
6 4
5 1
2 5
1 4
5 4
FHTAGN!
6 5
5 6
4 6
3 1
5 1
1 2
NO
10 10
4 10
8 5
2 8
4 9
9 3
2 7
10 6
10 2
9 8
1 8
FHTAGN!
5 4
1 5
1 3
1 4
3 2
NO
12 12
4 12
4 7
4 9
7 2
5 12
2 1
5 9
8 6
10 12
2 5
10 9
12 3
NO
12 15
3 2
11 12
1 9
2 1
1 8
9 6
11 5
9 5
9 10
11 3
7 11
5 6
11 10
4 6
4 2
NO
12 10
1 11
3 6
5 7
4 7
6 8
11 7
3 12
11 12
7 9
12 2
NO
1 0
NO
2 1
1 2
NO
3 1
1 3
NO
3 2
1 2
2 3
NO
3 3
1 2
2 3
3 1
FHTAGN!
4 4
1 2
3 4
4 1
2 4
FHTAGN!
6 6
1 2
2 3
3 1
4 5
5 6
6 4
NO
2 0
NO
3 0
NO
100 0
NO
100 1
11 23
NO
10 10
5 7
8 1
10 3
6 4
10 6
5 3
5 6
2 6
4 3
2 10
NO
20 20
9 10
4 19
9 20
12 20
1 15
2 12
19 10
19 15
4 10
4 8
8 9
20 8
6 2
2 15
7 19
20 4
3 16
1 20
9 1
20 10
NO
30 30
17 6
16 29
16 13
16 20
29 26
17 5
27 28
24 16
7 18
24 10
1 27
12 17
27 30
6 1
3 30
5 19
18 13
16 2
30 1
5 8
14 16
26 18
7 19
5 6
23 14
6 8
23 8
18 8
18 3
5 21
NO
100 66
41 14
19 13
70 43
79 62
9 62
71 40
53 86
80 4
34 33
72 68
40 96
84 59
36 77
55 50
40 3
79 81
3 43
33 47
22 98
33 90
56 49
69 28
73 30
65 22
98 20
9 52
54 20
32 70
51 80
63 12
21 48
35 17
48 87
25 43
65 80
42 3
86 35
95 98
43 59
51 46
66 37
88 34
32 47
24 42
21 44
92 59
81 6
100 82
85 6
58 25
66 6
14 32
59 85
3 98
44 4
85 51
69 41
80 70
81 24
75 71
93 9
82 55
70 46
66 32
77 58
11 46
NO
4 4
1 2
4 3
2 3
3 1
FHTAGN!
5 5
2 3
2 4
5 4
4 1
1 2
FHTAGN!
10 10
1 10
5 9
6 2
8 9
9 1
5 4
2 8
1 3
6 3
4 1
NO
6 6
1 2
2 3
3 1
4 5
5 6
6 4
NO
4 3
1 2
2 3
3 1
NO
6 5
1 2
2 3
3 1
1 4
1 5
NO

#?		 /\_/\
#?		(= ._.)
#?		/ >WA \>AC
#// WELCOME TO MY CODING SPACE
#!  Filename: nhap.py
#?  Author: TranDucTri2003
#*  CreatedAt: 2022-05-02 12:15:18

from queue import PriorityQueue
from collections import deque,OrderedDict,defaultdict,Counter
from heapq import heappop, heappush, heapify
import sys
import time
import os
from io import BytesIO, IOBase
import math
from random import randint
from itertools import compress


MOD=10**9+7
BUFSIZE = 8192
class FastIO(IOBase):
    newlines = 0
 
    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = "x" in file.mode or "r" not in file.mode
        self.write = self.buffer.write if self.writable else None
 
    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines = 0
        return self.buffer.read()
 
    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b"\n") + (not b)
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines -= 1
        return self.buffer.readline()
 
    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            self.buffer.truncate(0), self.buffer.seek(0)
 
 
class IOWrapper(IOBase):
    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode("ascii"))
        self.read = lambda: self.buffer.read().decode("ascii")
        self.readline = lambda: self.buffer.readline().decode("ascii")
 
 
def print(*args, **kwargs):
    """Prints the values to a stream, or to sys.stdout by default."""
    sep, file = kwargs.pop("sep", " "), kwargs.pop("file", sys.stdout)
    at_start = True
    for x in args:
        if not at_start:
            file.write(sep)
        file.write(str(x))
        at_start = False
    file.write(kwargs.pop("end", "\n"))
    if kwargs.pop("flush", False):
        file.flush()
 
 
if sys.version_info[0] < 3:
    sys.stdin, sys.stdout = FastIO(sys.stdin), FastIO(sys.stdout)
else:
    sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)
input = lambda: sys.stdin.readline().rstrip("\r\n")
 
def inputf(): 
    return sys.stdin.readline().rstrip("\r\n")  # for fast input
 

 
def get_ints(): 
    return list(map(int, inputf().split()))
 
 
def get_string(): 
    return list(map(str, inputf().split()))





global maximum
 
 
def _lis(arr, n):
 
    global maximum
 
    if n == 1:
        return 1
 
    maxEndingHere = 1
 
    """Recursively get all LIS ending with arr[0], arr[1]..arr[n-2]
       IF arr[n-1] is maller than arr[n-1], and max ending with
       arr[n-1] needs to be updated, then update it"""
    for i in range(1, n):
        res = _lis(arr, i)
        if arr[i-1] < arr[n-1] and res+1 > maxEndingHere:
            maxEndingHere = res + 1

    maximum = max(maximum, maxEndingHere)
 
    return maxEndingHere
 
 
def LIS(arr):
 
    global maximum
 
    n = len(arr)

    maximum = 1
 

    _lis(arr, n)
 
    return maximum
 

def binary_search(data, elem):
    
    low = 0
    high = len(data) - 1
    while low <= high:
      
        middle = (low + high)//2
        if data[middle] == elem:
            return middle
            
        elif data[middle] > elem:

            high = middle - 1
        else:
            low = middle + 1

    return middle   

def upper_bound(my_list, key):
    large = len(my_list) -1
    small = 0

    while (small <= large):
        mid = (small + large) // 2
        if my_list[mid] < key:  #Đổi thành if my_list[mid] > key:  trong th mảng từ lớn đến bé 
            small = mid + 1
        elif my_list[mid] > key:  #Đổi thành elif my_list[mid] < key: trong th mảng từ lớn đến bé
            large = mid - 1
        else:
            return mid
    if my_list[mid]>key:
        return mid
    else:
        return mid+1   #Đổi thành mid-1 trong th mảng từ lớn đến bé
    



def lower_bound(my_list, key):
    large = len(my_list) -1
    small = 0

    while (small <= large):
        mid = (small + large) // 2
        if my_list[mid] < key:
            small = mid + 1
        elif my_list[mid] > key:
            large = mid - 1
        else:
            return mid
    if my_list[mid]<key:
        return mid
    else:
        return mid-1




def rwh_primes1v1(n):
    """ Returns  a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def rwh_primes1v2(n):
    """ Returns a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2+1)
    for i in range(1,int(n**0.5)//2+1):
        if sieve[i]:
            sieve[2*i*(i+1)::2*i+1] = bytearray((n//2-2*i*(i+1))//(2*i+1)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def roman_number(x):
    if x > 15999:
        return
    value = [5000, 4000, 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
    symbol = ["F", "MF", "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
    roman = ""
    i = 0
    while x > 0:
        div = x // value[i]
        x = x % value[i]
        while div:
            roman += symbol[i]
            div -= 1
        i += 1
    return roman

def maxSubArraySum(a,size):
     
    max_so_far = a[0]   
    max_ending_here = 0
     
    for i in range(0, size):
        max_ending_here = max_ending_here + a[i]
        if max_ending_here < 0:
            max_ending_here = 0

        elif (max_so_far < max_ending_here):   
            max_so_far = max_ending_here
             
    return max_so_far

    


def lcm(x, y):

   if x > y:
       greater = x
   else:
       greater = y

   while(True):
       if((greater % x == 0) and (greater % y == 0)):
           lcm = greater
           break
       greater += 1

   return lcm

def primeFactors(n):
    a=[]
    while n % 2 == 0:
        a.append(2)
        n = n / 2
         
    for i in range(3,int(math.sqrt(n))+1,2):
         
        while n % i== 0:
            a.append(i)
            n = n / i
             
    if n > 2:
        a.append(n)
         

def findClosest(arr, n, target):
 
    if (target <= arr[0]):
        return arr[0]
    if (target >= arr[n - 1]):
        return arr[n - 1]
 
    i = 0; j = n; mid = 0
    while (i < j):
        mid = (i + j) // 2
 
        if (arr[mid] == target):
            return arr[mid]
 
        if (target < arr[mid]) :
 
            if (mid > 0 and target > arr[mid - 1]):
                return getClosest(arr[mid - 1], arr[mid], target)
 
            j = mid
         
        else :
            if (mid < n - 1 and target < arr[mid + 1]):
                return getClosest(arr[mid], arr[mid + 1], target)
                 
            i = mid + 1
         
    return arr[mid]
 

def getClosest(val1, val2, target):
 
    if (target - val1 >= val2 - target):
        return val2
    else:
        return val1

import random
 
def is_Prime(n):
    """
    Miller-Rabin primality test.
 
    A return value of False means n is certainly not prime. A return value of
    True means n is very likely a prime.
    """
    if n!=int(n):
        return False
    n=int(n)
    if n==0 or n==1 or n==4 or n==6 or n==8 or n==9:
        return False
 
    if n==2 or n==3 or n==5 or n==7:
        return True
    s = 0
    d = n-1
    while d%2==0:
        d>>=1
        s+=1
    assert(2**s * d == n-1)
 
    def trial_composite(a):
        if pow(a, d, n) == 1:
            return False
        for i in range(s):
            if pow(a, 2**i * d, n) == n-1:
                return False
        return True  
 
    for i in range(8):
        a = random.randrange(2, n)
        if trial_composite(a):
            return False
 
    return True  

def LCS(s1 , s2):
    m, n = len(s1), len(s2)
    prev, cur = [0]*(n+1), [0]*(n+1)
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s1[i-1] == s2[j-1]:
                cur[j] = 1 + prev[j-1]
            else:
                if cur[j-1] > prev[j]:
                    cur[j] = cur[j-1]
                else:
                    cur[j] = prev[j]
        cur, prev = prev, cur
    return prev[n]

fib_matrix = [[1,1],
              [1,0]]

def matrix_square(A, mod):
    return mat_mult(A,A,mod)


def mat_mult(A,B, mod):
  if mod is not None:
    return [[(A[0][0]*B[0][0] + A[0][1]*B[1][0])%mod, (A[0][0]*B[0][1] + A[0][1]*B[1][1])%mod],
            [(A[1][0]*B[0][0] + A[1][1]*B[1][0])%mod, (A[1][0]*B[0][1] + A[1][1]*B[1][1])%mod]]


def matrix_pow(M, power, mod):
    if power <= 0:
      return M

    powers =  list(reversed([True if i=="1" else False for i in bin(power)[2:]])) #Order is 1,2,4,8,16,...

    matrices = [None for _ in powers]
    matrices[0] = M

    for i in range(1,len(powers)):
        matrices[i] = matrix_square(matrices[i-1], mod)


    result = None

    for matrix, power in zip(matrices, powers):
        if power:
            if result is None:
                result = matrix
            else:
                result = mat_mult(result, matrix, mod)

    return result
#print (matrix_pow(fib_matrix, n, 10**9+7)[0][1])


def multiply(T, M):
     
    a = (T[0][0] * M[0][0] + T[0][1] *
         M[1][0] + T[0][2] * M[2][0])            
    b = (T[0][0] * M[0][1] + T[0][1] *
         M[1][1] + T[0][2] * M[2][1])
    c = (T[0][0] * M[0][2] + T[0][1] *
         M[1][2] + T[0][2] * M[2][2])
    d = (T[1][0] * M[0][0] + T[1][1] *
         M[1][0] + T[1][2] * M[2][0])
    e = (T[1][0] * M[0][1] + T[1][1] *
         M[1][1] + T[1][2] * M[2][1])
    f = (T[1][0] * M[0][2] + T[1][1] *
         M[1][2] + T[1][2] * M[2][2])
    g = (T[2][0] * M[0][0] + T[2][1] *
         M[1][0] + T[2][2] * M[2][0])
    h = (T[2][0] * M[0][1] + T[2][1] *
         M[1][1] + T[2][2] * M[2][1])
    i = (T[2][0] * M[0][2] + T[2][1] *
         M[1][2] + T[2][2] * M[2][2])
             
    T[0][0] = a
    T[0][1] = b
    T[0][2] = c
    T[1][0] = d
    T[1][1] = e
    T[1][2] = f
    T[2][0] = g
    T[2][1] = h
    T[2][2] = i
 

def power(T, n):
 
    if (n == 0 or n == 1):
        return;
    M = [[ 1, 1, 1 ],
                [ 1, 0, 0 ],
                [ 0, 1, 0 ]]
 
    power(T, n // 2)
 
    multiply(T, T)
 
    if (n % 2):
        multiply(T, M)
 
def tribonacci(n):
     
    T = [[ 1, 1, 1 ],
        [1, 0, 0 ],
        [0, 1, 0 ]]
 
    if (n == 0 or n == 1):
        return 0
    else:
        power(T, n - 2)

    return T[0][0]

def check_colinear(x1,y1,x2,y2,x3,y3):
    doan12=math.sqrt((x1-x2)**2+(y1-y2)**2)
    doan13=math.sqrt((x1-x3)**2+(y1-y3)**2)
    doan23=math.sqrt((x2-x3)**2+(y2-y3)**2)
    if doan12==0 or doan13==0 or doan23==0:
        return False    
    else:
        cos12=(doan13**2+doan23**2-doan12**2)/(2*doan13*doan23)
        cos13=(doan12**2+doan23**2-doan13**2)/(2*doan12*doan23)
        cos23=(doan13**2+doan12**2-doan23**2)/(2*doan13*doan12)
        if cos12==-1 or cos12==1 or cos13==-1 or cos13==1 or cos23==-1 or cos23==1:
            return False
        else:
            return True
        

def check_quadrilateral(x1,y1,x2,y2,x3,y3,x4,y4):
    if check_colinear(x1,y1,x2,y2,x4,y4)==True and check_colinear(x1,y1,x2,y2,x3,y3)==True and check_colinear(x1,y1,x3,y3,x4,y4)==True and check_colinear(x2,y2,x3,y3,x4,y4)==True:
        return True
    else:
        return False


def linear_equation(x1,x2,y1,y2):
    if x1==x2: 
        return True
    if y1==y2:
        return False
    a=(y1-y2)/(x1-x2)
    b=y1-a*x1
    return a,b


def check_quadrilateral(x1,y1,x2,y2,x3,y3,x4,y4):
        check=0
        if linear_equation(x1,x2,y1,y2)==True: 
            if (x3>x1 and x4>x1) or (x3<x1 and x4<x1):
                check+=1
        elif linear_equation(x1,x2,y1,y2)==False: 
            if (y3>y1 and y4>y1) or (y3<y1 and y4<y1):
                check+=1
        else:
            a,b=linear_equation(x1,x2,y1,y2)
            if (a*x3+b-y3>0 and a*x4+b-y4>0) or (a*x3+b-y3<0 and a*x4+b-y4<0):
                check+=1
                
                
        if linear_equation(x2,x3,y2,y3)==True: 
            if (x4>x2 and x1>x2) or (x4<x2 and x1<x2):
                check+=1
        elif linear_equation(x2,x3,y2,y3)==False: 
            if (y4>y2 and y1>y2) or (y4<y2 and y1<y2):
                check+=1
        else:
            a,b=linear_equation(x2,x3,y2,y3)
            if (a*x4+b-y4>0 and a*x1+b-y1>0) or (a*x1+b-y1<0 and a*x4+b-y4<0):
                check+=1                               
                
                
        if linear_equation(x3,x4,y3,y4)==True: 
            if (x1>x3 and x2>x3) or (x1<x3 and x2<x3):
                check+=1
        elif linear_equation(x3,x4,y3,y4)==False: 
            if (y1>y3 and y2>y3) or (y1<y3 and y2<y3):
                check+=1
        else:
            a,b=linear_equation(x3,x4,y3,y4)
            if (a*x1+b-y1>0 and a*x2+b-y2>0) or (a*x1+b-y1<0 and a*x2+b-y2<0):
                check+=1               
                
                
        if linear_equation(x4,x1,y4,y1)==True: 
            if (x2>x1 and x3>x1) or (x2<x1 and x3<x1):
                check+=1
        elif linear_equation(x4,x1,y4,y1)==False: 
            if (y2>y1 and y3>y1) or (y2<y1 and y3<y1):
                check+=1
        else:
            a,b=linear_equation(x4,x1,y4,y1)
            if (a*x2+b-y2>0 and a*x3+b-y3>0) or (a*x2+b-y2<0 and a*x3+b-y3<0):
                check+=1                
        
        if check==4:
            return True
        else:
            return False

"""
def find_shortest_path(graph, start, end, path):
    path = path + [start]
    if start == end:
        return path
    if start not in graph:
        return None
    shortest = None
    for node in graph[start]:
        if node not in path:
            newpath = find_shortest_path(graph, node, end, path)
            if newpath:
                if not shortest or len(newpath) < len(shortest):
                    shortest = newpath
    return shortest
""" 

"""
def dfs(root,nodeVal,nodeConnection,visited):
    leftVal = nodeVal[root][0]
    rightVal = nodeVal[root][1]
    solution = []
    if nodeConnection[root]:
        visited.add(root)
        for i in nodeConnection[root]:
            if i not in visited:
                solution.append(dfs(i,nodeVal,nodeConnection,visited))
        leftMax = 0
        rightMax = 0
        for i in solution:
            l, r = i
            leftMax += max(abs(leftVal - l[0]) + l[1], abs(leftVal - r[0]) + r[1])
            rightMax += max(abs(rightVal - l[0]) + l[1], abs(rightVal - r[0]) + r[1])
        return ((leftVal, leftMax), (rightVal, rightMax))
    else:
        return ((leftVal, 0), (rightVal, 0))
 
"""
 
"""
def BFS(adj,src,dist,paths,n):
    visited=[False]*n
    dist[src]=0
    paths[0]=1
    q=[src]
    visited[src]=True
    while(q):
        p=q.pop(0)
        for j in adj[p]:
            if not visited[j]:
                q.append(j)
                visited[j]=True
            if dist[j]>dist[p]+1:
                dist[j] = dist[p]+1
                paths[j] = paths[p]
            elif dist[j]==dist[p]+1:
                paths[j] +=paths[p]
    return paths
 
"""
"""from collections import defaultdict

a={}
a=DefaultDict(lambda:0,a)
print(a[5])"""
# NOT MY CODE
# https://codeforces.com/contest/1324/submission/73179914
 
## PYRIVAL BOOTSTRAP
# https://github.com/cheran-senthil/PyRival/blob/master/pyrival/misc/bootstrap.py
# This decorator allows for recursion without actually doing recursion
from types import GeneratorType
 
def bootstrap(f, stack=[]):
    def wrappedfunc(*args, **kwargs):
        if stack:
            return f(*args, **kwargs)
        else:
            to = f(*args, **kwargs)
            while True:
                if type(to) is GeneratorType:
                    stack.append(to)
                    to = next(to)
                else:
                    if not stack:
                        break
                    stack.pop()
                    to = stack[-1].send(to)
            return  to
 
    return wrappedfunc


# generic memoizer
def memoize(func):
    '''Memoizing decorator that checks whether the wrapped function 
    has been previously run with the current argument value. 
    If it has then that value is retrieved and offered instead 
    of rerunning the function'''
    memos = {}
    def wrapper(x):
        if x not in memos:
            memos[x] = func(x)
        return memos[x]
    return wrapper
 


from collections import defaultdict
from heapq import heappop, heappush

class Graph:
    INF=10**9
    #Searching Algorithms: DFS, BFS
    def __init__(self):
        self.graph = defaultdict(list)
        
    # Algorithms for finding the shortest path: Bellman Ford
    # def __init__(self, vertices):
    #     self.V = vertices # No. of vertices
    #     self.graph = []

    # Algorithms for finding the shortest path: Dijsktra
    # def __init__(self,vertices):
    #     self.distance=[self.INF]*vertices
    #     self.edges=defaultdict(dict)

    # Algorithms for finding the shortest path: Floyd Warshall    
    # def __init__(self,vertices):
    #     self.distance=defaultdict(lambda:defaultdict(lambda:self.INF))
    #     self.edges=defaultdict(lambda:defaultdict(lambda:self.INF))
    #     for i in range(1,vertices+1):
    #         self.distance[i][i]=0
    #         self.edges[i][i]=0
    
    #Minimum Spanning Trees: Kruskal's Algorithm
    # def __init__(self, vertices):
    #     self.vertices=vertices
    #     self.graph=[]
    

        
    #DFS,BFS
    def addEdge(self,u,v):
        self.graph[u].append(v)
        self.graph[v].append(u)
        
    #Bellman Ford
    # def addEdge(self, u, v, w):
    #     self.graph.append([u, v, w])
    
    #Dijsktra
    # def addEdge(self,u,v,w):
    #     self.edges[u][v]=w
        
    #Floyd Warshall
    # def addEdge(self,u,v,w):
    #     self.edges[u][v]=w
    
    #:Kruskal's Algorithm finding MST
    # def addEdge(self,node1,node2,weight):
    #     self.graph.append([node1,node2,weight])
                    
    # 1.Handling A Disconnected Graph: 
    def DFSUtil(self, vertex,visited,path):
        stack=[vertex]
        while len(stack):
            u=stack.pop()
            if visited[u]==0:
                path.append(u)
                visited[u]=1
                for neighbour in self.graph[u]:
                    stack.append(neighbour)
                    
    # def DFS(self,numVertex):
    #     visited=defaultdict(lambda:0)
    #     path=[]
    #     for vertex in range(1,numVertex+1):
    #         if visited[vertex]==0:
    #             self.DFSUtil(vertex,visited,path)        
    #     return path
                
    # 2.DFS from a vertex 
    def DFS(self,vertex):
        path=[]
        stack=[vertex]
        visited=defaultdict(lambda:0)
        ancestor=defaultdict(lambda:0)
        numCycle=0
        while len(stack):
            u=stack.pop()
            if visited[u]==0:
                path.append(u)
                visited[u]=1
                for neighbour in self.graph[u]:
                    ancestor[neighbour]=u
                    if visited[neighbour]==1: 
                        if ancestor[u]!=neighbour:
                            numCycle+=1
                    else:
                        stack.append(neighbour)
        return numCycle

                
    # 1. Handling A Disconnected Graph:
    def BFS(self,numVertex):
        visited=defaultdict(lambda:0)
        queue=[]
        for i in range(1,numVertex+1):
            if visited[i]==0:
                queue.append(i)
                visited[i]=1
                while queue:
                    u=queue.pop(0)
                    print(u,end=' ')
                    for v in self.graph[u]:
                        if visited[v]==0:
                            queue.append(v)
                            visited[v]=1
                            
    # 2. BFS from a vertex
    # def BFS(self,vertex):
    #     visited = defaultdict(lambda:0)
    #     queue=[vertex]
    #     visited[vertex]=1
    #     path=[]
    #     while queue:
    #         u=queue.pop(0)
    #         path.append(u)
    #         for v in self.graph[u]:
    #             if visited[v]==0:
    #                 queue.append(v)
    #                 visited[v]=1
    #     return path
        
    #DFSUtil in case finding Connected components
    def DFSUtilConnect(self, temp, v, visited):
        visited[v] = 1
        # Store the vertex to list
        temp.append(v)
        for neighbour in self.graph[v]:
            if visited[neighbour]==0:
                # Update the list
                temp = self.DFSUtilConnect(temp, neighbour, visited)
        return temp
    
          
    def connectedComponentsDFS(self,numVertex):
        path=[]
        visited=defaultdict(lambda:0)
        for vertex in range(1,numVertex+1):
            if visited[vertex] == 0:
                temp = []
                path.append(self.DFSUtilConnect(temp, vertex, visited))
        return path
      
    def connectedComponentsBFS(self,numVertex):
        visited=defaultdict(lambda:0)
        stack=[]
        path=[]
        for i in range(1,numVertex+1):
            if visited[i]==0:
                stack.append(i)
                visited[i]=1
                temp=[]
                while stack:
                    u=stack.pop()
                    temp.append(u)
                    for v in self.graph[u]:
                        if visited[v]==0:
                            stack.append(v)
                            visited[v]=1
                path.append(temp)
        return path
                  
    

    def BellmanFord(self, S):
        d=defaultdict(lambda:self.INF)
        trace=defaultdict(lambda:-1)
        d[S]=0
 
        for _ in range(self.V - 1):
            for u, v, w in self.graph:
                if d[u]!=self.INF and d[v]>d[u]+w:
                    d[v]=d[u]+w
                    trace[v]=u

        #Trả về đường đi từ đỉnh S đến u nào đó
        #return trace
        # if u!=S and trace[u]==-1:
        #     return -1 #Không có đường đi
        # else:
        #     path=[]
        #     while u!=-1:
        #         path.append(u)
        #         u=trace[u]
        #     path.reverse()
        #     return path

        #Nhận biết đường đi âm vô cực trong trường hợp có chu trình âm:
        
        # Chạy thuật toán Bellman-Ford thêm một lần nữa với N vòng lặp, những đỉnh nào vẫn còn tối ưu được ở lần chạy thứ hai
        # sẽ tối ưu được mãi mãi, và đó là các đỉnh không tồn tại đường đi ngắn nhất.
        
        for _ in range(self.V):
            for u, v, w in self.graph:
                if d[u]!=self.INF and d[v]>d[u]+w:
                    d[v]=-self.INF  # vẫn còn tối ưu được --> âm vô cực
                    trace[v]=u
        return d
    
    def Dijsktra(self,S):
        self.distance[S]=0
        queue=[(0,S)]
        trace=defaultdict(lambda:-1)
        while queue:
            cost,vertex=heappop(queue)
            for neighbour, weight in self.edges[vertex].items():
                if cost+weight<self.distance[neighbour]:
                    self.distance[neighbour]=cost+weight
                    heappush(queue, (cost + weight, neighbour))
                    trace[neighbour]=vertex
        #Trả về đường đi từ đỉnh S đến u nào đó
        #return trace
        # if u!=S and trace[u]==-1:
        #     return -1 #Không có đường đi
        # else:
        #     path=[]
        #     while u!=-1:
        #         path.append(u)
        #         u=trace[u]
        #     path.reverse()
        #     return path 
        return self.distance
    
    def FloydWarshall(self,vertices):
        for k in range(1,vertices+1):
            for i in range(1,vertices+1):
                for j in range(1,vertices+1):
                   self.distance[i][j]=min(self.distance[i][j],self.edges[i][k]+self.edges[k][j])
        return self.distance


    #Finds the root of a subtree containing node 'i'
    def findSubtree(self,parent,i):
        if parent[i]==i:
            return i
        else:
            return self.findSubtree(parent,parent[i])
    #Connects subtrees containing node 'x' and 'y'
    def connectSubtree(self,parent,subtreeSize,x,y):
        xroot=self.findSubtree(parent,x)
        yroot=self.findSubtree(parent,y)
        if subtreeSize[xroot]<subtreeSize[yroot]:
            parent[xroot]=yroot
        elif subtreeSize[xroot]>subtreeSize[yroot]:
            parent[yroot]=xroot
        else:
            parent[yroot]=xroot
            subtreeSize[xroot]+=1
        
    def Kruskal(self):
        #Resulting tree
        res=[]
        
        #Iterator
        i=0
        #Number of edges in MST
        e=0

        #Sort edges by their weight
        self.graph=sorted(self.graph,key=lambda item: item[2])

        #Auxiliary arrays
        parent=[]
        subtreeSize=[]
        
        #initialize parent and subtreeSize arrays
        
        for node in range(self.vertices):
            parent.append(node)
            subtreeSize.append(0)
        
        #Number of edges in a MST is (node-1)
        
        while e<self.vertices-1:
            node1,node2,weight=self.graph[i]
            i+=1

            x=self.findSubtree(parent,node1)
            y=self.findSubtree(parent,node2)
            
            if x!=y:
                e+=1
                res.append([node1,node2,weight])
                self.connectSubtree(parent,subtreeSize,node1,node2)
        return res


    def isEulerian(self):
        path=self.connectedComponentsBFS(self.v)
        for compo in path:
            odd=0
            for vertex in compo:
                if self.degree[vertex]%2==1:
                    odd+=1

        if odd == 0:
            return 2   # graph has a Euler cycle
        elif odd == 2:
            return 1  # graph has a Euler path
        elif odd > 2:
            return 0   # graph is not Euleria
            # '''If odd count is 2, then semi-eulerian.
            # If odd count is 0, then eulerian
            # If count is more than 2, then graph is not Eulerian
            # Note that odd count can never be 1 for undirected graph'''

n,m=list(map(int,input().split()))
g=Graph()
for i in range(m):
    u,v=list(map(int,input().split()))
    g.addEdge(u,v)

com=g.connectedComponentsDFS(n)
if len(com)==1 and g.DFS(1)==1:
    print("FHTAGN!")
else:
    print("NO")

#Nếu đi đến một đỉnh mà đỉnh đó đã được thăm nhưng tổ tiên của nó không phải là đỉnh đó nghĩa là có chu trình