U
    diF                     @   s@  d dl Z d dlmZ d dlmZmZmZmZmZ d dl	Z
ddlmZmZmZmZmZ ddlmZmZmZmZmZ ddlmZmZmZmZmZmZmZ e rd dlZddlm Z  e rd dl!Z!e rd dl"Z#e rd dl$m	Z% e rd d	l&m'Z( ne rd d	l)m'Z( dQe
j*eee+f eeee+f  e
j*d
ddZ,de
j-dfe
j*e.ee e
j/eee+ef  e
j*dddZ0dd Z1dRee
j*ddddf ee2 ee+ eee+ef  ddddZ3dSe
j*ee4ee4e4f ee4 ee4 f e2ee4 eee+ef  e5dddZ6dTe
j*ee4e4f dee4 ee e2eee+ef  e
j*ddd Z7dUe
j*ee.ee. f ee.ee. f ee eee+ef  e
j*d!d"d#Z8dVe
j*ee4e4f eee+ef  eee+ef  ee2 e
j*d$d%d&Z9ddd'd(d)Z:e
j*e
j*d'd*d+Z;ddd'd,d-Z<eed'd.d/Z=ddd0d1d2Z>e
j*e
j*d0d3d4Z?ddd0d5d6Z@eed0d7d8ZAd9d: ZBd;d< ZCG d=d> d>eZDeDjEd?ddfe
j*ee4ee4e4f eee4e4f  f eDee.ee. f eee+ef  eee+ef  e
j*d@dAdBZFeedCdDdEZGdWe
j*ee eee+ef  e
j*dFdGdHZHdIdJ ZIG dKdL dLZJG dMdN dNZKG dOdP dPZLdS )X    N)ceil)IterableListOptionalTupleUnion   )ChannelDimension
ImageInputget_channel_dimension_axisget_image_sizeinfer_channel_dimension_format)ExplicitEnum
TensorTypeis_jax_tensoris_tf_tensoris_torch_tensor)is_flax_availableis_tf_availableis_torch_availableis_torchvision_availableis_torchvision_v2_availableis_vision_availablerequires_backends)PILImageResampling)
functional)imagechannel_diminput_channel_dimreturnc                 C   s   t | tjstdt|  |dkr.t| }t|}||krB| S |tjkrX| d} n$|tj	krn| d} nt
d|| S )a)  
    Converts `image` to the channel dimension format specified by `channel_dim`.

    Args:
        image (`numpy.ndarray`):
            The image to have its channel dimension set.
        channel_dim (`ChannelDimension`):
            The channel dimension format to use.
        input_channel_dim (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If not provided, it will be inferred from the input image.

    Returns:
        `np.ndarray`: The image with the channel dimension set to `channel_dim`.
    ,Input image must be of type np.ndarray, got N)   r   r   )r   r!   r   z(Unsupported channel dimension format: {})
isinstancenpndarray	TypeErrortyper   r	   FIRST	transposeLAST
ValueErrorformat)r   r   r   Ztarget_channel_dim r,   A/tmp/pip-unpacked-wheel-bm_b0l5e/transformers/image_transforms.pyto_channel_dimension_format=   s    

r.   )r   scaledata_formatdtypeinput_data_formatr   c                 C   sP   t | tjstdt|  | tj| }|dk	rBt|||}||}|S )a  
    Rescales `image` by `scale`.

    Args:
        image (`np.ndarray`):
            The image to rescale.
        scale (`float`):
            The scale to use for rescaling the image.
        data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the image. If not provided, it will be the same as the input image.
        dtype (`np.dtype`, *optional*, defaults to `np.float32`):
            The dtype of the output image. Defaults to `np.float32`. Used for backwards compatibility with feature
            extractors.
        input_data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If not provided, it will be inferred from the input image.

    Returns:
        `np.ndarray`: The rescaled image.
    r    N)r"   r#   r$   r%   r&   astypeZfloat64r.   )r   r/   r0   r1   r2   Zrescaled_imager,   r,   r-   rescaled   s    
