from typing import List

from packaging import version
from sklearn.metrics import fa_score

import datasets
from datasets.config import PY_VERSION


if PY_VERSION < version.parse("""3.8"""):
     import importlib_metadata
else:
     import importlib.metadata as importlib_metadata


# TODO(Patrick/Anton)
_SCREAMING_SNAKE_CASE   		=			"""\
"""

_SCREAMING_SNAKE_CASE   		=			"""\
    XTREME-S is a benchmark to evaluate universal cross-lingual speech representations in many languages.
    XTREME-S covers four task families: speech recognition, classification, speech-to-text translation and retrieval.
"""

_SCREAMING_SNAKE_CASE   		=			"""
Compute XTREME-S evaluation metric associated to each XTREME-S dataset.
Args:
    predictions: list of predictions to score.
        Each translation should be tokenized into a list of tokens.
    references: list of lists of references for each translation.
        Each reference should be tokenized into a list of tokens.
    bleu_kwargs: optional dict of keywords to be passed when computing 'bleu'.
        Keywords include Dict can be one of 'smooth_method', 'smooth_value', 'force', 'lowercase',
        'tokenize', 'use_effective_order'.
    wer_kwargs: optional dict of keywords to be passed when computing 'wer' and 'cer'.
        Keywords include 'concatenate_texts'.
Returns: depending on the XTREME-S task, one or several of:
    \"accuracy\": Accuracy - for 'fleurs-lang_id', 'minds14'
    \"f1\": F1 score - for 'minds14'
    \"wer\": Word error rate - for 'mls', 'fleurs-asr', 'voxpopuli', 'babel'
    \"cer\": Character error rate - for 'mls', 'fleurs-asr', 'voxpopuli', 'babel'
    \"bleu\": BLEU score according to the `sacrebleu` metric - for 'covost2'
Examples:

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'mls')  # 'mls', 'voxpopuli', 'fleurs-asr' or 'babel'
    >>> references = [\"it is sunny here\", \"paper and pen are essentials\"]
    >>> predictions = [\"it's sunny\", \"paper pen are essential\"]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'wer': 0.56, 'cer': 0.27}

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'covost2')
    >>> references = [\"bonjour paris\", \"il est necessaire de faire du sport de temps en temp\"]
    >>> predictions = [\"bonjour paris\", \"il est important de faire du sport souvent\"]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'bleu': 31.65}

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'fleurs-lang_id')
    >>> references = [0, 1, 0, 0, 1]
    >>> predictions = [0, 1, 1, 0, 0]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'accuracy': 0.6}

    >>> xtreme_s_metric = datasets.load_metric('xtreme_s', 'minds14')
    >>> references = [0, 1, 0, 0, 1]
    >>> predictions = [0, 1, 1, 0, 0]
    >>> results = xtreme_s_metric.compute(predictions=predictions, references=references)
    >>> print({k: round(v, 2) for k, v in results.items()})
    {'f1': 0.58, 'accuracy': 0.6}
"""

_SCREAMING_SNAKE_CASE   		=			["""fleurs-asr""", """mls""", """voxpopuli""", """babel""", """covost2""", """fleurs-lang_id""", """minds14"""]
_SCREAMING_SNAKE_CASE   		=			""""""

try:
     from jiwer import transforms as tr

     _SCREAMING_SNAKE_CASE   		=			True
except ImportError:
     _SCREAMING_SNAKE_CASE   		=			False

if _jiwer_available and version.parse(importlib_metadata.version("""jiwer""")) < version.parse("""2.3.0"""):
     class SCREAMING_SNAKE_CASE_		(			tr.AbstractTransform		):







        def __init__(    self	:	str      ,      lowerCamelCase_	:	str = " "							):





         """simple docstring"""


         UpperCamelCase      =			sentence_delimiter







        def 	lowerCamelCase_  (    self	:	Optional[Any]      ,      lowerCamelCase_	:	str							):





         """simple docstring"""


         return list(lowerCamelCase_							)







        def 	lowerCamelCase_  (    self	:	int      ,      lowerCamelCase_	:	List[str]							):





         """simple docstring"""


         UpperCamelCase      =			[]
         for sent_idx, sentence in enumerate(lowerCamelCase_							):
          chars.extend(self.process_string(lowerCamelCase_							)							)
          if self.sentence_delimiter is not None and self.sentence_delimiter != "" and sent_idx < len(lowerCamelCase_							) - 1:
           chars.append(self.sentence_delimiter							)
         return chars





     _SCREAMING_SNAKE_CASE   		=			tr.Compose(
         [tr.RemoveMultipleSpaces(), tr.Strip(), SentencesToListOfCharacters(SENTENCE_DELIMITER)]
     )
elif _jiwer_available:
     _SCREAMING_SNAKE_CASE   		=			tr.Compose(
         [
             tr.RemoveMultipleSpaces(),
             tr.Strip(),
             tr.ReduceToSingleSentence(SENTENCE_DELIMITER),
             tr.ReduceToListOfListOfChars(),
         ]
     )
