
import inspect
from typing import Optional, Union

import numpy as np
import PIL
import torch
from torch.nn import functional as F
from torchvision import transforms
from transformers import CLIPFeatureExtractor, CLIPModel, CLIPTextModel, CLIPTokenizer

from diffusers import (
    AutoencoderKL,
    DDIMScheduler,
    DiffusionPipeline,
    DPMSolverMultistepScheduler,
    LMSDiscreteScheduler,
    PNDMScheduler,
    UNetaDConditionModel,
)
from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion import StableDiffusionPipelineOutput
from diffusers.utils import (
    PIL_INTERPOLATION,
    randn_tensor,
)







def 						_snake_case(  SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__				) ->    List[Any]:
       if isinstance(SCREAMING_SNAKE_CASE__					,	torch.Tensor				):
              return image
       elif isinstance(SCREAMING_SNAKE_CASE__					,	PIL.Image.Image				):
              lowercase							:     Tuple       	=      [image]

       if isinstance(image[0]					,	PIL.Image.Image				):
              lowercase							:     List[str]       	=      [np.array(i.resize((w, h)					,	resample=PIL_INTERPOLATION["""lanczos"""]				)				)[None, :] for i in image]
              lowercase							:     Optional[Any]       	=      np.concatenate(SCREAMING_SNAKE_CASE__					,	axis=0				)
              lowercase							:     Optional[int]       	=      np.array(SCREAMING_SNAKE_CASE__				).astype(np.floataa				) / 255.0
              lowercase							:     Tuple       	=      image.transpose(0					,	3					,	1					,	2				)
              lowercase							:     Dict       	=      2.0 * image - 1.0
              lowercase							:     Optional[Any]       	=      torch.from_numpy(SCREAMING_SNAKE_CASE__				)
       elif isinstance(image[0]					,	torch.Tensor				):
              lowercase							:     Any       	=      torch.cat(SCREAMING_SNAKE_CASE__					,	dim=0				)
       return image







def 						_snake_case(  SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__=0.9995				) ->    Any:
       if not isinstance(SCREAMING_SNAKE_CASE__					,	np.ndarray				):
              lowercase							:     Optional[Any]       	=      True
              lowercase							:     Any       	=      va.device
              lowercase							:     Tuple       	=      va.cpu().numpy()
              lowercase							:     Dict       	=      va.cpu().numpy()

       lowercase							:     Any       	=      np.sum(va * va / (np.linalg.norm(SCREAMING_SNAKE_CASE__				) * np.linalg.norm(SCREAMING_SNAKE_CASE__				))				)
       if np.abs(SCREAMING_SNAKE_CASE__				) > DOT_THRESHOLD:
              lowercase							:     Any       	=      (1 - t) * va + t * va
       else:
              lowercase							:     int       	=      np.arccos(SCREAMING_SNAKE_CASE__				)
              lowercase							:     List[str]       	=      np.sin(SCREAMING_SNAKE_CASE__				)
              lowercase							:     str       	=      theta_a * t
              lowercase							:     List[Any]       	=      np.sin(SCREAMING_SNAKE_CASE__				)
              lowercase							:     int       	=      np.sin(theta_a - theta_t				) / sin_theta_a
              lowercase							:     int       	=      sin_theta_t / sin_theta_a
              lowercase							:     Dict       	=      sa * va + sa * va

       if inputs_are_torch:
              lowercase							:     Optional[int]       	=      torch.from_numpy(SCREAMING_SNAKE_CASE__				).to(SCREAMING_SNAKE_CASE__				)

       return va







def 						_snake_case(  SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__				) ->    int:
       lowercase							:     Union[str, Any]       	=      F.normalize(SCREAMING_SNAKE_CASE__					,	dim=-1				)
       lowercase							:     List[Any]       	=      F.normalize(SCREAMING_SNAKE_CASE__					,	dim=-1				)
       return (x - y).norm(dim=-1				).div(2				).arcsin().pow(2				).mul(2				)