r4   c                 C   s   | j tjkrd}nt| | trftd| krFt| dkrFd}qtd|   d| 	  dn@td| krt| dkrd}ntd	|   d| 	  d|S )
z
    Detects whether or not the image needs to be rescaled before being converted to a PIL image.

    The assumption is that if the image is of type `np.float` and all values are between 0 and 1, it needs to be
    rescaled.
    Fr      zZThe image to be converted to a PIL image contains values outside the range [0, 255], got [z, z%] which cannot be converted to uint8.r   TzXThe image to be converted to a PIL image contains values outside the range [0, 1], got [)
r1   r#   uint8Zallcloser3   intallr*   minmax)r   
do_rescaler,   r,   r-   _rescale_for_pil_conversion   s    r<   zPIL.Image.Imagetorch.Tensorz	tf.Tensorzjnp.ndarray)r   r;   
image_moder2   r   c                 C   s   t tdg t| tjjr| S t| s.t| r8|  } n2t| rLt	
| } nt| t	jsjtdt| t| tj|} | jd dkrt	j| ddn| } |dkrt| n|}|rt| d} | t	j} tjj| |dS )	a  
    Converts `image` to a PIL Image. Optionally rescales it and puts the channel dimension back as the last axis if
    needed.

    Args:
        image (`PIL.Image.Image` or `numpy.ndarray` or `torch.Tensor` or `tf.Tensor`):
            The image to convert to the `PIL.Image` format.
        do_rescale (`bool`, *optional*):
            Whether or not to apply the scaling factor (to make pixel values integers between 0 and 255). Will default
            to `True` if the image type is a floating type and casting to `int` would result in a loss of precision,
            and `False` otherwise.
        image_mode (`str`, *optional*):
            The mode to use for the PIL image. If unset, will use the default mode for the input image type.
        input_data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If unset, will use the inferred format from the input.

    Returns:
        `PIL.Image.Image`: The converted image.
    visionz"Input image type not supported: {}r   ZaxisNr5   mode)r   to_pil_imager"   PILImager   r   numpyr   r#   arrayr$   r*   r+   r&   r.   r	   r)   shapeZsqueezer<   r4   r3   r6   Z	fromarray)r   r;   r>   r2   r,   r,   r-   rD      s     
 
rD   T)input_imagesizedefault_to_squaremax_sizer2   r   c                 C   s   t |ttfr@t|dkr"t|S t|dkr8|d }ntd|rL||fS t| |\}}||krj||fn||f\}}|}	|	t|	| |  }
}|dk	r||	krtd| d| ||krt||
 | | }
}||kr||
fS |
|fS )a  
    Find the target (height, width) dimension of the output image after resizing given the input image and the desired
    size.

    Args:
        input_image (`np.ndarray`):
            The image to resize.
        size (`int` or `Tuple[int, int]` or List[int] or `Tuple[int]`):
            The size to use for resizing the image. If `size` is a sequence like (h, w), output size will be matched to
            this.

            If `size` is an int and `default_to_square` is `True`, then image will be resized to (size, size). If
            `size` is an int and `default_to_square` is `False`, then smaller edge of the image will be matched to this
            number. i.e, if height > width, then image will be rescaled to (size * height / width, size).
        default_to_square (`bool`, *optional*, defaults to `True`):
            How to convert `size` when it is a single int. If set to `True`, the `size` will be converted to a square
            (`size`,`size`). If set to `False`, will replicate
            [`torchvision.transforms.Resize`](https://pytorch.org/vision/stable/transforms.html#torchvision.transforms.Resize)
            with support for resizing only the smallest edge and providing an optional `max_size`.
        max_size (`int`, *optional*):
            The maximum allowed for the longer edge of the resized image: if the longer edge of the image is greater
            than `max_size` after being resized according to `size`, then the image is resized again so that the longer
            edge is equal to `max_size`. As a result, `size` might be overruled, i.e the smaller edge may be shorter
            than `size`. Only used if `default_to_square` is `False`.
        input_data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If unset, will use the inferred format from the input.

    Returns:
        `tuple`: The target (height, width) dimension of the output image after resizing.
    r!   r   r   z7size must have 1 or 2 elements if it is a list or tupleNzmax_size = zN must be strictly greater than the requested size for the smaller edge size = )r"   tuplelistlenr*   r   r7   )rJ   rK   rL   rM   r2   heightwidthshortlongZrequested_new_shortZ	new_shortZnew_longr,   r,   r-   get_resize_output_image_size   s(    %
