import argparse
import os
import re

import numpy as np
import PIL
import torch
from timm import create_model
from torch.optim.lr_scheduler import OneCycleLR
from torch.utils.data import DataLoader, Dataset
from torchvision.transforms import Compose, RandomResizedCrop, Resize, ToTensor

from accelerate import Accelerator





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







 '''simple docstring'''
 UpperCamelCase			  =      fname.split(os.path.sep       )[-1]
 return re.search(R"""^(.*)_\d+\.jpg$"""							,					UpperCamelCase_       ).groups()[0]
class SCREAMING_SNAKE_CASE_		(      __lowerCAmelCase		):







   def __init__(     self						:						str   ,   lowerCamelCase_						:						Tuple   ,   lowerCamelCase_						:						Dict=None   ,   lowerCamelCase_						:						List[Any]=None				):





    """simple docstring"""


    UpperCamelCase			  =      file_names
    UpperCamelCase			  =      image_transform
    UpperCamelCase			  =      label_to_id







   def __len__(     self						:						str				):





    """simple docstring"""


    return len(self.file_names				)







   def __getitem__(     self						:						Optional[Any]   ,   lowerCamelCase_						:						Optional[int]				):





    """simple docstring"""


    UpperCamelCase			  =      self.file_names[idx]
    UpperCamelCase			  =      PIL.Image.open(lowerCamelCase_				)
    UpperCamelCase			  =      raw_image.convert("""RGB"""				)
    if self.image_transform is not None:
     UpperCamelCase			  =      self.image_transform(lowerCamelCase_				)
    UpperCamelCase			  =      extract_label(lowerCamelCase_				)
    if self.label_to_id is not None:
     UpperCamelCase			  =      self.label_to_id[label]
    return {"image": image, "label": label}





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







 '''simple docstring'''
 # Initialize accelerator
 if args.with_tracking:
  UpperCamelCase			  =      Accelerator(
      cpu=args.cpu							,					mixed_precision=args.mixed_precision							,					log_with="""all"""							,					project_dir=args.project_dir       )
 else:
  UpperCamelCase			  =      Accelerator(cpu=args.cpu							,					mixed_precision=args.mixed_precision       )

 # Sample hyper-parameters for learning rate, batch size, seed and a few other HPs
 UpperCamelCase			  =      config["""lr"""]
 UpperCamelCase			  =      int(config["""num_epochs"""]       )
 UpperCamelCase			  =      int(config["""seed"""]       )
 UpperCamelCase			  =      int(config["""batch_size"""]       )
 UpperCamelCase			  =      config["""image_size"""]
 if not isinstance(UpperCamelCase_							,					(list, tuple)       ):
  UpperCamelCase			  =      (image_size, image_size)

 # Parse out whether we are saving every epoch or after a certain number of batches
 if hasattr(args.checkpointing_steps							,					"""isdigit"""       ):
  if args.checkpointing_steps == "epoch":
   UpperCamelCase			  =      args.checkpointing_steps
  elif args.checkpointing_steps.isdigit():
   UpperCamelCase			  =      int(args.checkpointing_steps       )
  else:
   raise ValueError(
       f"""Argument `checkpointing_steps` must be either a number or `epoch`. `{args.checkpointing_steps}` passed."""       )
 else:
  UpperCamelCase			  =      None

 # We need to initialize the trackers we use, and also store our configuration
 if args.with_tracking:
  UpperCamelCase			  =      os.path.split(UpperCamelCase_       )[-1].split("""."""       )[0]
  accelerator.init_trackers(UpperCamelCase_							,					UpperCamelCase_       )

 # Grab all the image filenames
 UpperCamelCase			  =      [os.path.join(args.data_dir							,					UpperCamelCase_       ) for fname in os.listdir(args.data_dir       ) if fname.endswith(""".jpg"""       )]

 # Build the label correspondences
 UpperCamelCase			  =      [extract_label(UpperCamelCase_       ) for fname in file_names]
 UpperCamelCase			  =      list(set(UpperCamelCase_       )       )
 id_to_label.sort()
 UpperCamelCase			  =      {lbl: i for i, lbl in enumerate(UpperCamelCase_       )}

 # Set the seed before splitting the data.
 np.random.seed(UpperCamelCase_       )
 torch.manual_seed(UpperCamelCase_       )
 torch.cuda.manual_seed_all(UpperCamelCase_       )

 # Split our filenames between train and validation
 UpperCamelCase			  =      np.random.permutation(len(UpperCamelCase_       )       )
 UpperCamelCase			  =      int(0.8 * len(UpperCamelCase_       )       )
 UpperCamelCase			  =      random_perm[:cut]
 UpperCamelCase			  =      random_perm[cut:]

 # For training we use a simple RandomResizedCrop
 UpperCamelCase			  =      Compose([RandomResizedCrop(UpperCamelCase_							,					scale=(0.5, 1.0)       ), ToTensor()]       )
 UpperCamelCase			  =      PetsDataset(
     [file_names[i] for i in train_split]							,					image_transform=UpperCamelCase_							,					label_to_id=UpperCamelCase_       )

 # For evaluation, we use a deterministic Resize
 UpperCamelCase			  =      Compose([Resize(UpperCamelCase_       ), ToTensor()]       )
 UpperCamelCase			  =      PetsDataset([file_names[i] for i in eval_split]							,					image_transform=UpperCamelCase_							,					label_to_id=UpperCamelCase_       )

 # Instantiate dataloaders.
 UpperCamelCase			  =      DataLoader(UpperCamelCase_							,					shuffle=UpperCamelCase_							,					batch_size=UpperCamelCase_							,					num_workers=4       )
 UpperCamelCase			  =      DataLoader(UpperCamelCase_							,					shuffle=UpperCamelCase_							,					batch_size=UpperCamelCase_							,					num_workers=4       )

 # Instantiate the model (we build the model here so that the seed also control new weights initialization)
 UpperCamelCase			  =      create_model("""resnet50d"""							,					pretrained=UpperCamelCase_							,					num_classes=len(UpperCamelCase_       )       )

 # We could avoid this line since the accelerator is set with `device_placement=True` (default value).
 # Note that if you are placing tensors on devices manually, this line absolutely needs to be before the optimizer
 # creation otherwise training will not work on TPU (`accelerate` will kindly throw an error to make us aware of that).
 UpperCamelCase			  =      model.to(accelerator.device       )

 # Freezing the base model
 for param in model.parameters():
  UpperCamelCase			  =      False
 for param in model.get_classifier().parameters():
  UpperCamelCase			  =      True

 # We normalize the batches of images to be a bit faster.
 UpperCamelCase			  =      torch.tensor(model.default_cfg["""mean"""]       )[None, :, None, None].to(accelerator.device       )
 UpperCamelCase			  =      torch.tensor(model.default_cfg["""std"""]       )[None, :, None, None].to(accelerator.device       )

 # Instantiate optimizer
 UpperCamelCase			  =      torch.optim.Adam(params=model.parameters()							,					lr=lr / 25       )

 # Instantiate learning rate scheduler
 UpperCamelCase			  =      OneCycleLR(optimizer=UpperCamelCase_							,					max_lr=UpperCamelCase_							,					epochs=UpperCamelCase_							,					steps_per_epoch=len(UpperCamelCase_       )       )

 # Prepare everything
 # There is no specific order to remember, we just need to unpack the objects in the same order we gave them to the
 # prepare method.
 UpperCamelCase  ,     UpperCamelCase  ,     UpperCamelCase  ,     UpperCamelCase  ,     UpperCamelCase			  =      accelerator.prepare(
     UpperCamelCase_							,					UpperCamelCase_							,					UpperCamelCase_							,					UpperCamelCase_							,					UpperCamelCase_       )
 # We need to keep track of how many total steps we have iterated over
 UpperCamelCase			  =      0
 # We also need to keep track of the starting epoch so files are named properly
 UpperCamelCase			  =      0

 # Potentially load in the weights and states from a previous save
 if args.resume_from_checkpoint:
  if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "":
   accelerator.print(f"""Resumed from checkpoint: {args.resume_from_checkpoint}"""       )
   accelerator.load_state(args.resume_from_checkpoint       )
   UpperCamelCase			  =      os.path.basename(args.resume_from_checkpoint       )
  else:
   # Get the most recent checkpoint
   UpperCamelCase			  =      [f.name for f in os.scandir(os.getcwd()       ) if f.is_dir()]
   dirs.sort(key=os.path.getctime       )
   UpperCamelCase			  =      dirs[-1]  # Sorts folders by date modified, most recent checkpoint is the last
  # Extract `epoch_{i}` or `step_{i}`
  UpperCamelCase			  =      os.path.splitext(UpperCamelCase_       )[0]

  if "epoch" in training_difference:
   UpperCamelCase			  =      int(training_difference.replace("""epoch_"""							,					""""""       )       ) + 1
   UpperCamelCase			  =      None
  else:
   UpperCamelCase			  =      int(training_difference.replace("""step_"""							,					""""""       )       )
   UpperCamelCase			  =      resume_step // len(UpperCamelCase_       )
   resume_step -= starting_epoch * len(UpperCamelCase_       )

    # Now we train the model
 for epoch in range(UpperCamelCase_							,					UpperCamelCase_       ):
  model.train()
  if args.with_tracking:
   UpperCamelCase			  =      0
  if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None:
   # We need to skip steps until we reach the resumed step
   UpperCamelCase			  =      accelerator.skip_first_batches(UpperCamelCase_							,					UpperCamelCase_       )
   overall_step += resume_step
  else:
   # After the first iteration though, we need to go back to the original dataloader
   UpperCamelCase			  =      train_dataloader
  for batch in active_dataloader:
   # We could avoid this line since we set the accelerator with `device_placement=True`.
   UpperCamelCase			  =      {k: v.to(accelerator.device       ) for k, v in batch.items()}
   UpperCamelCase			  =      (batch["""image"""] - mean) / std
   UpperCamelCase			  =      model(UpperCamelCase_       )
   UpperCamelCase			  =      torch.nn.functional.cross_entropy(UpperCamelCase_							,					batch["""label"""]       )
   # We keep track of the loss at each epoch
   if args.with_tracking:
    total_loss += loss.detach().float()
   accelerator.backward(UpperCamelCase_       )
   optimizer.step()
   lr_scheduler.step()
   optimizer.zero_grad()
   overall_step += 1
   if isinstance(UpperCamelCase_							,					UpperCamelCase_       ):
    UpperCamelCase			  =      f"""step_{overall_step}"""
    if overall_step % checkpointing_steps == 0:
     if args.output_dir is not None:
      UpperCamelCase			  =      os.path.join(args.output_dir							,					UpperCamelCase_       )
     accelerator.save_state(UpperCamelCase_       )
  model.eval()
  UpperCamelCase			  =      0
  UpperCamelCase			  =      0
  for step, batch in enumerate(UpperCamelCase_       ):
   # We could avoid this line since we set the accelerator with `device_placement=True`.
   UpperCamelCase			  =      {k: v.to(accelerator.device       ) for k, v in batch.items()}
   UpperCamelCase			  =      (batch["""image"""] - mean) / std
   with torch.no_grad():
    UpperCamelCase			  =      model(UpperCamelCase_       )
   UpperCamelCase			  =      outputs.argmax(dim=-1       )
   UpperCamelCase  ,     UpperCamelCase			  =      accelerator.gather_for_metrics((predictions, batch["""label"""])       )
   UpperCamelCase			  =      predictions == references
   num_elems += accurate_preds.shape[0]
   accurate += accurate_preds.long().sum()

  UpperCamelCase			  =      accurate.item() / num_elems
  # Use accelerator.print to print only on the main process.
  accelerator.print(f"""epoch {epoch}: {100 * eval_metric:.2f}"""       )
  if args.with_tracking:
   accelerator.log(
       {
           """accuracy""": 100 * eval_metric,
           """train_loss""": total_loss.item() / len(UpperCamelCase_       ),
           """epoch""": epoch,
       }							,					step=UpperCamelCase_							,					)
  if checkpointing_steps == "epoch":
   UpperCamelCase			  =      f"""epoch_{epoch}"""
   if args.output_dir is not None:
    UpperCamelCase			  =      os.path.join(args.output_dir							,					UpperCamelCase_       )
   accelerator.save_state(UpperCamelCase_       )

 if args.with_tracking:
  accelerator.end_training()