def 						_snake_case(  SCREAMING_SNAKE_CASE__					,	SCREAMING_SNAKE_CASE__				) ->    Union[str, Any]:
       for param in model.parameters():
              lowercase							:     List[str]       	=      value




class __snake_case		(      lowerCAmelCase     ):
    def __init__(  self		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case=None		,snake_case=None		,snake_case=None		,):



           '''simple docstring'''







           super().__init__()
           self.register_modules(
               vae=snake_case		,text_encoder=snake_case		,clip_model=snake_case		,tokenizer=snake_case		,unet=snake_case		,scheduler=snake_case		,feature_extractor=snake_case		,coca_model=snake_case		,coca_tokenizer=snake_case		,coca_transform=snake_case		,)
           lowercase							:     Optional[int]       	=      (
               feature_extractor.size
               if isinstance(feature_extractor.size		,snake_case      )
               else feature_extractor.size["""shortest_edge"""]
           )
           lowercase							:     Dict       	=      transforms.Normalize(mean=feature_extractor.image_mean		,std=feature_extractor.image_std      )
           set_requires_grad(self.text_encoder		,snake_case      )
           set_requires_grad(self.clip_model		,snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self		,snake_case = "auto"      ):



           '''simple docstring'''







           if slice_size == "auto":
                  # half the attention head size is usually a good trade-off between
                  # speed and memory
                  lowercase							:     List[Any]       	=      self.unet.config.attention_head_dim // 2
           self.unet.set_attention_slice(snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self      ):



           '''simple docstring'''







           self.enable_attention_slicing(snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self      ):



           '''simple docstring'''







           set_requires_grad(self.vae		,snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self      ):



           '''simple docstring'''







           set_requires_grad(self.vae		,snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self      ):



           '''simple docstring'''







           set_requires_grad(self.unet		,snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self      ):



           '''simple docstring'''







           set_requires_grad(self.unet		,snake_case      )
    def       _SCREAMING_SNAKE_CASE       (  self		,snake_case		,snake_case		,snake_case      ):



           '''simple docstring'''







           lowercase							:     Optional[int]       	=      min(int(num_inference_steps * strength      )		,snake_case      )

           lowercase							:     List[Any]       	=      max(num_inference_steps - init_timestep		,0      )
           lowercase							:     int       	=      self.scheduler.timesteps[t_start:]

           return timesteps, num_inference_steps - t_start
    def       _SCREAMING_SNAKE_CASE       (  self		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case=None      ):



           '''simple docstring'''







           if not isinstance(snake_case		,torch.Tensor      ):
                  raise ValueError(f"`image` has to be of type `torch.Tensor` but is {type(snake_case      )}"      )

           lowercase							:     List[str]       	=      image.to(device=snake_case		,dtype=snake_case      )

           if isinstance(snake_case		,snake_case      ):
                  lowercase							:     Optional[int]       	=      [
                      self.vae.encode(image[i : i + 1]      ).latent_dist.sample(generator[i]      ) for i in range(snake_case      )
                  ]
                  lowercase							:     Tuple       	=      torch.cat(snake_case		,dim=0      )
           else:
                  lowercase							:     List[str]       	=      self.vae.encode(snake_case      ).latent_dist.sample(snake_case      )

           # Hardcode 0.18215 because stable-diffusion-2-base has not self.vae.config.scaling_factor
           lowercase							:     Any       	=      0.18_215 * init_latents
           lowercase							:     Dict       	=      init_latents.repeat_interleave(snake_case		,dim=0      )

           lowercase							:     List[str]       	=      randn_tensor(init_latents.shape		,generator=snake_case		,device=snake_case		,dtype=snake_case      )

           # get latents
           lowercase							:     Optional[int]       	=      self.scheduler.add_noise(snake_case		,snake_case		,snake_case      )
           lowercase							:     Optional[Any]       	=      init_latents

           return latents
    def       _SCREAMING_SNAKE_CASE       (  self		,snake_case      ):



           '''simple docstring'''







           lowercase							:     Dict       	=      self.coca_transform(snake_case      ).unsqueeze(0      )
           with torch.no_grad(), torch.cuda.amp.autocast():
                  lowercase							:     List[Any]       	=      self.coca_model.generate(transformed_image.to(device=self.device		,dtype=self.coca_model.dtype      )      )
           lowercase							:     int       	=      self.coca_tokenizer.decode(generated[0].cpu().numpy()      )
           return generated.split("""<end_of_text>"""      )[0].replace("""<start_of_text>"""		,""""""      ).rstrip(""" .,"""      )
    def       _SCREAMING_SNAKE_CASE       (  self		,snake_case		,snake_case      ):



           '''simple docstring'''







           lowercase							:     Optional[int]       	=      self.feature_extractor.preprocess(snake_case      )
           lowercase							:     Optional[int]       	=      torch.from_numpy(clip_image_input["""pixel_values"""][0]      ).unsqueeze(0      ).to(self.device      ).half()
           lowercase							:     List[Any]       	=      self.clip_model.get_image_features(snake_case      )
           lowercase							:     List[str]       	=      image_embeddings_clip / image_embeddings_clip.norm(p=2		,dim=-1		,keepdim=snake_case      )
           lowercase							:     Tuple       	=      image_embeddings_clip.repeat_interleave(snake_case		,dim=0      )
           return image_embeddings_clip
    @torch.enable_grad()
    def       _SCREAMING_SNAKE_CASE       (  self		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,):



           '''simple docstring'''







           lowercase							:     Optional[int]       	=      latents.detach().requires_grad_()

           lowercase							:     Optional[int]       	=      self.scheduler.scale_model_input(snake_case		,snake_case      )

           # predict the noise residual
           lowercase							:     Optional[int]       	=      self.unet(snake_case		,snake_case		,encoder_hidden_states=snake_case      ).sample

           if isinstance(self.scheduler		,(PNDMScheduler, DDIMScheduler, DPMSolverMultistepScheduler)      ):
                  lowercase							:     Optional[int]       	=      self.scheduler.alphas_cumprod[timestep]
                  lowercase							:     Union[str, Any]       	=      1 - alpha_prod_t
                  # compute predicted original sample from predicted noise also called
                  # "predicted x_0" of formula (12) from https://arxiv.org/pdf/2010.02502.pdf
                  lowercase							:     Tuple       	=      (latents - beta_prod_t ** 0.5 * noise_pred) / alpha_prod_t ** 0.5

                  lowercase							:     int       	=      torch.sqrt(snake_case      )
                  lowercase							:     Any       	=      pred_original_sample * (fac) + latents * (1 - fac)
           elif isinstance(self.scheduler		,snake_case      ):
                  lowercase							:     Dict       	=      self.scheduler.sigmas[index]
                  lowercase							:     Tuple       	=      latents - sigma * noise_pred
           else:
                  raise ValueError(f"scheduler type {type(self.scheduler      )} not supported"      )

           # Hardcode 0.18215 because stable-diffusion-2-base has not self.vae.config.scaling_factor
           lowercase							:     Optional[Any]       	=      1 / 0.18_215 * sample
           lowercase							:     Union[str, Any]       	=      self.vae.decode(snake_case      ).sample
           lowercase							:     str       	=      (image / 2 + 0.5).clamp(0		,1      )

           lowercase							:     int       	=      transforms.Resize(self.feature_extractor_size      )(snake_case      )
           lowercase							:     Tuple       	=      self.normalize(snake_case      ).to(latents.dtype      )

           lowercase							:     Tuple       	=      self.clip_model.get_image_features(snake_case      )
           lowercase							:     List[str]       	=      image_embeddings_clip / image_embeddings_clip.norm(p=2		,dim=-1		,keepdim=snake_case      )

           lowercase							:     str       	=      spherical_dist_loss(snake_case		,snake_case      ).mean() * clip_guidance_scale

           lowercase							:     List[Any]       	=      -torch.autograd.grad(snake_case		,snake_case      )[0]

           if isinstance(self.scheduler		,snake_case      ):
                  lowercase							:     Any       	=      latents.detach() + grads * (sigma**2)
                  lowercase							:     Optional[Any]       	=      noise_pred_original
           else:
                  lowercase							:     int       	=      noise_pred_original - torch.sqrt(snake_case      ) * grads
           return noise_pred, latents
    @torch.no_grad()
    def __call__(  self		,snake_case		,snake_case		,snake_case = None		,snake_case = None		,snake_case = 512		,snake_case = 512		,snake_case = 0.6		,snake_case = 50		,snake_case = 7.5		,snake_case = 1		,snake_case = 0.0		,snake_case = 100		,snake_case = None		,snake_case = "pil"		,snake_case = True		,snake_case = 0.8		,snake_case = 0.1		,snake_case = 0.1		,):



           '''simple docstring'''







           if isinstance(snake_case		,snake_case      ) and len(snake_case      ) != batch_size:
                  raise ValueError(f"You have passed {batch_size} batch_size, but only {len(snake_case      )} generators."      )

           if height % 8 != 0 or width % 8 != 0:
                  raise ValueError(f"`height` and `width` have to be divisible by 8 but are {height} and {width}."      )

           if isinstance(snake_case		,torch.Generator      ) and batch_size > 1:
                  lowercase							:     str       	=      [generator] + [None] * (batch_size - 1)

           lowercase							:     Union[str, Any]       	=      [
               ("""model""", self.coca_model is None),
               ("""tokenizer""", self.coca_tokenizer is None),
               ("""transform""", self.coca_transform is None),
           ]
           lowercase							:     Optional[int]       	=      [x[0] for x in coca_is_none if x[1]]
           lowercase							:     int       	=      """, """.join(snake_case      )
           # generate prompts with coca model if prompt is None
           if content_prompt is None:
                  if len(snake_case      ):
                         raise ValueError(
                             f"Content prompt is None and CoCa [{coca_is_none_str}] is None."
                             f"Set prompt or pass Coca [{coca_is_none_str}] to DiffusionPipeline."      )
                  lowercase							:     Optional[int]       	=      self.get_image_description(snake_case      )
           if style_prompt is None:
                  if len(snake_case      ):
                         raise ValueError(
                             f"Style prompt is None and CoCa [{coca_is_none_str}] is None."
                             f" Set prompt or pass Coca [{coca_is_none_str}] to DiffusionPipeline."      )
                  lowercase							:     str       	=      self.get_image_description(snake_case      )

           # get prompt text embeddings for content and style
           lowercase							:     List[Any]       	=      self.tokenizer(
               snake_case		,padding="""max_length"""		,max_length=self.tokenizer.model_max_length		,truncation=snake_case		,return_tensors="""pt"""		,)
           lowercase							:     List[Any]       	=      self.text_encoder(content_text_input.input_ids.to(self.device      )      )[0]

           lowercase							:     Optional[int]       	=      self.tokenizer(
               snake_case		,padding="""max_length"""		,max_length=self.tokenizer.model_max_length		,truncation=snake_case		,return_tensors="""pt"""		,)
           lowercase							:     Tuple       	=      self.text_encoder(style_text_input.input_ids.to(self.device      )      )[0]

           lowercase							:     Optional[Any]       	=      slerp(snake_case		,snake_case		,snake_case      )

           # duplicate text embeddings for each generation per prompt
           lowercase							:     str       	=      text_embeddings.repeat_interleave(snake_case		,dim=0      )

           # set timesteps
           lowercase							:     str       	=      """offset""" in set(inspect.signature(self.scheduler.set_timesteps      ).parameters.keys()      )
           lowercase							:     Tuple       	=      {}
           if accepts_offset:
                  lowercase							:     int       	=      1

           self.scheduler.set_timesteps(snake_case		,**snake_case      )
           # Some schedulers like PNDM have timesteps as arrays
           # It's more optimized to move all timesteps to correct device beforehand
           self.scheduler.timesteps.to(self.device      )

           lowercase	,			lowercase							:     Optional[int]       	=      self.get_timesteps(snake_case		,snake_case		,self.device      )
           lowercase							:     Tuple       	=      timesteps[:1].repeat(snake_case      )

           # Preprocess image
           lowercase							:     str       	=      preprocess(snake_case		,snake_case		,snake_case      )
           lowercase							:     int       	=      self.prepare_latents(
               snake_case		,snake_case		,snake_case		,text_embeddings.dtype		,self.device		,snake_case      )

           lowercase							:     List[Any]       	=      preprocess(snake_case		,snake_case		,snake_case      )
           lowercase							:     Tuple       	=      self.prepare_latents(
               snake_case		,snake_case		,snake_case		,text_embeddings.dtype		,self.device		,snake_case      )

           lowercase							:     List[str]       	=      slerp(snake_case		,snake_case		,snake_case      )

           if clip_guidance_scale > 0:
                  lowercase							:     Union[str, Any]       	=      self.get_clip_image_embeddings(snake_case		,snake_case      )
                  lowercase							:     Optional[int]       	=      self.get_clip_image_embeddings(snake_case		,snake_case      )
                  lowercase							:     Optional[int]       	=      slerp(
                      snake_case		,snake_case		,snake_case      )

           # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)
           # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`
           # corresponds to doing no classifier free guidance.
           lowercase							:     str       	=      guidance_scale > 1.0
           # get unconditional embeddings for classifier free guidance
           if do_classifier_free_guidance:
                  lowercase							:     List[str]       	=      content_text_input.input_ids.shape[-1]
                  lowercase							:     Optional[Any]       	=      self.tokenizer([""""""]		,padding="""max_length"""		,max_length=snake_case		,return_tensors="""pt"""      )
                  lowercase							:     Any       	=      self.text_encoder(uncond_input.input_ids.to(self.device      )      )[0]
                  # duplicate unconditional embeddings for each generation per prompt
                  lowercase							:     Any       	=      uncond_embeddings.repeat_interleave(snake_case		,dim=0      )

                  # For classifier free guidance, we need to do two forward passes.
                  # Here we concatenate the unconditional and text embeddings into a single batch
                  # to avoid doing two forward passes
                  lowercase							:     List[str]       	=      torch.cat([uncond_embeddings, text_embeddings]      )

           # get the initial random noise unless the user supplied it

           # Unlike in other pipelines, latents need to be generated in the target device
           # for 1-to-1 results reproducibility with the CompVis implementation.
           # However this currently doesn't work in `mps`.
           lowercase							:     Tuple       	=      (batch_size, self.unet.config.in_channels, height // 8, width // 8)
           lowercase							:     Tuple       	=      text_embeddings.dtype
           if latents is None:
                  if self.device.type == "mps":
                         # randn does not work reproducibly on mps
                         lowercase							:     str       	=      torch.randn(snake_case		,generator=snake_case		,device="""cpu"""		,dtype=snake_case      ).to(
                             self.device      )
                  else:
                         lowercase							:     Optional[int]       	=      torch.randn(snake_case		,generator=snake_case		,device=self.device		,dtype=snake_case      )
           else:
                  if latents.shape != latents_shape:
                         raise ValueError(f"Unexpected latents shape, got {latents.shape}, expected {latents_shape}"      )
                  lowercase							:     Any       	=      latents.to(self.device      )

           # scale the initial noise by the standard deviation required by the scheduler
           lowercase							:     Dict       	=      latents * self.scheduler.init_noise_sigma

           # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature
           # eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.
           # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502
           # and should be between [0, 1]
           lowercase							:     Union[str, Any]       	=      """eta""" in set(inspect.signature(self.scheduler.step      ).parameters.keys()      )
           lowercase							:     str       	=      {}
           if accepts_eta:
                  lowercase							:     str       	=      eta

           # check if the scheduler accepts generator
           lowercase							:     Optional[Any]       	=      """generator""" in set(inspect.signature(self.scheduler.step      ).parameters.keys()      )
           if accepts_generator:
                  lowercase							:     Tuple       	=      generator

           with self.progress_bar(total=snake_case      ):
                  for i, t in enumerate(snake_case      ):
                         # expand the latents if we are doing classifier free guidance
                         lowercase							:     Optional[Any]       	=      torch.cat([latents] * 2      ) if do_classifier_free_guidance else latents
                         lowercase							:     Optional[int]       	=      self.scheduler.scale_model_input(snake_case		,snake_case      )

                         # predict the noise residual
                         lowercase							:     Dict       	=      self.unet(snake_case		,snake_case		,encoder_hidden_states=snake_case      ).sample

                         # perform classifier free guidance
                         if do_classifier_free_guidance:
                                lowercase	,			lowercase							:     str       	=      noise_pred.chunk(2      )
                                lowercase							:     Optional[int]       	=      noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)

                         # perform clip guidance
                         if clip_guidance_scale > 0:
                                lowercase							:     int       	=      (
                                    text_embeddings.chunk(2      )[1] if do_classifier_free_guidance else text_embeddings
                                )
                                lowercase	,			lowercase							:     Union[str, Any]       	=      self.cond_fn(
                                    snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,snake_case		,)

                         # compute the previous noisy sample x_t -> x_t-1
                         lowercase							:     Any       	=      self.scheduler.step(snake_case		,snake_case		,snake_case		,**snake_case      ).prev_sample

        # Hardcode 0.18215 because stable-diffusion-2-base has not self.vae.config.scaling_factor
           lowercase							:     Optional[Any]       	=      1 / 0.18_215 * latents
           lowercase							:     Any       	=      self.vae.decode(snake_case      ).sample

           lowercase							:     Optional[Any]       	=      (image / 2 + 0.5).clamp(0		,1      )
           lowercase							:     Optional[Any]       	=      image.cpu().permute(0		,2		,3		,1      ).numpy()

           if output_type == "pil":
                  lowercase							:     List[str]       	=      self.numpy_to_pil(snake_case      )

           if not return_dict:
                  return (image, None)

           return StableDiffusionPipelineOutput(images=snake_case		,nsfw_content_detected=snake_case      )