rU   r   )r   rK   resamplereducing_gapr0   return_numpyr2   r   c                 C   s   t tdg |dk	r|ntj}t|dks2td|dkrBt| }|dkrN|n|}d}t| tj	j	szt
| }t| ||d} |\}}	| j|	|f||d}
|rt|
}
|
jdkrtj|
dd	n|
}
t|
|tjd
}
|rt|
dn|
}
|
S )a  
    Resizes `image` to `(height, width)` specified by `size` using the PIL library.

    Args:
        image (`np.ndarray`):
            The image to resize.
        size (`Tuple[int, int]`):
            The size to use for resizing the image.
        resample (`int`, *optional*, defaults to `PILImageResampling.BILINEAR`):
            The filter to user for resampling.
        reducing_gap (`int`, *optional*):
            Apply optimization by resizing the image in two steps. The bigger `reducing_gap`, the closer the result to
            the fair resampling. See corresponding Pillow documentation for more details.
        data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the output image. If unset, will use the inferred format from the input.
        return_numpy (`bool`, *optional*, defaults to `True`):
            Whether or not to return the resized image as a numpy array. If False a `PIL.Image.Image` object is
            returned.
        input_data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If unset, will use the inferred format from the input.

    Returns:
        `np.ndarray`: The resized image.
    r?   Nr!   zsize must have 2 elementsF)r;   r2   )rV   rW   r@   rA   r   gp?)r   resizer   ZBILINEARrP   r*   r   r"   rE   rF   r<   rD   r#   rH   ndimZexpand_dimsr.   r	   r)   r4   )r   rK   rV   rW   r0   rX   r2   r;   rQ   rR   Zresized_imager,   r,   r-   rZ     s.    !
  rZ   )r   meanstdr0   r2   r   c                 C   s2  t | tjstd|dkr$t| }t| |d}| j| }t| jtj	sV| 
tj} t |trt||krtd| dt| n
|g| }tj|| jd}t |trt||krtd| dt| n
|g| }tj|| jd}|tjkr| | | } n| j| | j} |dk	r*t| ||n| } | S )a  
    Normalizes `image` using the mean and standard deviation specified by `mean` and `std`.

    image = (image - mean) / std

    Args:
        image (`np.ndarray`):
            The image to normalize.
        mean (`float` or `Iterable[float]`):
            The mean to use for normalization.
        std (`float` or `Iterable[float]`):
            The standard deviation to use for normalization.
        data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the output image. If unset, will use the inferred format from the input.
        input_data_format (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If unset, will use the inferred format from the input.
    zimage must be a numpy arrayN)r2   zmean must have z$ elements if it is an iterable, got r1   zstd must have )r"   r#   r$   r*   r   r   rI   Z
issubdtyper1   Zfloatingr3   float32r   rP   rH   r	   r)   Tr.   )r   r\   r]   r0   r2   Zchannel_axisZnum_channelsr,   r,   r-   	normalizef  s.    




ra   )r   rK   r0   r2   rX   r   c                 C   s(  t tdg |dk	r tdt |dkr,dn|}t| tjsNtdt	|  t|t
rdt|dkrltd|dkr|t| }|dk	r|n|}t| tj|} t| tj\}}|\}}	t|t|	 }}	|| d }
|
| }||	 d }||	 }|
dkr<||kr<|dkr<||kr<| d	|
|||f } t| |tj} | S t||}t|	|}| jdd
 ||f }tj| |d}t|| d }|| }t|| d }|| }| |d	||||f< |