else:
     _SCREAMING_SNAKE_CASE   		=			None





def  lowercase(  UpperCamelCase_       ,				UpperCamelCase_					)		->  List[str]:







 '''simple docstring'''
 return float((preds == labels).mean()					)





def  lowercase(  UpperCamelCase_       ,				UpperCamelCase_					)		->  List[Any]:







 '''simple docstring'''
 return {
     "f1": float(fa_score(y_true=UpperCamelCase_       ,				y_pred=UpperCamelCase_       ,				average="""macro"""					)					),
     "accuracy": simple_accuracy(UpperCamelCase_       ,				UpperCamelCase_					),
 }





def  lowercase(  UpperCamelCase_       ,				UpperCamelCase_       ,				UpperCamelCase_="exp"       ,				UpperCamelCase_=None       ,				UpperCamelCase_=False       ,				UpperCamelCase_=False       ,				UpperCamelCase_=None       ,				UpperCamelCase_=False       ,				)		->  str:







 '''simple docstring'''
 # xtreme-s can only have one label
 UpperCamelCase      =			[[label] for label in labels]
 UpperCamelCase      =			list(UpperCamelCase_					)
 try:
  import sacrebleu as scb
 except ImportError:
  raise ValueError(
      """sacrebleu has to be installed in order to apply the bleu metric for covost2."""
      """You can install it via `pip install sacrebleu`."""					)

 if version.parse(scb.__version__					) < version.parse("""1.4.12"""					):
  raise ImportWarning(
      """To use `sacrebleu`, the module `sacrebleu>=1.4.12` is required, and the current version of `sacrebleu` doesn't match this condition.\n"""
      """You can install it with `pip install \"sacrebleu>=1.4.12\"`."""					)

 UpperCamelCase      =			len(labels[0]					)
 if any(len(UpperCamelCase_					) != references_per_prediction for refs in labels					):
  raise ValueError("""Sacrebleu requires the same number of references for each prediction"""					)
 UpperCamelCase      =			[[refs[i] for refs in labels] for i in range(UpperCamelCase_					)]
 UpperCamelCase      =			scb.corpus_bleu(
     UpperCamelCase_       ,				UpperCamelCase_       ,				smooth_method=UpperCamelCase_       ,				smooth_value=UpperCamelCase_       ,				force=UpperCamelCase_       ,				lowercase=UpperCamelCase_       ,				use_effective_order=UpperCamelCase_       ,				**({"""tokenize""": tokenize} if tokenize else {})       ,				)
 return {"bleu": output.score}





def  lowercase(  UpperCamelCase_       ,				UpperCamelCase_       ,				UpperCamelCase_       ,				UpperCamelCase_					)		->  Any:







 '''simple docstring'''
 try:
  from jiwer import compute_measures
 except ImportError:
  raise ValueError(
      f"""jiwer has to be installed in order to apply the wer metric for {config_name}."""
      """You can install it via `pip install jiwer`."""					)

 if concatenate_texts:
  UpperCamelCase      =			compute_measures(UpperCamelCase_       ,				UpperCamelCase_					)["""wer"""]

  UpperCamelCase      =			compute_measures(UpperCamelCase_       ,				UpperCamelCase_       ,				truth_transform=UpperCamelCase_       ,				hypothesis_transform=UpperCamelCase_					)["""wer"""]
  return {"wer": wer, "cer": cer}
 else:

  def compute_score(UpperCamelCase_       ,				UpperCamelCase_       ,				UpperCamelCase_="wer"					):
   UpperCamelCase      =			0
   UpperCamelCase      =			0
   for prediction, reference in zip(UpperCamelCase_       ,				UpperCamelCase_					):
    if score_type == "wer":
     UpperCamelCase      =			compute_measures(UpperCamelCase_       ,				UpperCamelCase_					)
    elif score_type == "cer":
     UpperCamelCase      =			compute_measures(
         UpperCamelCase_       ,				UpperCamelCase_       ,				truth_transform=UpperCamelCase_       ,				hypothesis_transform=UpperCamelCase_					)
    incorrect += measures["substitutions"] + measures["deletions"] + measures["insertions"]
    total += measures["substitutions"] + measures["deletions"] + measures["hits"]
   return incorrect / total

  return {"wer": compute_score(UpperCamelCase_       ,				UpperCamelCase_       ,				"""wer"""					), "cer": compute_score(UpperCamelCase_       ,				UpperCamelCase_       ,				"""cer"""					)}