def    __lowercase     (						lowerCamelCase					:     str  ,  lowerCamelCase					:     str	):

 def get_matched_characters(lowerCamelCase					:     str  ,  lowerCamelCase					:     str	) -> str:
  UpperCamelCase_					:						Tuple =					[]
  UpperCamelCase_					:						List[Any] =					min(len(_stra	)  ,  len(_stra	)	) // 2
  for i, l in enumerate(_stra	):
   UpperCamelCase_					:						int =					int(max(0  ,  i - limit	)	)
   UpperCamelCase_					:						Dict =					int(min(i + limit + 1  ,  len(_stra	)	)	)
   if l in _stra[left:right]:
    matched.append(lowerCamelCase	)
    UpperCamelCase_					:						Dict =					F"{_stra[0:_stra.index(lowerCamelCase	)]} {_stra[_stra.index(lowerCamelCase	) + 1:]}"

  return "".join(lowerCamelCase	)

 # matching characters
 UpperCamelCase_					:						str =					get_matched_characters(lowerCamelCase  ,  lowerCamelCase	)
 UpperCamelCase_					:						str =					get_matched_characters(lowerCamelCase  ,  lowerCamelCase	)
 UpperCamelCase_					:						Union[str, Any] =					len(lowerCamelCase	)

 # transposition
 UpperCamelCase_					:						int =					(
     len([(ca, ca) for ca, ca in zip(lowerCamelCase  ,  lowerCamelCase	) if ca != ca]	) // 2
 )

 if not match_count:
  UpperCamelCase_					:						Union[str, Any] =					0.0
 else:
  UpperCamelCase_					:						str =					(
      1
      / 3
      * (
          match_count / len(lowerCamelCase	)
          + match_count / len(lowerCamelCase	)
          + (match_count - transpositions) / match_count
      )
  )

 # common prefix up to 4 characters
 UpperCamelCase_					:						Dict =					0
 for ca, ca in zip(stra[:4]  ,  stra[:4]	):
  if ca == ca:
   prefix_len += 1
  else:
   break

 return jaro + 0.1 * prefix_len * (1 - jaro)


if __name__ == "__main__":
   import doctest

   doctest.testmod()
   print(jaro_winkler('hello', 'world'))