|7 }
||7 }||7 }||7 }|d	td|
t||td|t||f }t||tj}|s$t|}|S )a  
    Crops the `image` to the specified `size` using a center crop. Note that if the image is too small to be cropped to
    the size given, it will be padded (so the returned result will always be of size `size`).

    Args:
        image (`np.ndarray`):
            The image to crop.
        size (`Tuple[int, int]`):
            The target size for the cropped image.
        data_format (`str` or `ChannelDimension`, *optional*):
            The channel dimension format for the output image. Can be one of:
                - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
                - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
            If unset, will use the inferred format of the input image.
        input_data_format (`str` or `ChannelDimension`, *optional*):
            The channel dimension format for the input image. Can be one of:
                - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
                - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
            If unset, will use the inferred format of the input image.
        return_numpy (`bool`, *optional*):
            Whether or not to return the cropped image as a numpy array. Used for backwards compatibility with the
            previous ImageFeatureExtractionMixin method.
                - Unset: will return the same type as the input image.
                - `True`: will return a numpy array.
                - `False`: will return a `PIL.Image.Image` object.
    Returns:
        `np.ndarray`: The cropped image.
    r?   Nz8return_numpy is deprecated and will be removed in v.4.33Tr    r!   zOsize must have 2 elements representing the height and width of the output imager   .)rI   )r   center_cropwarningswarnFutureWarningr"   r#   r$   r%   r&   r   rP   r*   r   r.   r	   r'   r   r7   r:   rI   Z
zeros_liker   r9   rD   )r   rK   r0   r2   rX   Zoutput_data_formatZorig_heightZ
orig_widthZcrop_heightZ
crop_widthtopZbottomleftrightZ
new_heightZ	new_widthZ	new_shapeZ	new_imageZtop_padZ
bottom_padZleft_padZ	right_padr,   r,   r-   rc     sR    #(

