
import gc
import random
import tempfile
import unittest

import numpy as np
import torch
from transformers import CLIPTextConfig, CLIPTextModel, CLIPTokenizer

from diffusers import AutoencoderKL, DDIMScheduler, LMSDiscreteScheduler, PNDMScheduler, UNetaDConditionModel
from diffusers.pipelines.semantic_stable_diffusion import SemanticStableDiffusionPipeline as StableDiffusionPipeline
from diffusers.utils import floats_tensor, nightly, torch_device
from diffusers.utils.testing_utils import enable_full_determinism, require_torch_gpu


enable_full_determinism()







class      lowerCamelCase		(  unittest.TestCase  ):





     def 		UpperCAmelCase(self      :    int   )						->						Optional[int]:
         # clean up the VRAM after each test
         super().tearDown()
         gc.collect()
         torch.cuda.empty_cache()





     @property
     def 		UpperCAmelCase(self      :    Union[str, Any]   )						->						Union[str, Any]:
         snake_case      =					1
         snake_case      =					3
         snake_case      =					(3_2, 3_2)

         snake_case      =					floats_tensor((batch_size, num_channels) + sizes				,    rng=random.Random(0   )   ).to(_A   )
         return image





     @property
     def 		UpperCAmelCase(self      :    List[str]   )						->						Tuple:
         torch.manual_seed(0   )
         snake_case      =					UNetaDConditionModel(
             block_out_channels=(3_2, 6_4)				,    layers_per_block=2				,    sample_size=3_2				,    in_channels=4				,    out_channels=4				,    down_block_types=("DownBlock2D", "CrossAttnDownBlock2D")				,    up_block_types=("CrossAttnUpBlock2D", "UpBlock2D")				,    cross_attention_dim=3_2				,    )
         return model





     @property
     def 		UpperCAmelCase(self      :    List[str]   )						->						str:
         torch.manual_seed(0   )
         snake_case      =					AutoencoderKL(
             block_out_channels=[3_2, 6_4]				,    in_channels=3				,    out_channels=3				,    down_block_types=["DownEncoderBlock2D", "DownEncoderBlock2D"]				,    up_block_types=["UpDecoderBlock2D", "UpDecoderBlock2D"]				,    latent_channels=4				,    )
         return model





     @property
     def 		UpperCAmelCase(self      :    Dict   )						->						Any:
         torch.manual_seed(0   )
         snake_case      =					CLIPTextConfig(
             bos_token_id=0				,    eos_token_id=2				,    hidden_size=3_2				,    intermediate_size=3_7				,    layer_norm_eps=1E-05				,    num_attention_heads=4				,    num_hidden_layers=5				,    pad_token_id=1				,    vocab_size=1_0_0_0				,    )
         return CLIPTextModel(_A   )





     @property
     def 		UpperCAmelCase(self      :    Dict   )						->						int:
         def extract(*_A      :    List[Any]				,    **_A      :    List[str]   ):







             class      lowerCamelCase		:





                  def __init__(self      :    Optional[int]   )						->						str:
                      snake_case      =					torch.ones([0]   )





                  def 		UpperCAmelCase(self      :    Dict				,    _A      :    Any   )						->						Optional[int]:
                      self.pixel_values.to(_A   )
                      return self


             return Out()

         return extract





     def 		UpperCAmelCase(self      :    str   )						->						Any:
         snake_case      =					"cpu"  # ensure determinism for the device-dependent torch.Generator
         snake_case      =					self.dummy_cond_unet
         snake_case      =					DDIMScheduler(
             beta_start=0.0_00_85				,    beta_end=0.0_12				,    beta_schedule="scaled_linear"				,    clip_sample=_A				,    set_alpha_to_one=_A				,    )

         snake_case      =					self.dummy_vae
         snake_case      =					self.dummy_text_encoder
         snake_case      =					CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip"   )

         # make sure here that pndm scheduler skips prk
         snake_case      =					StableDiffusionPipeline(
             unet=_A				,    scheduler=_A				,    vae=_A				,    text_encoder=_A				,    tokenizer=_A				,    safety_checker=_A				,    feature_extractor=self.dummy_extractor				,    )
         snake_case      =					sd_pipe.to(_A   )
         sd_pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"A painting of a squirrel eating a burger"

         snake_case      =					torch.Generator(device=_A   ).manual_seed(0   )
         snake_case      =					sd_pipe([prompt]				,    generator=_A				,    guidance_scale=6.0				,    num_inference_steps=2				,    output_type="np"   )
         snake_case      =					output.images

         snake_case      =					torch.Generator(device=_A   ).manual_seed(0   )
         snake_case      =					sd_pipe(
             [prompt]				,    generator=_A				,    guidance_scale=6.0				,    num_inference_steps=2				,    output_type="np"				,    return_dict=_A				,    )[0]

         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					image_from_tuple[0, -3:, -3:, -1]

         assert image.shape == (1, 6_4, 6_4, 3)
         snake_case      =					np.array([0.57_53, 0.61_14, 0.50_01, 0.50_34, 0.54_70, 0.47_29, 0.49_71, 0.48_67, 0.48_67]   )

         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 		UpperCAmelCase(self      :    Optional[Any]   )						->						Optional[int]:
         snake_case      =					"cpu"  # ensure determinism for the device-dependent torch.Generator
         snake_case      =					self.dummy_cond_unet
         snake_case      =					PNDMScheduler(skip_prk_steps=_A   )
         snake_case      =					self.dummy_vae
         snake_case      =					self.dummy_text_encoder
         snake_case      =					CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip"   )

         # make sure here that pndm scheduler skips prk
         snake_case      =					StableDiffusionPipeline(
             unet=_A				,    scheduler=_A				,    vae=_A				,    text_encoder=_A				,    tokenizer=_A				,    safety_checker=_A				,    feature_extractor=self.dummy_extractor				,    )
         snake_case      =					sd_pipe.to(_A   )
         sd_pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"A painting of a squirrel eating a burger"
         snake_case      =					torch.Generator(device=_A   ).manual_seed(0   )
         snake_case      =					sd_pipe([prompt]				,    generator=_A				,    guidance_scale=6.0				,    num_inference_steps=2				,    output_type="np"   )

         snake_case      =					output.images

         snake_case      =					torch.Generator(device=_A   ).manual_seed(0   )
         snake_case      =					sd_pipe(
             [prompt]				,    generator=_A				,    guidance_scale=6.0				,    num_inference_steps=2				,    output_type="np"				,    return_dict=_A				,    )[0]

         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					image_from_tuple[0, -3:, -3:, -1]

         assert image.shape == (1, 6_4, 6_4, 3)
         snake_case      =					np.array([0.51_22, 0.57_12, 0.48_25, 0.50_53, 0.56_46, 0.47_69, 0.51_79, 0.48_94, 0.49_94]   )

         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 		UpperCAmelCase(self      :    Union[str, Any]   )						->						Optional[Any]:
         snake_case      =					StableDiffusionPipeline.from_pretrained(
             "hf-internal-testing/tiny-stable-diffusion-lms-pipe"				,    safety_checker=_A   )
         assert isinstance(_A				,    _A   )
         assert isinstance(pipe.scheduler				,    _A   )
         assert pipe.safety_checker is None

         snake_case      =					pipe("example prompt"				,    num_inference_steps=2   ).images[0]
         assert image is not None

         # check that there's no error when saving a pipeline with one of the models being None
         with tempfile.TemporaryDirectory() as tmpdirname:
             pipe.save_pretrained(_A   )
             snake_case      =					StableDiffusionPipeline.from_pretrained(_A   )

         # sanity check that the pipeline still works
         assert pipe.safety_checker is None
         snake_case      =					pipe("example prompt"				,    num_inference_steps=2   ).images[0]
         assert image is not None





     @unittest.skipIf(torch_device != "cuda"				,    "This test requires a GPU"   )
     def 		UpperCAmelCase(self      :    Tuple   )						->						Optional[Any]:
         snake_case      =					self.dummy_cond_unet
         snake_case      =					PNDMScheduler(skip_prk_steps=_A   )
         snake_case      =					self.dummy_vae
         snake_case      =					self.dummy_text_encoder
         snake_case      =					CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip"   )

         # put models in fp16
         snake_case      =					unet.half()
         snake_case      =					vae.half()
         snake_case      =					bert.half()

         # make sure here that pndm scheduler skips prk
         snake_case      =					StableDiffusionPipeline(
             unet=_A				,    scheduler=_A				,    vae=_A				,    text_encoder=_A				,    tokenizer=_A				,    safety_checker=_A				,    feature_extractor=self.dummy_extractor				,    )
         snake_case      =					sd_pipe.to(_A   )
         sd_pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"A painting of a squirrel eating a burger"
         snake_case      =					sd_pipe([prompt]				,    num_inference_steps=2				,    output_type="np"   ).images

         assert image.shape == (1, 6_4, 6_4, 3)