def 			lowercase(	)		->	Any:







 '''simple docstring'''
 UpperCamelCase			  =      argparse.ArgumentParser(description="""Simple example of training script."""       )
 parser.add_argument("""--data_dir"""							,					required=UpperCamelCase_							,					help="""The data folder on disk."""       )
 parser.add_argument("""--fp16"""							,					action="""store_true"""							,					help="""If passed, will use FP16 training."""       )
 parser.add_argument(
     """--mixed_precision"""							,					type=UpperCamelCase_							,					default=UpperCamelCase_							,					choices=["""no""", """fp16""", """bf16""", """fp8"""]							,					help="""Whether to use mixed precision. Choose"""
     """between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >= 1.10."""
     """and an Nvidia Ampere GPU."""							,					)
 parser.add_argument("""--cpu"""							,					action="""store_true"""							,					help="""If passed, will train on the CPU."""       )
 parser.add_argument(
     """--checkpointing_steps"""							,					type=UpperCamelCase_							,					default=UpperCamelCase_							,					help="""Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch."""							,					)
 parser.add_argument(
     """--output_dir"""							,					type=UpperCamelCase_							,					default="""."""							,					help="""Optional save directory where all checkpoint folders will be stored. Default is the current working directory."""							,					)
 parser.add_argument(
     """--resume_from_checkpoint"""							,					type=UpperCamelCase_							,					default=UpperCamelCase_							,					help="""If the training should continue from a checkpoint folder."""							,					)
 parser.add_argument(
     """--with_tracking"""							,					action="""store_true"""							,					help="""Whether to load in all available experiment trackers from the environment and use them for logging."""							,					)
 parser.add_argument(
     """--project_dir"""							,					type=UpperCamelCase_							,					default="""logs"""							,					help="""Location on where to store experiment tracking logs` and relevent project information"""							,					)
 UpperCamelCase			  =      parser.parse_args()
 UpperCamelCase			  =      {"""lr""": 3E-2, """num_epochs""": 3, """seed""": 42, """batch_size""": 64, """image_size""": 224}
 training_function(UpperCamelCase_							,					UpperCamelCase_       )