.rc   )bboxes_centerr   c                 C   sL   |  d\}}}}tj|d|  |d|  |d|  |d|  gdd}|S )Nr@         ?ZdimZunbindtorchstack)rj   center_xcenter_yrR   rQ   Zbbox_cornersr,   r,   r-   _center_to_corners_format_torch  s    *rr   c                 C   sH   | j \}}}}tj|d|  |d|  |d|  |d|  gdd}|S )Nrk   r@   rA   r`   r#   ro   rj   rp   rq   rR   rQ   bboxes_cornersr,   r,   r-   _center_to_corners_format_numpy  s    *rv   c                 C   sP   t j| dd\}}}}t j|d|  |d|  |d|  |d|  gdd}|S )Nr@   rA   rk   tfZunstackro   rt   r,   r,   r-   _center_to_corners_format_tf  s    *ry   c                 C   sJ   t | rt| S t| tjr$t| S t| r4t| S tdt	|  dS )a|  
    Converts bounding boxes from center format to corners format.

    center format: contains the coordinate for the center of the box and its width, height dimensions
        (center_x, center_y, width, height)
    corners format: contains the coodinates for the top-left and bottom-right corners of the box
        (top_left_x, top_left_y, bottom_right_x, bottom_right_y)
    Unsupported input type N)
r   rr   r"   r#   r$   rv   r   ry   r*   r&   )rj   r,   r,   r-   center_to_corners_format%  s    r{   )ru   r   c                 C   sD   |  d\}}}}|| d || d || || g}tj|ddS )Nr@   r!   rl   rm   )ru   
top_left_x
top_left_ybottom_right_xbottom_right_ybr,   r,   r-   _corners_to_center_format_torch:  s    

r   c                 C   s@   | j \}}}}tj|| d || d || || gdd}|S )Nr!   r@   rA   rs   ru   r|   r}   r~   r   rj   r,   r,   r-   _corners_to_center_format_numpyE  s    

	r   c                 C   sH   t j| dd\}}}}t j|| d || d || || gdd}|S )Nr@   rA   r!   rw   r   r,   r,   r-   _corners_to_center_format_tfS  s    

	r   c                 C   sJ   t | rt| S t| tjr$t| S t| r4t| S tdt	|  dS )a  
    Converts bounding boxes from corners format to center format.

    corners format: contains the coordinates for the top-left and bottom-right corners of the box
        (top_left_x, top_left_y, bottom_right_x, bottom_right_y)
    center format: contains the coordinate for the center of the box and its the width, height dimensions
        (center_x, center_y, width, height)
    rz   N)
r   r   r"   r#   r$   r   r   r   r*   r&   )ru   r,   r,   r-   corners_to_center_formata  s    
r   c                 C   s   t | tjr|t| jdkr|| jtjkr2| tj} | dddddf d| dddddf   d| dddddf   S t	| d d| d   d| d   S )z*
    Converts RGB color to unique ID.
       Nr      r   i   r!   )
r"   r#   r$   rP   rI   r1   r6   r3   Zint32r7   )colorr,   r,   r-   	rgb_to_idx  s
    Jr   c                 C   s   t | tjrb|  }tt| jdg }tj|tjd}t	dD ]}|d |d|f< |d }q@|S g }t	dD ]}|
| d  | d } qn|S )z*
    Converts unique ID to RGB color.
    r   r^   r   .)r"   r#   r$   copyrN   rO   rI   zerosr6   rangeappend)Zid_mapZid_map_copyZ	rgb_shapeZrgb_mapir   _r,   r,   r-   	id_to_rgb  s    

r   c                   @   s    e Zd ZdZdZdZdZdZdS )PaddingModezP
    Enum class for the different padding modes to use when padding images.
    constantreflectZ	replicate	symmetricN)__name__
__module____qualname____doc__CONSTANTREFLECT	REPLICATE	SYMMETRICr,   r,   r,   r-   r     s
   r   g        )r   paddingrC   constant_valuesr0   r2   r   c                    s   dkrt   fdd}||}|tjkrL||}tj |d|d nb|tjkrhtj |dd nF|tjkrtj |dd n*|tjkrtj |d	d ntd
| |dk	rt	 |n   S )a  
    Pads the `image` with the specified (height, width) `padding` and `mode`.

    Args:
        image (`np.ndarray`):
            The image to pad.
        padding (`int` or `Tuple[int, int]` or `Iterable[Tuple[int, int]]`):
            Padding to apply to the edges of the height, width axes. Can be one of three formats:
            - `((before_height, after_height), (before_width, after_width))` unique pad widths for each axis.
            - `((before, after),)` yields same before and after pad for height and width.
            - `(pad,)` or int is a shortcut for before = after = pad width for all axes.
        mode (`PaddingMode`):
            The padding mode to use. Can be one of:
                - `"constant"`: pads with a constant value.
                - `"reflect"`: pads with the reflection of the vector mirrored on the first and last values of the
                  vector along each axis.
                - `"replicate"`: pads with the replication of the last value on the edge of the array along each axis.
                - `"symmetric"`: pads with the reflection of the vector mirrored along the edge of the array.
        constant_values (`float` or `Iterable[float]`, *optional*):
            The value to use for the padding if `mode` is `"constant"`.
        data_format (`str` or `ChannelDimension`, *optional*):
            The channel dimension format for the output image. Can be one of:
                - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
                - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
            If unset, will use same as the input image.
        input_data_format (`str` or `ChannelDimension`, *optional*):
            The channel dimension format for the input image. Can be one of:
                - `"channels_first"` or `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
                - `"channels_last"` or `ChannelDimension.LAST`: image in (height, width, num_channels) format.
            If unset, will use the inferred format of the input image.

    Returns:
        `np.ndarray`: The padded image.

    Nc                    s   t | ttfr | | f| | ff} nt | trXt| dkrX| d | d f| d | d ff} nft | trt| dkrt | d tr| | f} n8t | trt| dkrt | d tr| } ntd|  tjkrd| n| d}  jdkrd	| n| } | S )
za
        Convert values to be in the format expected by np.pad based on the data format.
        r   r   r!   zUnsupported format: r   r      )r   )r   )r   )	r"   r7   floatrN   rP   r*   r	   r'   r[   )valuesr   r2   r,   r-   _expand_for_data_format  s    "$
$z$pad.<locals>._expand_for_data_formatr   )rC   r   r   rB   Zedger   zInvalid padding mode: )
r   r   r   r#   padr   r   r   r*   r.   )r   r   rC   r   r0   r2   r   r,   r   r-   r     s     +