@nightly
@require_torch_gpu
class      lowerCamelCase		(  unittest.TestCase  ):





     def 		UpperCAmelCase(self      :    Union[str, Any]   )						->						Any:
         # clean up the VRAM after each test
         super().tearDown()
         gc.collect()
         torch.cuda.empty_cache()





     def 		UpperCAmelCase(self      :    Union[str, Any]   )						->						int:
         snake_case      =					"cuda"
         snake_case      =					StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5"   )
         snake_case      =					pipe.to(_A   )
         pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"a photo of a cat"
         snake_case      =					{
             "editing_prompt": ["sunglasses"],
             "reverse_editing_direction": [False],
             "edit_warmup_steps": 1_0,
             "edit_guidance_scale": 6,
             "edit_threshold": 0.95,
             "edit_momentum_scale": 0.5,
             "edit_mom_beta": 0.6,
         }

         snake_case      =					3
         snake_case      =					7

         # no sega enabled
         snake_case      =					torch.Generator(_A   )
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.34_67_31_13,
             0.38_49_27_33,
             0.37_59_73_52,
             0.34_08_63_35,
             0.35_65_07_48,
             0.35_57_92_05,
             0.3_38_47_63,
             0.34_34_02_36,
             0.3_57_32_71,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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

         # with sega enabled
         # generator = torch.manual_seed(seed)
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    **_A				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.41_88_78_26,
             0.37_72_87_66,
             0.30_13_82_72,
             0.41_41_63_35,
             0.41_66_49_85,
             0.36_28_33_92,
             0.36_19_12_46,
             0.43_36_44_65,
             0.43_00_17_32,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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





     def 		UpperCAmelCase(self      :    List[Any]   )						->						Optional[int]:
         snake_case      =					"cuda"
         snake_case      =					StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5"   )
         snake_case      =					pipe.to(_A   )
         pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"an image of a crowded boulevard, realistic, 4k"
         snake_case      =					{
             "editing_prompt": "crowd, crowded, people",
             "reverse_editing_direction": True,
             "edit_warmup_steps": 1_0,
             "edit_guidance_scale": 8.3,
             "edit_threshold": 0.9,
             "edit_momentum_scale": 0.5,
             "edit_mom_beta": 0.6,
         }

         snake_case      =					9
         snake_case      =					7

         # no sega enabled
         snake_case      =					torch.Generator(_A   )
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.43_49_79_98,
             0.91_81_40_65,
             0.7_54_07_39,
             0.55_58_02_05,
             0.8_46_72_65,
             0.5_38_96_91,
             0.62_57_45_06,
             0.58_89_77_63,
             0.50_92_67_57,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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

         # with sega enabled
         # generator = torch.manual_seed(seed)
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    **_A				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.3_08_97_19,
             0.30_50_01_44,
             0.29_01_60_42,
             0.30_63_09_64,
             0.32_56_87,
             0.29_41_92_25,
             0.2_90_80_91,
             0.28_72_35_98,
             0.27_69_62_94,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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





     def 		UpperCAmelCase(self      :    Tuple   )						->						str:
         snake_case      =					"cuda"
         snake_case      =					StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5"   )
         snake_case      =					pipe.to(_A   )
         pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"a castle next to a river"
         snake_case      =					{
             "editing_prompt": ["boat on a river, boat", "monet, impression, sunrise"],
             "reverse_editing_direction": False,
             "edit_warmup_steps": [1_5, 1_8],
             "edit_guidance_scale": 6,
             "edit_threshold": [0.9, 0.8],
             "edit_momentum_scale": 0.5,
             "edit_mom_beta": 0.6,
         }

         snake_case      =					4_8
         snake_case      =					7

         # no sega enabled
         snake_case      =					torch.Generator(_A   )
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.75_16_35_55,
             0.76_03_71_45,
             0.6_17_85,
             0.9_18_96_73,
             0.8_62_77_01,
             0.85_18_96_94,
             0.8_51_28_13,
             0.87_01_20_76,
             0.8_31_28_57,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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

         # with sega enabled
         # generator = torch.manual_seed(seed)
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    **_A				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.73_55_33_65,
             0.7_53_72_71,
             0.74_34_19_05,
             0.66_48_03_56,
             0.6_47_29_25,
             0.63_03_94_16,
             0.64_81_29_05,
             0.6_74_97_17,
             0.6_51_71_02,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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





     def 		UpperCAmelCase(self      :    Dict   )						->						Dict:
         snake_case      =					"cuda"
         snake_case      =					StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5"				,    torch_dtype=torch.floataa   )
         snake_case      =					pipe.to(_A   )
         pipe.set_progress_bar_config(disable=_A   )

         snake_case      =					"a photo of a cat"
         snake_case      =					{
             "editing_prompt": ["sunglasses"],
             "reverse_editing_direction": [False],
             "edit_warmup_steps": 1_0,
             "edit_guidance_scale": 6,
             "edit_threshold": 0.95,
             "edit_momentum_scale": 0.5,
             "edit_mom_beta": 0.6,
         }

         snake_case      =					3
         snake_case      =					7

         # no sega enabled
         snake_case      =					torch.Generator(_A   )
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.34_88_76_95,
             0.3_87_69_53,
             0.3_75,
             0.34_42_38_28,
             0.3_58_15_43,
             0.35_71_77_73,
             0.3_38_37_89,
             0.34_57_03_12,
             0.35_93_75,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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

         # with sega enabled
         # generator = torch.manual_seed(seed)
         generator.manual_seed(_A   )
         snake_case      =					pipe(
             [prompt]				,    generator=_A				,    guidance_scale=_A				,    num_inference_steps=5_0				,    output_type="np"				,    width=5_1_2				,    height=5_1_2				,    **_A				,    )

         snake_case      =					output.images
         snake_case      =					image[0, -3:, -3:, -1]
         snake_case      =					[
             0.42_28_51_56,
             0.36_91_40_62,
             0.29_07_71_48,
             0.42_04_10_16,
             0.41_91_89_45,
             0.35_49_80_47,
             0.3_61_81_64,
             0.4_42_38_28,
             0.43_11_52_34,
         ]

         assert image.shape == (1, 5_1_2, 5_1_2, 3)

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



