
"""simple docstring"""




import gc
import random
import unittest

import numpy as np
import torch
from transformers import (
    CLIPImageProcessor,
    CLIPTextConfig,
    CLIPTextModelWithProjection,
    CLIPTokenizer,
    CLIPVisionConfig,
    CLIPVisionModelWithProjection,
)

from diffusers import (
    DiffusionPipeline,
    UnCLIPImageVariationPipeline,
    UnCLIPScheduler,
    UNetaDConditionModel,
    UNetaDModel,
)
from diffusers.pipelines.unclip.text_proj import UnCLIPTextProjModel
from diffusers.utils import floats_tensor, load_numpy, slow, torch_device
from diffusers.utils.testing_utils import enable_full_determinism, load_image, require_torch_gpu, skip_mps

from ..pipeline_params import IMAGE_VARIATION_BATCH_PARAMS, IMAGE_VARIATION_PARAMS
from ..test_pipelines_common import PipelineTesterMixin, assert_mean_pixel_difference


enable_full_determinism()



class 	lowerCAmelCase_						(__a ,					unittest.TestCase  ):


				"""simple docstring"""



				__UpperCamelCase      :						Any					       =   UnCLIPImageVariationPipeline
				__UpperCamelCase      :						List[str]					       =   IMAGE_VARIATION_PARAMS - {'''height''', '''width''', '''guidance_scale'''}
				__UpperCamelCase      :						Optional[int]					       =   IMAGE_VARIATION_BATCH_PARAMS

				__UpperCamelCase      :						Any					       =   [
				    '''generator''',
				    '''return_dict''',
				    '''decoder_num_inference_steps''',
				    '''super_res_num_inference_steps''',
				]
				__UpperCamelCase      :						List[str]					       =   False



				@property
				def 	__magic_name__    (self    )					->		int:



											"""simple docstring"""




											return 32



				@property
				def 	__magic_name__    (self    )					->		Tuple:



											"""simple docstring"""




											return 32



				@property
				def 	__magic_name__    (self    )					->		int:



											"""simple docstring"""




											return self.time_input_dim



				@property
				def 	__magic_name__    (self    )					->		int:



											"""simple docstring"""




											return self.time_input_dim * 4



				@property
				def 	__magic_name__    (self    )					->		Dict:



											"""simple docstring"""




											return 1_00



				@property
				def 	__magic_name__    (self    )					->		Dict:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Any           =   CLIPTokenizer.from_pretrained("""hf-internal-testing/tiny-random-clip"""    )
											return tokenizer



				@property
				def 	__magic_name__    (self    )					->		Dict:



											"""simple docstring"""




											torch.manual_seed(0    )
											SCREAMING_SNAKE_CASE__						:       int           =   CLIPTextConfig(
											    bos_token_id=0   ,       eos_token_id=2   ,       hidden_size=self.text_embedder_hidden_size   ,       projection_dim=self.text_embedder_hidden_size   ,       intermediate_size=37   ,       layer_norm_eps=1E-05   ,       num_attention_heads=4   ,       num_hidden_layers=5   ,       pad_token_id=1   ,       vocab_size=10_00   ,       )
											return CLIPTextModelWithProjection(_A    )



				@property
				def 	__magic_name__    (self    )					->		int:



											"""simple docstring"""




											torch.manual_seed(0    )
											SCREAMING_SNAKE_CASE__						:       Any           =   CLIPVisionConfig(
											    hidden_size=self.text_embedder_hidden_size   ,       projection_dim=self.text_embedder_hidden_size   ,       num_hidden_layers=5   ,       num_attention_heads=4   ,       image_size=32   ,       intermediate_size=37   ,       patch_size=1   ,       )
											return CLIPVisionModelWithProjection(_A    )



				@property
				def 	__magic_name__    (self    )					->		Union[str, Any]:



											"""simple docstring"""




											torch.manual_seed(0    )

											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   {
											    '''clip_embeddings_dim''': self.text_embedder_hidden_size,
											    '''time_embed_dim''': self.time_embed_dim,
											    '''cross_attention_dim''': self.cross_attention_dim,
											}

											SCREAMING_SNAKE_CASE__						:       Any           =   UnCLIPTextProjModel(**_A    )
											return model



				@property
				def 	__magic_name__    (self    )					->		List[Any]:



											"""simple docstring"""




											torch.manual_seed(0    )

											SCREAMING_SNAKE_CASE__						:       str           =   {
											    '''sample_size''': 32,
											    # RGB in channels
											    '''in_channels''': 3,
											    # Out channels is double in channels because predicts mean and variance
											    '''out_channels''': 6,
											    '''down_block_types''': ('''ResnetDownsampleBlock2D''', '''SimpleCrossAttnDownBlock2D'''),
											    '''up_block_types''': ('''SimpleCrossAttnUpBlock2D''', '''ResnetUpsampleBlock2D'''),
											    '''mid_block_type''': '''UNetMidBlock2DSimpleCrossAttn''',
											    '''block_out_channels''': (self.block_out_channels_a, self.block_out_channels_a * 2),
											    '''layers_per_block''': 1,
											    '''cross_attention_dim''': self.cross_attention_dim,
											    '''attention_head_dim''': 4,
											    '''resnet_time_scale_shift''': '''scale_shift''',
											    '''class_embed_type''': '''identity''',
											}

											SCREAMING_SNAKE_CASE__						:       int           =   UNetaDConditionModel(**_A    )
											return model



				@property
				def 	__magic_name__    (self    )					->		Optional[int]:



											"""simple docstring"""




											return {
											    "sample_size": 64,
											    "layers_per_block": 1,
											    "down_block_types": ("ResnetDownsampleBlock2D", "ResnetDownsampleBlock2D"),
											    "up_block_types": ("ResnetUpsampleBlock2D", "ResnetUpsampleBlock2D"),
											    "block_out_channels": (self.block_out_channels_a, self.block_out_channels_a * 2),
											    "in_channels": 6,
											    "out_channels": 3,
											}



				@property
				def 	__magic_name__    (self    )					->		List[str]:



											"""simple docstring"""




											torch.manual_seed(0    )

											SCREAMING_SNAKE_CASE__						:       Tuple           =   UNetaDModel(**self.dummy_super_res_kwargs    )
											return model



				@property
				def 	__magic_name__    (self    )					->		List[str]:



											"""simple docstring"""




											torch.manual_seed(1    )

											SCREAMING_SNAKE_CASE__						:       Dict           =   UNetaDModel(**self.dummy_super_res_kwargs    )
											return model



				def 	__magic_name__    (self    )					->		Tuple:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Any           =   self.dummy_decoder
											SCREAMING_SNAKE_CASE__						:       Any           =   self.dummy_text_proj
											SCREAMING_SNAKE_CASE__						:       int           =   self.dummy_text_encoder
											SCREAMING_SNAKE_CASE__						:       Tuple           =   self.dummy_tokenizer
											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   self.dummy_super_res_first
											SCREAMING_SNAKE_CASE__						:       Dict           =   self.dummy_super_res_last

											SCREAMING_SNAKE_CASE__						:       int           =   UnCLIPScheduler(
											    variance_type="""learned_range"""   ,       prediction_type="""epsilon"""   ,       num_train_timesteps=10_00   ,       )

											SCREAMING_SNAKE_CASE__						:       Union[str, Any]           =   UnCLIPScheduler(
											    variance_type="""fixed_small_log"""   ,       prediction_type="""epsilon"""   ,       num_train_timesteps=10_00   ,       )

											SCREAMING_SNAKE_CASE__						:       List[str]           =   CLIPImageProcessor(crop_size=32   ,       size=32    )

											SCREAMING_SNAKE_CASE__						:       Tuple           =   self.dummy_image_encoder

											return {
											    "decoder": decoder,
											    "text_encoder": text_encoder,
											    "tokenizer": tokenizer,
											    "text_proj": text_proj,
											    "feature_extractor": feature_extractor,
											    "image_encoder": image_encoder,
											    "super_res_first": super_res_first,
											    "super_res_last": super_res_last,
											    "decoder_scheduler": decoder_scheduler,
											    "super_res_scheduler": super_res_scheduler,
											}



				def 	__magic_name__    (self   ,       SCREAMING_SNAKE_CASE__   ,       SCREAMING_SNAKE_CASE__=0   ,       SCREAMING_SNAKE_CASE__=True    )					->		Optional[Any]:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       List[Any]           =   floats_tensor((1, 3, 32, 32)   ,       rng=random.Random(_A    )    ).to(_A    )
											if str(_A    ).startswith("""mps"""    ):
																		SCREAMING_SNAKE_CASE__						:       int           =   torch.manual_seed(_A    )
											else:
																		SCREAMING_SNAKE_CASE__						:       List[str]           =   torch.Generator(device=_A    ).manual_seed(_A    )

											if pil_image:
																		SCREAMING_SNAKE_CASE__						:       Dict           =   input_image * 0.5 + 0.5
																		SCREAMING_SNAKE_CASE__						:       Optional[int]           =   input_image.clamp(0   ,       1    )
																		SCREAMING_SNAKE_CASE__						:       Any           =   input_image.cpu().permute(0   ,       2   ,       3   ,       1    ).float().numpy()
																		SCREAMING_SNAKE_CASE__						:       str           =   DiffusionPipeline.numpy_to_pil(_A    )[0]

											return {
											    "image": input_image,
											    "generator": generator,
											    "decoder_num_inference_steps": 2,
											    "super_res_num_inference_steps": 2,
											    "output_type": "np",
											}



				def 	__magic_name__    (self    )					->		Tuple:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Union[str, Any]           =   '''cpu'''

											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   self.get_dummy_components()

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   self.pipeline_class(**_A    )
											SCREAMING_SNAKE_CASE__						:       List[str]           =   pipe.to(_A    )

											pipe.set_progress_bar_config(disable=_A    )

											SCREAMING_SNAKE_CASE__						:       str           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )

											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   pipe(**_A    )
											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   output.images

											SCREAMING_SNAKE_CASE__						:       int           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )

											SCREAMING_SNAKE_CASE__						:       Any           =   pipe(
											    **_A   ,       return_dict=_A   ,       )[0]

											SCREAMING_SNAKE_CASE__						:       List[str]           =   image[0, -3:, -3:, -1]
											SCREAMING_SNAKE_CASE__						:       str           =   image_from_tuple[0, -3:, -3:, -1]

											assert image.shape == (1, 64, 64, 3)

											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   np.array(
											    [
											        0.9997,
											        0.0002,
											        0.9997,
											        0.9997,
											        0.9969,
											        0.0023,
											        0.9997,
											        0.9969,
											        0.9970,
											    ]    )

											assert np.abs(image_slice.flatten() - expected_slice    ).max() < 1E-2
											assert np.abs(image_from_tuple_slice.flatten() - expected_slice    ).max() < 1E-2



				def 	__magic_name__    (self    )					->		Optional[int]:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Tuple           =   '''cpu'''

											SCREAMING_SNAKE_CASE__						:       int           =   self.get_dummy_components()

											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   self.pipeline_class(**_A    )
											SCREAMING_SNAKE_CASE__						:       Any           =   pipe.to(_A    )

											pipe.set_progress_bar_config(disable=_A    )

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )

											SCREAMING_SNAKE_CASE__						:       Union[str, Any]           =   pipe(**_A    )
											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   output.images

											SCREAMING_SNAKE_CASE__						:       Dict           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )

											SCREAMING_SNAKE_CASE__						:       Dict           =   pipe(
											    **_A   ,       return_dict=_A   ,       )[0]

											SCREAMING_SNAKE_CASE__						:       List[str]           =   image[0, -3:, -3:, -1]
											SCREAMING_SNAKE_CASE__						:       Any           =   image_from_tuple[0, -3:, -3:, -1]

											assert image.shape == (1, 64, 64, 3)

											SCREAMING_SNAKE_CASE__						:       List[str]           =   np.array([0.9997, 0.0003, 0.9997, 0.9997, 0.9970, 0.0024, 0.9997, 0.9971, 0.9971]    )

											assert np.abs(image_slice.flatten() - expected_slice    ).max() < 1E-2
											assert np.abs(image_from_tuple_slice.flatten() - expected_slice    ).max() < 1E-2



				def 	__magic_name__    (self    )					->		Optional[Any]:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Tuple           =   '''cpu'''

											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   self.get_dummy_components()

											SCREAMING_SNAKE_CASE__						:       Dict           =   self.pipeline_class(**_A    )
											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   pipe.to(_A    )

											pipe.set_progress_bar_config(disable=_A    )

											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )
											SCREAMING_SNAKE_CASE__						:       Union[str, Any]           =   [
											    pipeline_inputs['''image'''],
											    pipeline_inputs['''image'''],
											]

											SCREAMING_SNAKE_CASE__						:       Any           =   pipe(**_A    )
											SCREAMING_SNAKE_CASE__						:       List[str]           =   output.images

											SCREAMING_SNAKE_CASE__						:       Any           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )
											SCREAMING_SNAKE_CASE__						:       List[str]           =   [
											    tuple_pipeline_inputs['''image'''],
											    tuple_pipeline_inputs['''image'''],
											]

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   pipe(
											    **_A   ,       return_dict=_A   ,       )[0]

											SCREAMING_SNAKE_CASE__						:       Union[str, Any]           =   image[0, -3:, -3:, -1]
											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   image_from_tuple[0, -3:, -3:, -1]

											assert image.shape == (2, 64, 64, 3)

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   np.array(
											    [
											        0.9997,
											        0.9989,
											        0.0008,
											        0.0021,
											        0.9960,
											        0.0018,
											        0.0014,
											        0.0002,
											        0.9933,
											    ]    )

											assert np.abs(image_slice.flatten() - expected_slice    ).max() < 1E-2
											assert np.abs(image_from_tuple_slice.flatten() - expected_slice    ).max() < 1E-2



				def 	__magic_name__    (self    )					->		Optional[int]:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       str           =   torch.device("""cpu"""    )



											class 	lowerCAmelCase_						:


															"""simple docstring"""



															__UpperCamelCase      :						List[Any]					       =   1






											SCREAMING_SNAKE_CASE__						:       Union[str, Any]           =   self.get_dummy_components()

											SCREAMING_SNAKE_CASE__						:       str           =   self.pipeline_class(**_A    )
											SCREAMING_SNAKE_CASE__						:       int           =   pipe.to(_A    )

											pipe.set_progress_bar_config(disable=_A    )

											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   torch.Generator(device=_A    ).manual_seed(0    )
											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   pipe.decoder.dtype
											SCREAMING_SNAKE_CASE__						:       Any           =   1

											SCREAMING_SNAKE_CASE__						:       Tuple           =   (
											    batch_size,
											    pipe.decoder.config.in_channels,
											    pipe.decoder.config.sample_size,
											    pipe.decoder.config.sample_size,
											)
											SCREAMING_SNAKE_CASE__						:       Any           =   pipe.prepare_latents(
											    _A   ,       dtype=_A   ,       device=_A   ,       generator=_A   ,       latents=_A   ,       scheduler=DummyScheduler()    )

											SCREAMING_SNAKE_CASE__						:       List[str]           =   (
											    batch_size,
											    pipe.super_res_first.config.in_channels // 2,
											    pipe.super_res_first.config.sample_size,
											    pipe.super_res_first.config.sample_size,
											)
											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   pipe.prepare_latents(
											    _A   ,       dtype=_A   ,       device=_A   ,       generator=_A   ,       latents=_A   ,       scheduler=DummyScheduler()    )

											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   pipe(
											    **_A   ,       decoder_latents=_A   ,       super_res_latents=_A    ).images

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   self.get_dummy_inputs(_A   ,       pil_image=_A    )
											# Don't pass image, instead pass embedding
											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   pipeline_inputs.pop("""image"""    )
											SCREAMING_SNAKE_CASE__						:       str           =   pipe.image_encoder(_A    ).image_embeds

											SCREAMING_SNAKE_CASE__						:       Dict           =   pipe(
											    **_A   ,       decoder_latents=_A   ,       super_res_latents=_A   ,       image_embeddings=_A   ,       ).images

											# make sure passing text embeddings manually is identical
											assert np.abs(img_out_a - img_out_a    ).max() < 1E-4



				@skip_mps
				def 	__magic_name__    (self    )					->		Union[str, Any]:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Any           =   torch_device == '''cpu'''

											# Check is relaxed because there is not a torch 2.0 sliced attention added kv processor
											SCREAMING_SNAKE_CASE__						:       Dict           =   1E-2

											self._test_attention_slicing_forward_pass(
											    test_max_difference=_A   ,       expected_max_diff=_A    )



				@skip_mps
				def 	__magic_name__    (self    )					->		Dict:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   torch_device == '''cpu'''
											SCREAMING_SNAKE_CASE__						:       Dict           =   True
											SCREAMING_SNAKE_CASE__						:       List[str]           =   [
											    '''decoder_num_inference_steps''',
											    '''super_res_num_inference_steps''',
											]

											self._test_inference_batch_single_identical(
											    test_max_difference=_A   ,       relax_max_difference=_A   ,       additional_params_copy_to_batched_inputs=_A   ,       )



				def 	__magic_name__    (self    )					->		Tuple:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       int           =   [
											    '''decoder_num_inference_steps''',
											    '''super_res_num_inference_steps''',
											]

											if torch_device == "mps":
																		# TODO: MPS errors with larger batch sizes
																		SCREAMING_SNAKE_CASE__						:       Dict           =   [2, 3]
																		self._test_inference_batch_consistent(
																		    batch_sizes=_A   ,       additional_params_copy_to_batched_inputs=_A   ,       )
											else:
																		self._test_inference_batch_consistent(
																		    additional_params_copy_to_batched_inputs=_A    )



				@skip_mps
				def 	__magic_name__    (self    )					->		str:



											"""simple docstring"""




											return super().test_dict_tuple_outputs_equivalent()



				@skip_mps
				def 	__magic_name__    (self    )					->		Optional[int]:



											"""simple docstring"""




											return super().test_save_load_local()



				@skip_mps
				def 	__magic_name__    (self    )					->		Optional[int]:



											"""simple docstring"""




											return super().test_save_load_optional_components()