r   )r   r   c                 C   s:   t tdg t| tjjs| S | jdkr,| S | d} | S )z
    Converts an image to RGB format. Only converts if the image is of type PIL.Image.Image, otherwise returns the image
    as is.
    Args:
        image (Image):
            The image to convert.
    r?   ZRGB)r   convert_to_rgbr"   rE   rF   rC   convertr   r,   r,   r-   r     s    

r   )r   r0   r2   r   c                 C   sx   |dkrt | n|}|tjkr2| ddddf } n,|tjkrP| ddddf } ntd| |dk	rtt| ||d} | S )a  
    Flips the channel order of the image.

    If the image is in RGB format, it will be converted to BGR and vice versa.

    Args:
        image (`np.ndarray`):
            The image to flip.
        data_format (`ChannelDimension`, *optional*):
            The channel dimension format for the output image. Can be one of:
                - `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
                - `ChannelDimension.LAST`: image in (height, width, num_channels) format.
            If unset, will use same as the input image.
        input_data_format (`ChannelDimension`, *optional*):
            The channel dimension format for the input image. Can be one of:
                - `ChannelDimension.FIRST`: image in (num_channels, height, width) format.
                - `ChannelDimension.LAST`: image in (height, width, num_channels) format.
            If unset, will use the inferred format of the input image.
    N.r@   zUnsupported channel dimension: rY   )r   r	   r)   r'   r*   r.   )r   r0   r2   r,   r,   r-   flip_channel_order  s    

r   c                 C   s   |   r| S |  S N)Zis_floating_pointr   )xr,   r,   r-   _cast_tensor_to_float2  s    r   c                   @   s0   e Zd ZdZdeedddZddd	d
ZdS )FusedRescaleNormalizez<
    Rescale and normalize the input image in one step.
          ?F)rescale_factorinplacec                 C   s2   t |d|  | _t |d|  | _|| _d S )Nr   )rn   Ztensorr\   r]   r   )selfr\   r]   r   r   r,   r,   r-   __init__=  s    zFusedRescaleNormalize.__init__r=   r   c                 C   s    t |}tj|| j| j| jdS )N)r   )r   Fra   r\   r]   r   r   r   r,   r,   r-   __call__B  s    zFusedRescaleNormalize.__call__N)r   F)r   r   r   r   r   boolr   r   r,   r,   r,   r-   r   8  s   r   c                   @   s.   e Zd ZdZdedddZdddd	Zd
S )RescalezM
    Rescale the input image by rescale factor: image *= rescale_factor.
    r   r   c                 C   s
   || _ d S r   r   )r   r   r,   r,   r-   r   L  s    zRescale.__init__r=   r   c                 C   s   || j  }|S r   r   r   r,   r,   r-   r   O  s    
zRescale.__call__N)r   )r   r   r   r   r   r   r   r,   r,   r,   r-   r   G  s   r   c                   @   s    e Zd ZdZejdddZdS )NumpyToTensorz4
    Convert a numpy array to a PyTorch tensor.
    r   c                 C   s   t |ddd S )Nr!   r   r   )rn   Z
from_numpyr(   
contiguousr   r,   r,   r-   r   Y  s    zNumpyToTensor.__call__N)r   r   r   r   r#   r$   r   r,   r,   r,   r-   r   T  s   r   )N)NNN)TNN)NNNTN)NN)NNN)NN)Mrd   mathr   typingr   r   r   r   r   rG   r#   Zimage_utilsr	   r
   r   r   r   utilsr   r   r   r   r   Zutils.import_utilsr   r   r   r   r   r   r   rE   r   rn   Z
tensorflowrx   Z	jax.numpyZjnpZtorchvision.transforms.v2r   r   Ztorchvision.transformsr$   strr.   r_   r   r1   r4   r<   r   rD   r7   rN   rU   rZ   ra   rc   rr   rv   ry   r{   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r,   r,   r,   r-   <module>   s  $ 
*&   :   F     
K  @   
c

 W  &