from typing import List, Optional, Union

import numpy as np

from ...feature_extraction_sequence_utils import SequenceFeatureExtractor
from ...feature_extraction_utils import BatchFeature
from ...utils import PaddingStrategy, TensorType, logging


_A  					= logging.get_logger(__name__)







class      lowerCamelCase		(  A_  ):
     UpperCAmelCase__				:							int           =		["input_values", "attention_mask"]





     def __init__(self      :    Tuple				,    _A      :    Optional[Any]=1				,    _A      :    Dict=1_6_0_0_0				,    _A      :    int=0.0				,    _A      :    List[str]=False				,    _A      :    Optional[int]=True				,    **_A      :    List[Any]				,    )						->						str:
         super().__init__(feature_size=_A				,    sampling_rate=_A				,    padding_value=_A				,    **_A   )
         snake_case      =					return_attention_mask
         snake_case      =					do_normalize





     @staticmethod
     def 		UpperCAmelCase(_A      :    List[np.ndarray]				,    _A      :    List[np.ndarray]				,    _A      :    float = 0.0   )						->						List[np.ndarray]:
         if attention_mask is not None:
             snake_case      =					np.array(_A				,    np.intaa   )
             snake_case      =					[]

             for vector, length in zip(_A				,    attention_mask.sum(-1   )   ):
                 snake_case      =					(vector - vector[:length].mean()) / np.sqrt(vector[:length].var() + 1E-7   )
                 if length < normed_slice.shape[0]:
                     snake_case      =					padding_value

                 normed_input_values.append(_A   )
         else:
             snake_case      =					[(x - x.mean()) / np.sqrt(x.var() + 1E-7   ) for x in input_values]

         return normed_input_values





     def __call__(self      :    Optional[Any]				,    _A      :    Union[np.ndarray, List[float], List[np.ndarray], List[List[float]]]				,    _A      :    Union[bool, str, PaddingStrategy] = False				,    _A      :    Optional[int] = None				,    _A      :    bool = False				,    _A      :    Optional[int] = None				,    _A      :    Optional[bool] = None				,    _A      :    Optional[Union[str, TensorType]] = None				,    _A      :    Optional[int] = None				,    **_A      :    List[Any]				,    )						->						BatchFeature:

         if sampling_rate is not None:
             if sampling_rate != self.sampling_rate:
                 raise ValueError(
                     f'The model corresponding to this feature extractor: {self} was trained using a sampling rate of'
                     f' {self.sampling_rate}. Please make sure that the provided `raw_speech` input was sampled with'
                     f' {self.sampling_rate} and not {sampling_rate}.'   )
         else:
             logger.warning(
                 "It is strongly recommended to pass the ``sampling_rate`` argument to this function. "
                 "Failing to do so can result in silent errors that might be hard to debug."   )

         snake_case      =					isinstance(_A				,    np.ndarray   ) and len(raw_speech.shape   ) > 1
         if is_batched_numpy and len(raw_speech.shape   ) > 2:
             raise ValueError(f'Only mono-channel audio is supported for input to {self}'   )
         snake_case      =					is_batched_numpy or (
             isinstance(_A				,    (list, tuple)   ) and (isinstance(raw_speech[0]				,    (np.ndarray, tuple, list)   ))
         )

         # always return batch
         if not is_batched:
             snake_case      =					[raw_speech]

         # convert into correct format for padding
         snake_case      =					BatchFeature({"input_values": raw_speech}   )

         snake_case      =					self.pad(
             _A				,    padding=_A				,    max_length=_A				,    truncation=_A				,    pad_to_multiple_of=_A				,    return_attention_mask=_A				,    )

         # convert input values to correct format
         snake_case      =					padded_inputs["input_values"]
         if not isinstance(input_values[0]				,    np.ndarray   ):
             snake_case      =					[np.asarray(_A				,    dtype=np.floataa   ) for array in input_values]
         elif (
             not isinstance(_A				,    np.ndarray   )
             and isinstance(input_values[0]				,    np.ndarray   )
             and input_values[0].dtype is np.dtype(np.floataa   )
         ):
             snake_case      =					[array.astype(np.floataa   ) for array in input_values]
         elif isinstance(_A				,    np.ndarray   ) and input_values.dtype is np.dtype(np.floataa   ):
             snake_case      =					input_values.astype(np.floataa   )

         # convert attention_mask to correct format
         snake_case      =					padded_inputs.get("attention_mask"   )
         if attention_mask is not None:
             snake_case      =					[np.asarray(_A				,    dtype=np.intaa   ) for array in attention_mask]

         # zero-mean and unit-variance normalization
         if self.do_normalize:
             snake_case      =					(
                 attention_mask
                 if self._get_padding_strategies(_A				,    max_length=_A   ) is not PaddingStrategy.DO_NOT_PAD
                 else None
             )
             snake_case      =					self.zero_mean_unit_var_norm(
                 padded_inputs["input_values"]				,    attention_mask=_A				,    padding_value=self.padding_value   )

         if return_tensors is not None:
             snake_case      =					padded_inputs.convert_to_tensors(_A   )

         return padded_inputs