@datasets.utils.file_utils.add_start_docstrings(_DESCRIPTION     ,    _KWARGS_DESCRIPTION		)
class SCREAMING_SNAKE_CASE_		(			datasets.Metric		):







   def 	lowerCamelCase_  (    self	:	Tuple							):





    """simple docstring"""


    if self.config_name not in _CONFIG_NAMES:
     raise KeyError(f"""You should supply a configuration name selected in {_CONFIG_NAMES}"""							)

    UpperCamelCase      =			"""int64""" if self.config_name in ["""fleurs-lang_id""", """minds14"""] else """string"""

    return datasets.MetricInfo(
        description=_DESCRIPTION      ,      citation=_CITATION      ,      inputs_description=_KWARGS_DESCRIPTION      ,      features=datasets.Features(
            {"""predictions""": datasets.Value(lowerCamelCase_							), """references""": datasets.Value(lowerCamelCase_							)}							)      ,      codebase_urls=[]      ,      reference_urls=[]      ,      format="""numpy"""      ,      )







   def 	lowerCamelCase_  (    self	:	Optional[Any]      ,      lowerCamelCase_	:	Dict      ,      lowerCamelCase_	:	List[Any]      ,      lowerCamelCase_	:	Optional[int]=None      ,      lowerCamelCase_	:	Optional[Any]=None							):





    """simple docstring"""


    UpperCamelCase      =			bleu_kwargs if bleu_kwargs is not None else {}
    UpperCamelCase      =			wer_kwargs if wer_kwargs is not None else {}

    if self.config_name == "fleurs-lang_id":
     return {"accuracy": simple_accuracy(lowerCamelCase_      ,      lowerCamelCase_							)}
    elif self.config_name == "minds14":
     return fa_and_simple_accuracy(lowerCamelCase_      ,      lowerCamelCase_							)
    elif self.config_name == "covost2":
     UpperCamelCase      =			bleu_kwargs.pop("""smooth_method"""      ,      """exp"""							)
     UpperCamelCase      =			bleu_kwargs.pop("""smooth_value"""      ,      lowerCamelCase_							)
     UpperCamelCase      =			bleu_kwargs.pop("""force"""      ,      lowerCamelCase_							)
     UpperCamelCase      =			bleu_kwargs.pop("""lowercase"""      ,      lowerCamelCase_							)
     UpperCamelCase      =			bleu_kwargs.pop("""tokenize"""      ,      lowerCamelCase_							)
     UpperCamelCase      =			bleu_kwargs.pop("""use_effective_order"""      ,      lowerCamelCase_							)
     return bleu(
         preds=lowerCamelCase_      ,      labels=lowerCamelCase_      ,      smooth_method=lowerCamelCase_      ,      smooth_value=lowerCamelCase_      ,      force=lowerCamelCase_      ,      lowercase=lowerCamelCase_      ,      tokenize=lowerCamelCase_      ,      use_effective_order=lowerCamelCase_      ,      )
    elif self.config_name in ["fleurs-asr", "mls", "voxpopuli", "babel"]:
     UpperCamelCase      =			wer_kwargs.pop("""concatenate_texts"""      ,      lowerCamelCase_							)
     return wer_and_cer(lowerCamelCase_      ,      lowerCamelCase_      ,      lowerCamelCase_      ,      self.config_name							)
    else:
     raise KeyError(f"""You should supply a configuration name selected in {_CONFIG_NAMES}"""							)

from __future__ import annotations





def  lowercase(  UpperCamelCase_					)		->  Dict:







 '''simple docstring'''
 global graph, reversed_graph, scc, component, visit, stack
 if visit[u]:
  return
 UpperCamelCase      =			True
 for v in graph[u]:
  dfs(UpperCamelCase_					)
 stack.append(UpperCamelCase_					)





def  lowercase(  UpperCamelCase_					)		->  Optional[int]:







 '''simple docstring'''
 global graph, reversed_graph, scc, component, visit, stack
 if visit[u]:
  return
 UpperCamelCase      =			True
 component.append(UpperCamelCase_					)
 for v in reversed_graph[u]:
  dfsa(UpperCamelCase_					)





def  lowercase(  )		->  Any:







 '''simple docstring'''
 global graph, reversed_graph, scc, component, visit, stack
 for i in range(UpperCamelCase_					):
  dfs(UpperCamelCase_					)
 UpperCamelCase      =			[False] * n
 for i in stack[::-1]:
  if visit[i]:
   continue
  UpperCamelCase      =			[]
  dfsa(UpperCamelCase_					)
  scc.append(UpperCamelCase_					)
 return scc


if __name__ == "__main__":
     # n - no of nodes, m - no of edges
     _SCREAMING_SNAKE_CASE		,  _SCREAMING_SNAKE_CASE   		=			list(map(int, input().strip().split()))

     _SCREAMING_SNAKE_CASE   		=			[[] for _ in range(n)]  # graph
     _SCREAMING_SNAKE_CASE   		=			[[] for i in range(n)]  # reversed graph
     # input graph data (edges)
     for _ in range(m):
          _SCREAMING_SNAKE_CASE		,  _SCREAMING_SNAKE_CASE   		=			list(map(int, input().strip().split()))
          graph[u].append(v)
          reversed_graph[v].append(u)

     _SCREAMING_SNAKE_CASE   		=			[]
     _SCREAMING_SNAKE_CASE   		=			[False] * n
     _SCREAMING_SNAKE_CASE   		=			[]
     _SCREAMING_SNAKE_CASE   		=			[]
     print(kosaraju())
