text: # BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
  
  from __future__ import absolute_import
  
  import numpy
  
  import awkward as ak
  
  
  def of(*arrays):
      libs = set()
      for array in arrays:
          if isinstance(array, numpy.ndarray):
              ptr_lib = "cpu"
          elif (
              type(array).__module__.startswith("cupy.")
              and type(array).__name__ == "ndarray"
          ):
              ptr_lib = "cuda"
          else:
              ptr_lib = ak.operations.convert.kernels(array)
              if ptr_lib is None:
                  pass
              elif ptr_lib == "cpu":
                  libs.add("cpu")
              elif ptr_lib == "cuda":
                  libs.add("cuda")
              else:
                  raise ValueError(
                      """structure mixes 'cpu' and 'cuda' buffers; use one of
  
      ak.to_kernels(array, 'cpu')
      ak.to_kernels(array, 'cuda')
  
  to obtain an unmixed array in main memory or the GPU(s)."""
                      + ak._util.exception_suffix(__file__)
                  )
  
      if libs == set() or libs == set(["cpu"]):
          return Numpy.instance()
      elif libs == set(["cuda"]):
          return Cupy.instance()
      else:
          raise ValueError(
              """attempting to use both a 'cpu' array and a 'cuda' array in the """
              """same operation; use one of
  
      ak.to_kernels(array, 'cpu')
      ak.to_kernels(array, 'cuda')
  
  to move one or the other to main memory or the GPU(s)."""
              + ak._util.exception_suffix(__file__)
          )
  
  
  class Singleton(object):
      _instance = None
  
      @classmethod
      def instance(cls):
          if cls._instance is None:
              cls._instance = cls()
          return cls._instance
  
  
  class NumpyMetadata(Singleton):
      bool = numpy.bool
      bool_ = numpy.bool_
      int8 = numpy.int8
      int16 = numpy.int16
      int32 = numpy.int32
      int64 = numpy.int64
      uint8 = numpy.uint8
      uint16 = numpy.uint16
      uint32 = numpy.uint32
      uint64 = numpy.uint64
      float32 = numpy.float32
      float64 = numpy.float64
      complex64 = numpy.complex64
      complex128 = numpy.complex128
      str_ = numpy.str_
      bytes_ = numpy.bytes_
  
      intp = numpy.intp
      integer = numpy.integer
      floating = numpy.floating
      number = numpy.number
      object = numpy.object
      object_ = numpy.object_
      generic = numpy.generic
  
      dtype = numpy.dtype
      ufunc = numpy.ufunc
      iinfo = numpy.iinfo
      errstate = numpy.errstate
      newaxis = numpy.newaxis
  
      ndarray = numpy.ndarray
  
      nan = numpy.nan
      inf = numpy.inf
  
  
  if hasattr(numpy, "float16"):
      NumpyMetadata.float16 = numpy.float16
  
  if hasattr(numpy, "float128"):
      NumpyMetadata.float128 = numpy.float128
  
  if hasattr(numpy, "complex256"):
      NumpyMetadata.complex256 = numpy.complex256
  
  if hasattr(numpy, "datetime64"):
      NumpyMetadata.datetime64 = numpy.datetime64
  
  if hasattr(numpy, "timedelta64"):
      NumpyMetadata.timedelta64 = numpy.timedelta64
  
  
  class NumpyLike(Singleton):
      ############################ array creation
  
      def array(self, *args, **kwargs):
          # data[, dtype=[, copy=]]
          return self._module.array(*args, **kwargs)
  
      def asarray(self, *args, **kwargs):
          # array[, dtype=]
          return self._module.asarray(*args, **kwargs)
  
      def frombuffer(self, *args, **kwargs):
          # array[, dtype=]
          return self._module.frombuffer(*args, **kwargs)
  
      def zeros(self, *args, **kwargs):
          # shape/len[, dtype=]
          return self._module.zeros(*args, **kwargs)
  
      def ones(self, *args, **kwargs):
          # shape/len[, dtype=]
          return self._module.ones(*args, **kwargs)
  
      def empty(self, *args, **kwargs):
          # shape/len[, dtype=]
          return self._module.empty(*args, **kwargs)
  
      def full(self, *args, **kwargs):
          # shape/len, value[, dtype=]
          return self._module.full(*args, **kwargs)
  
      def full_like(self, *args, **kwargs):
          # array, fill_value
          return self._module.full_like(*args, **kwargs)
  
      def zeros_like(self, *args, **kwargs):
          # array
          return self._module.zeros_like(*args, **kwargs)
  
      def ones_like(self, *args, **kwargs):
          # array
          return self._module.ones_like(*args, **kwargs)
  
      def arange(self, *args, **kwargs):
          # stop[, dtype=]
          # start, stop[, dtype=]
          # start, stop, step[, dtype=]
          return self._module.arange(*args, **kwargs)
  
      def meshgrid(self, *args, **kwargs):
          # *arrays, indexing="ij"
          return self._module.meshgrid(*args, **kwargs)
  
      ############################ testing
  
      def array_equal(self, *args, **kwargs):
          # array1, array2
          return self._module.array_equal(*args, **kwargs)
  
      def size(self, *args, **kwargs):
          # array
          return self._module.size(*args, **kwargs)
  
      def searchsorted(self, *args, **kwargs):
          # haystack, needle, side="right"
          return self._module.searchsorted(*args, **kwargs)
  
      ############################ manipulation
  
      def cumsum(self, *args, **kwargs):
          # arrays[, out=]
          return self._module.cumsum(*args, **kwargs)
  
      def nonzero(self, *args, **kwargs):
          # array
          return self._module.nonzero(*args, **kwargs)
  
      def unique(self, *args, **kwargs):
          # array
          return self._module.unique(*args, **kwargs)
  
      def concatenate(self, *args, **kwargs):
          # arrays
          return self._module.concatenate(*args, **kwargs)
  
      def repeat(self, *args, **kwargs):
          # array, int
          # array1, array2
          return self._module.repeat(*args, **kwargs)
  
      def stack(self, *args, **kwargs):
          # arrays
          return self._module.stack(*args, **kwargs)
  
      def vstack(self, *args, **kwargs):
          # arrays
          return self._module.vstack(*args, **kwargs)
  
      def packbits(self, *args, **kwargs):
          # array
          return self._module.packbits(*args, **kwargs)
  
      def unpackbits(self, *args, **kwargs):
          # array
          return self._module.unpackbits(*args, **kwargs)
  
      def atleast_1d(self, *args, **kwargs):
          # *arrays
          return self._module.atleast_1d(*args, **kwargs)
  
      def broadcast_to(self, *args, **kwargs):
          # array, shape
          return self._module.broadcast_to(*args, **kwargs)
  
      ############################ ufuncs
  
      def sqrt(self, *args, **kwargs):
          # array
          return self._module.sqrt(*args, **kwargs)
  
      def exp(self, *args, **kwargs):
          # array
          return self._module.exp(*args, **kwargs)
  
      def true_divide(self, *args, **kwargs):
          # array1, array2
          return self._module.true_divide(*args, **kwargs)
  
      def bitwise_or(self, *args, **kwargs):
          # array1, array2[, out=output]
          return self._module.bitwise_or(*args, **kwargs)
  
      def logical_and(self, *args, **kwargs):
          # array1, array2
          return self._module.logical_and(*args, **kwargs)
  
      def equal(self, *args, **kwargs):
          # array1, array2
          return self._module.equal(*args, **kwargs)
  
      def ceil(self, *args, **kwargs):
          # array
          return self._module.ceil(*args, **kwargs)
  
      ############################ reducers
  
      def all(self, *args, **kwargs):
          # array
          return self._module.all(*args, **kwargs)
  
      def any(self, *args, **kwargs):
          # array
          return self._module.any(*args, **kwargs)
  
      def count_nonzero(self, *args, **kwargs):
          # array
          return self._module.count_nonzero(*args, **kwargs)
  
      def sum(self, *args, **kwargs):
          # array
          return self._module.sum(*args, **kwargs)
  
      def prod(self, *args, **kwargs):
          # array
          return self._module.prod(*args, **kwargs)
  
      def min(self, *args, **kwargs):
          # array
          return self._module.min(*args, **kwargs)
  
      def max(self, *args, **kwargs):
          # array
          return self._module.max(*args, **kwargs)
  
      def argmin(self, *args, **kwargs):
          # array[, axis=]
          return self._module.argmin(*args, **kwargs)
  
      def argmax(self, *args, **kwargs):
          # array[, axis=]
          return self._module.argmax(*args, **kwargs)
  
  
  class Numpy(NumpyLike):
      def __init__(self):
          self._module = numpy
  
      @property
      def ma(self):
          return self._module.ma
  
      @property
      def char(self):
          return self._module.char
  
  
  class Cupy(NumpyLike):
      def __init__(self):
          try:
              import cupy
          except ImportError:
              raise ImportError(
                  """to use CUDA arrays in Python, install the 'cupy' package with:
  
      pip install cupy --upgrade
  
  or
  
      conda install cupy"""
              )
          self._module = cupy
  
      @property
      def ma(self):
          raise ValueError(
              "CUDA arrays cannot have missing values until CuPy implements "
              "numpy.ma.MaskedArray" + ak._util.exception_suffix(__file__)
          )
  
      @property
      def char(self):
          raise ValueError(
              "CUDA arrays cannot do string manipulations until CuPy implements "
              "numpy.char" + ak._util.exception_suffix(__file__)
          )
  
      @property
      def ndarray(self):
          return self._module.ndarray
  
      def asarray(self, array, dtype=None):
          if isinstance(
              array,
              (
                  ak.highlevel.Array,
                  ak.highlevel.Record,
                  ak.layout.Content,
                  ak.layout.Record,
              ),
          ):
              out = ak.operations.convert.to_cupy(array)
              if dtype is not None and out.dtype != dtype:
                  return self._module.asarray(out, dtype=dtype)
              else:
                  return out
          else:
              return self._module.asarray(array, dtype=dtype)
  
      def frombuffer(self, *args, **kwargs):
          np_array = numpy.frombuffer(*args, **kwargs)
          return self._module.array(np_array)
  
      def array_equal(self, array1, array2):
          if array1.shape != array2.shape:
              return False
          else:
              return self._module.all(array1 - array2 == 0)
  
      def repeat(self, array, repeats):
          if isinstance(repeats, self._module.ndarray):
              all_stops = self._module.cumsum(repeats)
              parents = self._module.zeros(all_stops[-1].item(), dtype=int)
              stops, stop_counts = self._module.unique(all_stops[:-1], return_counts=True)
              parents[stops] = stop_counts
              self._module.cumsum(parents, out=parents)
              return array[parents]
          else:
              return self._module.repeat(array, repeats)
  
      def all(self, array, axis=None):
          out = self._module.all(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def any(self, array, axis=None):
          out = self._module.any(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def count_nonzero(self, array, axis=None):
          out = self._module.count_nonzero(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def sum(self, array, axis=None):
          out = self._module.sum(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def prod(self, array, axis=None):
          out = self._module.prod(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def min(self, array, axis=None):
          out = self._module.min(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def max(self, array, axis=None):
          out = self._module.max(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def argmin(self, array, axis=None):
          out = self._module.argmin(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  
      def argmax(self, array, axis=None):
          out = self._module.argmax(array, axis=axis)
          if axis is None and isinstance(out, self._module.ndarray):
              return out.item()
          else:
              return out
  