if __name__ == "__main__":
     main()

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    8_0_0,
    7_9_9,
    6_0_0,
    5_9_9,
    5_0_0,
    4_0_0,
    3_9_9,
    3_7_7,
    3_5_5,
    3_3_3,
    3_1_1,
    2_8_8,
    2_6_6,
    2_4_4,
    2_2_2,
    2_0_0,
    1_9_9,
    1_7_7,
    1_5_5,
    1_3_3,
    1_1_1,
    8_8,
    6_6,
    4_4,
    2_2,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_7_6,
    9_5_2,
    9_2_8,
    9_0_5,
    8_8_2,
    8_5_8,
    8_5_7,
    8_1_0,
    7_6_2,
    7_1_5,
    7_1_4,
    5_7_2,
    4_2_9,
    4_2_8,
    2_8_6,
    2_8_5,
    2_3_8,
    1_9_0,
    1_4_3,
    1_4_2,
    1_1_8,
    9_5,
    7_1,
    4_7,
    2_4,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_8_8,
    9_7_7,
    9_6_6,
    9_5_5,
    9_4_4,
    9_3_3,
    9_2_2,
    9_1_1,
    9_0_0,
    8_9_9,
    8_7_9,
    8_5_9,
    8_4_0,
    8_2_0,
    8_0_0,
    7_9_9,
    7_6_6,
    7_3_3,
    7_0_0,
    6_9_9,
    6_5_0,
    6_0_0,
    5_9_9,
    5_0_0,
    4_9_9,
    4_0_0,
    3_9_9,
    3_5_0,
    3_0_0,
    2_9_9,
    2_6_6,
    2_3_3,
    2_0_0,
    1_9_9,
    1_7_9,
    1_5_9,
    1_4_0,
    1_2_0,
    1_0_0,
    9_9,
    8_8,
    7_7,
    6_6,
    5_5,
    4_4,
    3_3,
    2_2,
    1_1,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_9_5,
    9_9_2,
    9_8_9,
    9_8_5,
    9_8_1,
    9_7_8,
    9_7_5,
    9_7_1,
    9_6_7,
    9_6_4,
    9_6_1,
    9_5_7,
    9_5_6,
    9_5_1,
    9_4_7,
    9_4_2,
    9_3_7,
    9_3_3,
    9_2_8,
    9_2_3,
    9_1_9,
    9_1_4,
    9_1_3,
    9_0_8,
    9_0_3,
    8_9_7,
    8_9_2,
    8_8_7,
    8_8_1,
    8_7_6,
    8_7_1,
    8_7_0,
    8_6_4,
    8_5_8,
    8_5_2,
    8_4_6,
    8_4_0,
    8_3_4,
    8_2_8,
    8_2_7,
    8_2_0,
    8_1_3,
    8_0_6,
    7_9_9,
    7_9_2,
    7_8_5,
    7_8_4,
    7_7_7,
    7_7_0,
    7_6_3,
    7_5_6,
    7_4_9,
    7_4_2,
    7_4_1,
    7_3_3,
    7_2_4,
    7_1_6,
    7_0_7,
    6_9_9,
    6_9_8,
    6_8_8,
    6_7_7,
    6_6_6,
    6_5_6,
    6_5_5,
    6_4_5,
    6_3_4,
    6_2_3,
    6_1_3,
    6_1_2,
    5_9_8,
    5_8_4,
    5_7_0,
    5_6_9,
    5_5_5,
    5_4_1,
    5_2_7,
    5_2_6,
    5_0_5,
    4_8_4,
    4_8_3,
    4_6_2,
    4_4_0,
    4_3_9,
    3_9_6,
    3_9_5,
    3_5_2,
    3_5_1,
    3_0_8,
    3_0_7,
    2_6_4,
    2_6_3,
    2_2_0,
    2_1_9,
    1_7_6,
    1_3_2,
    8_8,
    4_4,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_9_7,
    9_9_5,
    9_9_2,
    9_9_0,
    9_8_8,
    9_8_6,
    9_8_4,
    9_8_1,
    9_7_9,
    9_7_7,
    9_7_5,
    9_7_2,
    9_7_0,
    9_6_8,
    9_6_6,
    9_6_4,
    9_6_1,
    9_5_9,
    9_5_7,
    9_5_6,
    9_5_4,
    9_5_1,
    9_4_9,
    9_4_6,
    9_4_4,
    9_4_1,
    9_3_9,
    9_3_6,
    9_3_4,
    9_3_1,
    9_2_9,
    9_2_6,
    9_2_4,
    9_2_1,
    9_1_9,
    9_1_6,
    9_1_4,
    9_1_3,
    9_1_0,
    9_0_7,
    9_0_5,
    9_0_2,
    8_9_9,
    8_9_6,
    8_9_3,
    8_9_1,
    8_8_8,
    8_8_5,
    8_8_2,
    8_7_9,
    8_7_7,
    8_7_4,
    8_7_1,
    8_7_0,
    8_6_7,
    8_6_4,
    8_6_1,
    8_5_8,
    8_5_5,
    8_5_2,
    8_4_9,
    8_4_6,
    8_4_3,
    8_4_0,
    8_3_7,
    8_3_4,
    8_3_1,
    8_2_8,
    8_2_7,
    8_2_4,
    8_2_1,
    8_1_7,
    8_1_4,
    8_1_1,
    8_0_8,
    8_0_4,
    8_0_1,
    7_9_8,
    7_9_5,
    7_9_1,
    7_8_8,
    7_8_5,
    7_8_4,
    7_8_0,
    7_7_7,
    7_7_4,
    7_7_0,
    7_6_6,
    7_6_3,
    7_6_0,
    7_5_6,
    7_5_2,
    7_4_9,
    7_4_6,
    7_4_2,
    7_4_1,
    7_3_7,
    7_3_3,
    7_3_0,
    7_2_6,
    7_2_2,
    7_1_8,
    7_1_4,
    7_1_0,
    7_0_7,
    7_0_3,
    6_9_9,
    6_9_8,
    6_9_4,
    6_9_0,
    6_8_5,
    6_8_1,
    6_7_7,
    6_7_3,
    6_6_9,
    6_6_4,
    6_6_0,
    6_5_6,
    6_5_5,
    6_5_0,
    6_4_6,
    6_4_1,
    6_3_6,
    6_3_2,
    6_2_7,
    6_2_2,
    6_1_8,
    6_1_3,
    6_1_2,
    6_0_7,
    6_0_2,
    5_9_6,
    5_9_1,
    5_8_6,
    5_8_0,
    5_7_5,
    5_7_0,
    5_6_9,
    5_6_3,
    5_5_7,
    5_5_1,
    5_4_5,
    5_3_9,
    5_3_3,
    5_2_7,
    5_2_6,
    5_1_9,
    5_1_2,
    5_0_5,
    4_9_8,
    4_9_1,
    4_8_4,
    4_8_3,
    4_7_4,
    4_6_6,
    4_5_7,
    4_4_9,
    4_4_0,
    4_3_9,
    4_2_8,
    4_1_8,
    4_0_7,
    3_9_6,
    3_9_5,
    3_8_1,
    3_6_6,
    3_5_2,
    3_5_1,
    3_3_0,
    3_0_8,
    3_0_7,
    2_8_6,
    2_6_4,
    2_6_3,
    2_4_2,
    2_2_0,
    2_1_9,
    1_7_6,
    1_7_5,
    1_3_2,
    1_3_1,
    8_8,
    4_4,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_9_1,
    9_8_2,
    9_7_4,
    9_6_6,
    9_5_8,
    9_5_0,
    9_4_1,
    9_3_3,
    9_2_5,
    9_1_6,
    9_0_8,
    9_0_0,
    8_9_9,
    8_7_4,
    8_5_0,
    8_2_5,
    8_0_0,
    7_9_9,
    7_0_0,
    6_0_0,
    5_0_0,
    4_0_0,
    3_0_0,
    2_0_0,
    1_0_0,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_9_2,
    9_8_5,
    9_7_8,
    9_7_1,
    9_6_4,
    9_5_7,
    9_4_9,
    9_4_2,
    9_3_5,
    9_2_8,
    9_2_1,
    9_1_4,
    9_0_7,
    9_0_0,
    8_9_9,
    8_7_9,
    8_5_9,
    8_4_0,
    8_2_0,
    8_0_0,
    7_9_9,
    7_6_6,
    7_3_3,
    7_0_0,
    6_9_9,
    6_5_0,
    6_0_0,
    5_9_9,
    5_0_0,
    4_9_9,
    4_0_0,
    3_9_9,
    3_0_0,
    2_9_9,
    2_0_0,
    1_9_9,
    1_0_0,
    9_9,
    0,
]