@slow
@require_torch_gpu
class 	lowerCAmelCase_						(unittest.TestCase  ):


				"""simple docstring"""



				def 	__magic_name__    (self    )					->		Any:



											"""simple docstring"""




											super().tearDown()
											gc.collect()
											torch.cuda.empty_cache()



				def 	__magic_name__    (self    )					->		Optional[int]:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       Any           =   load_image(
											    """https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/unclip/cat.png"""    )
											SCREAMING_SNAKE_CASE__						:       int           =   load_numpy(
											    """https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main"""
											    """/unclip/karlo_v1_alpha_cat_variation_fp16.npy"""    )

											SCREAMING_SNAKE_CASE__						:       Optional[int]           =   UnCLIPImageVariationPipeline.from_pretrained(
											    """kakaobrain/karlo-v1-alpha-image-variations"""   ,       torch_dtype=torch.floataa    )
											SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   pipeline.to(_A    )
											pipeline.set_progress_bar_config(disable=_A    )

											SCREAMING_SNAKE_CASE__						:       List[str]           =   torch.Generator(device="""cpu"""    ).manual_seed(0    )
											SCREAMING_SNAKE_CASE__						:       Tuple           =   pipeline(
											    _A   ,       generator=_A   ,       output_type="""np"""   ,       )

											SCREAMING_SNAKE_CASE__						:       List[Any]           =   output.images[0]

											assert image.shape == (2_56, 2_56, 3)

											assert_mean_pixel_difference(_A   ,       _A   ,       15    )








