code: def projection(
      values: np.ndarray,
      eps: Union[int, float, np.ndarray],
      norm_p: Union[int, float, str],
  ) -> np.ndarray:
      """
      Project `values` on the L_p norm ball of size `eps`.
  
      :param values: Array of perturbations to clip.
      :param eps: Maximum norm allowed.
      :param norm_p: L_p norm to use for clipping.
              Only 1, 2 , `np.Inf` 1.1 and 1.2 supported for now.
              1.1 and 1.2 compute orthogonal projections on l1-ball, using two different algorithms
      :return: Values of `values` after projection.
      """
      # Pick a small scalar to avoid division by 0
      tol = 10e-8
      values_tmp = values.reshape((values.shape[0], -1))
  
      if norm_p == 2:
          if isinstance(eps, np.ndarray):
              raise NotImplementedError(
                  "The parameter `eps` of type `np.ndarray` is not supported to use with norm 2."
              )
  
          values_tmp = values_tmp * np.expand_dims(
              np.minimum(
                  1.0, eps / (np.linalg.norm(values_tmp, axis=1) + tol)
              ),
              axis=1,
          )
  
      elif norm_p == 1:
          if isinstance(eps, np.ndarray):
              raise NotImplementedError(
                  "The parameter `eps` of type `np.ndarray` is not supported to use with norm 1."
              )
  
          values_tmp = values_tmp * np.expand_dims(
              np.minimum(
                  1.0,
                  eps
                  / (np.linalg.norm(values_tmp, axis=1, ord=1) + tol),
              ),
              axis=1,
          )
      elif norm_p == 1.1:
          values_tmp = projection_l1_1(values_tmp, eps)
      elif norm_p == 1.2:
          values_tmp = projection_l1_2(values_tmp, eps)
  
      elif norm_p in [np.inf, "inf"]:
          if isinstance(eps, np.ndarray):
              eps = eps * np.ones_like(values)
              eps = eps.reshape([eps.shape[0], -1])  # type: ignore
  
          values_tmp = np.sign(values_tmp) * np.minimum(
              abs(values_tmp), eps
          )
  
      else:
          raise NotImplementedError(
              'Values of `norm_p` different from 1, 2, `np.inf` and "inf" are currently not '
              "supported."
          )
  
      values = values_tmp.reshape(values.shape)
  
      return values
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  import math
  import os
  import shutil
  import sys
  import tarfile
  import warnings
  import zipfile
  from functools import wraps
  from inspect import signature
  from typing import TYPE_CHECKING, Callable, List, Dict, Optional, Tuple, Union
  import numpy
  import six
  from scipy.special import gammainc
  from tqdm.auto import tqdm
  from art import config
label_desc: Use image node_id 5 for calling a global function with example usage: projection(values, eps, norm_p) and returns: values