_SCREAMING_SNAKE_CASE 		=      [
    9_9_9,
    9_9_6,
    9_9_2,
    9_8_9,
    9_8_5,
    9_8_2,
    9_7_9,
    9_7_5,
    9_7_2,
    9_6_8,
    9_6_5,
    9_6_1,
    9_5_8,
    9_5_5,
    9_5_1,
    9_4_8,
    9_4_4,
    9_4_1,
    9_3_8,
    9_3_4,
    9_3_1,
    9_2_7,
    9_2_4,
    9_2_0,
    9_1_7,
    9_1_4,
    9_1_0,
    9_0_7,
    9_0_3,
    9_0_0,
    8_9_9,
    8_9_1,
    8_8_4,
    8_7_6,
    8_6_9,
    8_6_1,
    8_5_3,
    8_4_6,
    8_3_8,
    8_3_0,
    8_2_3,
    8_1_5,
    8_0_8,
    8_0_0,
    7_9_9,
    7_8_8,
    7_7_7,
    7_6_6,
    7_5_5,
    7_4_4,
    7_3_3,
    7_2_2,
    7_1_1,
    7_0_0,
    6_9_9,
    6_8_8,
    6_7_7,
    6_6_6,
    6_5_5,
    6_4_4,
    6_3_3,
    6_2_2,
    6_1_1,
    6_0_0,
    5_9_9,
    5_8_5,
    5_7_1,
    5_5_7,
    5_4_2,
    5_2_8,
    5_1_4,
    5_0_0,
    4_9_9,
    4_8_5,
    4_7_1,
    4_5_7,
    4_4_2,
    4_2_8,
    4_1_4,
    4_0_0,
    3_9_9,
    3_7_9,
    3_5_9,
    3_4_0,
    3_2_0,
    3_0_0,
    2_9_9,
    2_7_9,
    2_5_9,
    2_4_0,
    2_2_0,
    2_0_0,
    1_9_9,
    1_6_6,
    1_3_3,
    1_0_0,
    9_9,
    6_6,
    3_3,
    0,
]