'''simple docstring'''
# Copyright 2023 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING

# rely on isort to merge the imports
from ...utils import OptionalDependencyNotAvailable, _LazyModule, is_torch_available, is_vision_available


UpperCamelCase__    					=      {
    '''configuration_vivit''': ['''VIVIT_PRETRAINED_CONFIG_ARCHIVE_MAP''', '''VivitConfig'''],
}
try:
  if not is_vision_available():
    raise OptionalDependencyNotAvailable()
except OptionalDependencyNotAvailable:
  pass
else:
  UpperCamelCase__    					=      ['''VivitImageProcessor''']


try:
  if not is_torch_available():
    raise OptionalDependencyNotAvailable()
except OptionalDependencyNotAvailable:
  pass
else:
  UpperCamelCase__    					=      [
      '''VIVIT_PRETRAINED_MODEL_ARCHIVE_LIST''',
      '''VivitModel''',
      '''VivitPreTrainedModel''',
      '''VivitForVideoClassification''',
  ]


if TYPE_CHECKING:
  from .configuration_vivit import VIVIT_PRETRAINED_CONFIG_ARCHIVE_MAP, VivitConfig

  try:
    if not is_vision_available():
      raise OptionalDependencyNotAvailable()
  except OptionalDependencyNotAvailable:
    pass
  else:
    from .image_processing_vivit import VivitImageProcessor

  try:
    if not is_torch_available():
      raise OptionalDependencyNotAvailable()
  except OptionalDependencyNotAvailable:
    pass
  else:
    from .modeling_vivit import (
        VIVIT_PRETRAINED_MODEL_ARCHIVE_LIST,
        VivitForVideoClassification,
        VivitModel,
        VivitPreTrainedModel,
    )


else:
  import sys

  UpperCamelCase__    					=      _LazyModule(__name__, globals()['''__file__'''], _import_structure, module_spec=__spec__)
