diff --git a/CHANGELOG.md b/CHANGELOG.md index 95107a94f..68ad17ed5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,12 +20,17 @@ *note*: this is a breaking change - if you had custom attention settings in previous releases, you will need to re-apply them in the new settings section - new `sparse-attention` method that can be combined with other attention methods to reduce memory usage and improve performance on large models +- **Modular Pipelines** + - *TODO*: see [Modular Pipelines docs](https://vladmandic.github.io/sdnext-docs/Modular-Pipelines) for details and usage instructions + - implement progress and preview + - intercept and profiling hooks + - full modular guidance + - on-demand convert standard model on-demand - **Internal** - - modular pipelines intercept and profiling hooks - - modular pipelines convert standard model on-demand - - modular pipelines previews - - modular pipelines basic guidance - attention mechanisms decision tree and apply method refactor +- **Fixes** + - unnecessary secondary prompt + - js fetch exception handling ## Update for 2026-08-26 diff --git a/TODO.md b/TODO.md index ffa870508..798cef684 100644 --- a/TODO.md +++ b/TODO.md @@ -3,14 +3,18 @@ ## Short-term - MiniMax LoRA: native loader for MiniMax-H3: fl2va, ref2va, pruned, @CalamitousFelicitousness -- MiniMax TAESD: need to unpack latents, @vladmandic -- MiniMax: Create pre-quant for MiniMax-H3-Turbo +- MiniMax TAESD: unpack latents, @vladmandic +- MiniMax: Create pre-quants for MiniMax-H3-Turbo, MiniMax-H3-Pruned-Turbo - Benchmark tool productize: @CalamitousFelicitousness -- Inpaint: https://discord.com/channels/1101998836328697867/1130536562422186044/1506850651035144322, @vladmandic - Control tab verify overrides handling, @vladmandic - LTX: Create pre-quant for LTX-2.5 -- Modular guiders, @vladmandic - ROCm: v10 +- Modular: cache hooks, @vladmandic +- Modular: disable legacy PAG, etc., @vladmandic + +## Issues + +- Inpaint: https://discord.com/channels/1101998836328697867/1130536562422186044/1506850651035144322, @vladmandic ## Features @@ -27,7 +31,6 @@ - Video upscaling: LTX-Upscaler - Video capabilities to processing tab, add RIFE, upscaling (once available) - Distraction-free UI mode with prompt-only, chat-based interface -- Revisit transformer caching for modular pipelines - Video models: support finetunes - Incorporate [prompting guides](https://github.com/CalamitousFelicitousness/ai-prompting-guides) - Video models: use Networks/Reference instead of custom @@ -49,15 +52,6 @@ - Unify *huggingface* and *diffusers* model folders - JSON image metadata -### Modular - -- Switch to modular pipelines -- Feature: Transformers unified cache handler -- [MagCache](https://github.com/huggingface/diffusers/pull/12744) -- [SmoothCache](https://github.com/huggingface/diffusers/issues/11135) -- [STG](https://github.com/huggingface/diffusers/blob/main/examples/community/README.md#spatiotemporal-skip-guidance) -- [TextKVCache](https://huggingface.co/NucleusAI/Nucleus-Image#quick-start), @vladmandic - ## New models / Pipelines TODO: Investigate which models are diffusers-compatible and prioritize! diff --git a/extensions-builtin/sdnq b/extensions-builtin/sdnq index f18fbf08a..0d0b5d204 160000 --- a/extensions-builtin/sdnq +++ b/extensions-builtin/sdnq @@ -1 +1 @@ -Subproject commit f18fbf08a5987e9f3f166cd837298e738d2bb881 +Subproject commit 0d0b5d20477caf0b56ea97eaed50e7ac2561b018 diff --git a/modules/control/run.py b/modules/control/run.py index a64fabe60..02c186d55 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -350,9 +350,8 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg styles: list[str] | None = None, steps: int = 20, sampler_index: int | None = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, - guidance_name: str = 'Default', guidance_scale: float = 6.0, guidance_rescale: float = 0.0, guidance_start: float = 0.0, guidance_stop: float = 1.0, - cfg_scale: float = 6.0, clip_skip: float = 1.0, cfg_image: float = 6.0, cfg_rescale: float = 0.7, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, cfg_end: float = 1.0, - vae_type: str = 'Full', tiling: bool = False, hidiffusion: bool = False, + cfg_name: str = 'Default', cfg_scale: float = 6.0, cfg_image: float = 6.0, cfg_rescale: float = 0.0, cfg_start: float = 0.0, cfg_stop: float = 1.0, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, + clip_skip: float = 1.0, vae_type: str = 'Full', tiling: bool = False, hidiffusion: bool = False, detailer_enabled: bool = False, detailer_prompt: str = '', detailer_negative: str = '', detailer_steps: int = 10, detailer_strength: float = 0.3, detailer_resolution: int = 1024, detailer_classes: str = '', hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundary: float = 1.0, hdr_color_picker: str | None = None, hdr_tint_ratio: float = 0, hdr_apply_hires: bool = True, @@ -465,21 +464,17 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg seed_resize_from_w = seed_resize_from_w, denoising_strength = denoising_strength, skip_processing = skip_processing, - # modular guidance - guidance_name = guidance_name, - guidance_scale = guidance_scale, - guidance_rescale = guidance_rescale, - guidance_start = guidance_start, - guidance_stop = guidance_stop, - # legacy guidance + # guidance + cfg_name = cfg_name, cfg_scale = cfg_scale, - cfg_end = cfg_end, - clip_skip = clip_skip, cfg_image = cfg_image, cfg_rescale = cfg_rescale, + cfg_start = cfg_start, + cfg_stop = cfg_stop, cfg_true = cfg_true, cfg_adaptive = cfg_adaptive, # advanced + clip_skip = clip_skip, vae_type = vae_type, tiling = tiling, hidiffusion = hidiffusion, @@ -852,7 +847,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg debug_log(f'Ready: {image_txt}') html_txt = f'
Ready {image_txt}
' if image_txt != '' else '' - if len(info_txt) > 0: + if (info_txt is not None) and (len(info_txt) > 0): html_txt = html_txt + infotext_to_html(info_txt[0]) result = (output_images, blended_image, html_txt, output_filename) if is_generator: diff --git a/modules/img2img.py b/modules/img2img.py index 70d7e48cc..6c178da85 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -163,8 +163,7 @@ def img2img(id_task: str, state: str, mode: int, vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, n_iter, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, refiner_start, clip_skip, denoising_strength, @@ -261,13 +260,6 @@ def img2img(id_task: str, state: str, mode: int, batch_size=batch_size, n_iter=n_iter, steps=steps, - guidance_name=guidance_name, - guidance_scale=guidance_scale, - guidance_rescale=guidance_rescale, - guidance_start=guidance_start, - guidance_stop=guidance_stop, - cfg_scale=cfg_scale, - cfg_end=cfg_end, clip_skip=clip_skip, width=width, height=height, @@ -289,10 +281,6 @@ def img2img(id_task: str, state: str, mode: int, resize_context=resize_context, scale_by=scale_by, denoising_strength=denoising_strength, - cfg_image=cfg_image, - cfg_rescale=cfg_rescale, - cfg_true=cfg_true, - cfg_adaptive=cfg_adaptive, refiner_start=refiner_start, inpaint_full_res=inpaint_full_res != 0, inpaint_full_res_padding=inpaint_full_res_padding, @@ -306,6 +294,15 @@ def img2img(id_task: str, state: str, mode: int, grading_shadows_tint=grading_shadows_tint, grading_highlights_tint=grading_highlights_tint, grading_split_tone_balance=grading_split_tone_balance, grading_vignette=grading_vignette, grading_grain=grading_grain, grading_lut_file=grading_lut_file.name if grading_lut_file is not None else '', grading_lut_strength=grading_lut_strength, + # guidance + cfg_name=cfg_name, + cfg_scale=cfg_scale, + cfg_image=cfg_image, + cfg_rescale=cfg_rescale, + cfg_start=cfg_start, + cfg_stop=cfg_stop, + cfg_true=cfg_true, + cfg_adaptive=cfg_adaptive, # refiner enable_hr=enable_hr, hr_denoising_strength=hr_denoising_strength, diff --git a/modules/modular.py b/modules/modular.py index 3916ca210..f0b4b2d3c 100644 --- a/modules/modular.py +++ b/modules/modular.py @@ -1,15 +1,20 @@ import os import diffusers -from modules import shared, sd_hijack_modular +from modules import shared, sd_hijack_modular, sd_models from modules.logger import log debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None +exclude = ['Krea2'] def get_modular_class(diffusion_pipeline: diffusers.DiffusionPipeline): name = diffusion_pipeline.__class__.__name__ name = name.replace('Pipeline', '').replace('Img2Img', '').replace('Inpaint', '').replace('ImageToVideo', '') + if name in exclude: + if debug: + log.trace(f'Modular lookup: key={name} source={diffusion_pipeline.__class__.__name__} excluded') + return None name = f'{name}AutoBlocks' modular_cls = getattr(diffusers, name, None) if debug: @@ -46,6 +51,7 @@ def convert_to_modular(diffusion_pipeline: diffusers.DiffusionPipeline) -> diffu except Exception as e: log.error(f'Modular: {e}') raise e + sd_models.copy_diffuser_options(modular_pipe, diffusion_pipeline) sd_hijack_modular.install_state_hook(modular_pipe) sd_hijack_modular.register_callbacks(modular_pipe) return modular_pipe diff --git a/modules/modular_guiders.py b/modules/modular_guiders.py index 5ce8442e0..92bb43a97 100644 --- a/modules/modular_guiders.py +++ b/modules/modular_guiders.py @@ -19,91 +19,113 @@ guiders = { } -def set_guider(p: processing.StableDiffusionProcessing): - guidance_name = p.guidance_name or 'Default' +def get_layers(layer_str: str): + if not layer_str: + return [] + try: + # layers can be comma separated, e.g. "7, 8, 9" or range "7-9" or mixed "7, 8-10, 12" + layers = [] + for part in layer_str.split(','): + part = part.strip() + if '-' in part: + start, end = part.split('-') + layers.extend(range(int(start), int(end) + 1)) + elif part.isdigit(): + layers.append(int(part)) + layers = sorted(set(layers)) # remove duplicates and sort + return layers + except Exception as e: + log.error(f'Guiders layers: {e}') + return [] + + +def set_args(guidance_name: str): + args = {} + import modules.ui_guidance + inputs = modules.ui_guidance.get_modular_args() + # for k, v in inputs.items(): + # log.trace(f'Guiders: arg={k} value={v}') + if guidance_name.startswith('Default'): + pass + if guidance_name.startswith('CFG:'): + pass + if guidance_name.startswith('Auto:'): + args['dropout'] = float(inputs.get('autoguidance_dropout', 1.0)) + args['auto_guidance_layers'] = get_layers(inputs.get('autoguidance_layers', [])) + if guidance_name.startswith('Zero:'): + args['zero_init_steps'] = int(inputs.get('zerostar_init_steps', 1)) + if guidance_name.startswith('PAG:'): + args['perturbed_guidance_scale'] = float(inputs.get('pag_scale', 1.0)) + args['perturbed_guidance_start'] = float(inputs.get('pag_start', 0.01)) + args['perturbed_guidance_stop'] = float(inputs.get('pag_stop', 0.2)) + args['perturbed_guidance_layers'] = get_layers(inputs.get('pag_layers', [])) + if guidance_name.startswith('APG:'): + args['adaptive_projected_guidance_momentum'] = float(inputs.get('apg_momentum', None)) if inputs.get('apg_momentum', -1) >= 0 else None + args['adaptive_projected_guidance_rescale'] = float(inputs.get('apg_rescale', 15.0)) + if guidance_name.startswith('SLG:'): + args['skip_layer_guidance_scale'] = float(inputs.get('slg_scale', 1.0)) + args['skip_layer_guidance_start'] = float(inputs.get('slg_start', 0.01)) + args['skip_layer_guidance_stop'] = float(inputs.get('slg_stop', 0.2)) + args['skip_layer_guidance_layers'] = get_layers(inputs.get('slg_layers', [])) + if guidance_name.startswith('SEG:'): + args['seg_guidance_scale'] = float(inputs.get('seg_scale', 3.0)) + args['seg_blur_sigma'] = float(inputs.get('seg_blur_sigma', 9999999.0)) + args['seg_blur_threshold_inf'] = float(inputs.get('seg_blur_threshold_inf', 9999.0)) + args['seg_guidance_start'] = float(inputs.get('seg_start', 0.0)) + args['seg_guidance_stop'] = float(inputs.get('seg_stop', 1.0)) + args['seg_guidance_layers'] = get_layers(inputs.get('seg_layers', [])) + if guidance_name.startswith('TCFG:'): + pass + if guidance_name.startswith('FDG:'): + args['guidance_scales'] = [float(x.strip()) for x in inputs.get('fdg_scales', '5.0').split(',')] + args['parallel_weights'] = float(inputs.get('fdg_weights', 1.0)) + args['guidance_rescale_space'] = inputs.get('fdg_rescale_space', 'data') + log.trace(f'Guiders: args={args}') + return args + + +def set_guider(p: processing.StableDiffusionProcessing, phase: str | None = None): + guidance_name = p.cfg_name or 'Default' if guidance_name not in guiders: return - if guidance_name == 'Default': - if hasattr(shared.sd_model, 'default_guider'): - guider_info = shared.sd_model.default_guider - guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) - shared.sd_model.update_components(guider=guider_info) - elif hasattr(shared.sd_model, 'get_component_spec'): - guider_info = shared.sd_model.get_component_spec("guider") - guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) - shared.sd_model.default_guider = guider_info - elif hasattr(shared.sd_model, 'guider') and hasattr(shared.sd_model.guider, 'config'): - guider_info = shared.sd_model.guider - guider_cls = type(shared.sd_model.guider) - # shared.sd_model.default_guider = guider_info - else: - guider_info = None - guider_cls = None - if guider_info is not None and guider_cls is not None and guider_info.config is not None: - guider_args = {k: v for k, v in guider_info.config.items() if not k.startswith('_') and v is not None} - else: - guider_args = {} - log.info(f'Guider: name="{guidance_name}" cls={guider_cls.__name__ if guider_cls is not None else None} args={guider_args}') - return + if not hasattr(shared.sd_model, 'default_guider'): # store default guider + guider_info = shared.sd_model.get_component_spec("guider") + guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) + shared.sd_model.default_guider = guider_cls + if guidance_name == 'None': shared.sd_model.update_components(guider=None) # breaks the pipeline - log.info(f'Guider: name="{guidance_name}"') + log.info(f'Pipeline: guidance="{guidance_name}"') return + elif guidance_name == 'Default': + guider_cls = shared.sd_model.default_guider + else: + guider_info = guiders[guidance_name] + guider_cls = guider_info['cls'] - guider_info = guiders[guidance_name] - guider_cls = guider_info['cls'] + guider_args = set_args(guidance_name) + possible = inspect.signature(guider_cls.__init__).parameters if guider_cls is not None else [] + if 'guidance_scale' in list(possible): + if (phase == 'hires' or phase == 'refine') and p.cfg_image >= 0.0: + guider_args['guidance_scale'] = float(p.cfg_image) + elif p.cfg_scale >= 0.0: + guider_args['guidance_scale'] = float(p.cfg_scale) + if p.cfg_rescale >= 0.0 and 'guidance_rescale' in list(possible): + guider_args['guidance_rescale'] = float(p.cfg_rescale) + if p.cfg_start >= 0.0 and 'start' in list(possible): + guider_args['start'] = float(p.cfg_start) + if p.cfg_stop >= 0.0 and 'stop' in list(possible): + guider_args['stop'] = float(p.cfg_stop) - guider_args = {} - possible = list(inspect.signature(guider_cls.__init__).parameters) if guider_cls is not None else [] - if p.guidance_scale >= 0.0 and 'guidance_scale' in possible: - guider_args['guidance_scale'] = float(p.guidance_scale) - if p.guidance_rescale >= 0.0 and 'guidance_rescale' in possible: - guider_args['guidance_rescale'] = float(p.guidance_rescale) - if p.guidance_start >= 0.0 and 'start' in possible: - guider_args['start'] = float(p.guidance_start) - if p.guidance_stop >= 0.0 and 'stop' in possible: - guider_args['stop'] = float(p.guidance_stop) - - """ - import modules.ui_guidance - for k, v in modules.ui_guidance.get_modular_args().items(): - log.trace(f'Guiders: arg={k} value={v}') - """ - - log.warning('Guiders: advanced parameters are not yet implemented') # TODO: guiders - """ - for k, v in guider_info['args'].items(): - try: - if k is None: - pass - elif k.endswith('_layers') and isinstance(v, str): - guider_args[k] = [int(x.strip()) for x in v.split(',') if x.strip().isdigit()] - elif k.endswith('_config'): - # if lsc_enabled - # guider_args[k] = diffusers.LayerSkipConfig(...) - pass - elif isinstance(v, list) and len(v) > 0: - guider_args[k] = v - elif isinstance(v, int) and (v >= 0): - guider_args[k] = int(v) - elif isinstance(v, float) and (v >= 0.0): - guider_args[k] = float(v) - elif isinstance(v, str) and (len(v) > 0): - guider_args[k] = v - except Exception as e: - log.error(f'Guiders: arg={k} value={v} error={e}') - errors.display(e, 'Guiders') - # guider_args.update(guider_info['args']) - """ if guider_cls is not None: try: guider_instance: diffusers.BaseGuidance = guider_cls(**guider_args) - log.info(f'Guider: name="{guidance_name}" cls={guider_cls.__name__} args={guider_args}') + log.info(f'Pipeline: guidance="{guidance_name}" cls={guider_cls.__name__} args={guider_args}') shared.sd_model.update_components(guider=guider_instance) except Exception as e: - log.error(f'Guider: name="{guidance_name}" cls={guider_cls.__name__} args={guider_args} {e}') + log.error(f'Pipeline: guidance="{guidance_name}" cls={guider_cls.__name__} args={guider_args} {e}') errors.display(e, 'Guiders') return else: - log.warning(f'Guider: name="{guidance_name}" cls=None args={guider_args}') + log.warning(f'Pipeline: guidance="{guidance_name}" cls=None args={guider_args}') diff --git a/modules/processing.py b/modules/processing.py index fbb2f68a1..7f5eb0557 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -53,9 +53,14 @@ class Processed: self.height = p.height if hasattr(p, 'height') else (self.images[0].height if len(self.images) > 0 else 0) self.sampler_name = p.sampler_name or '' + + self.cfg_name = p.cfg_name if (p.cfg_name is not None and p.cfg_name != 'Default') else None self.cfg_scale = p.cfg_scale if (p.cfg_scale is not None and p.cfg_scale > -1) else None - self.cfg_end = p.cfg_end if p.cfg_end < 1 else None + self.cfg_rescale = p.cfg_rescale if (p.cfg_rescale is not None and p.cfg_rescale > -1) else None self.cfg_image = p.cfg_image if (p.cfg_image is not None and p.cfg_image > -1) else None + self.cfg_start = p.cfg_start if p.cfg_start > 0 else None + self.cfg_stop = p.cfg_stop if p.cfg_stop < 1 else None + self.steps = p.steps or 0 self.batch_size = max(1, p.batch_size) self.denoising_strength = p.denoising_strength @@ -103,8 +108,12 @@ class Processed: "width": self.width, "height": self.height, "sampler_name": self.sampler_name, + "cfg_name": self.cfg_name, "cfg_scale": self.cfg_scale, - "cfg_end": self.cfg_end, + "cfg_rescale": self.cfg_rescale, + "cfg_image": self.cfg_image, + "cfg_start": self.cfg_start, + "cfg_stop": self.cfg_stop, "steps": self.steps, "batch_size": self.batch_size, "detailer": self.detailer, diff --git a/modules/processing_args.py b/modules/processing_args.py index 115bc6c61..52a68cdce 100644 --- a/modules/processing_args.py +++ b/modules/processing_args.py @@ -31,6 +31,9 @@ def task_modular_kwargs(p, model): if len(getattr(p, 'init_images', [])) > 0: task_args['image'] = p.init_images task_args['strength'] = p.denoising_strength + if (shared.sd_model_type == 'sdxl') and hasattr(model, 'register_to_config') and (model_cls not in sd_models.i2i_pipes): + model.register_to_config(requires_aesthetics_score = False) + mask_image = p.task_args.get('image_mask', None) or getattr(p, 'image_mask', None) or getattr(p, 'mask', None) if mask_image is not None: task_args['mask_image'] = mask_image @@ -68,8 +71,8 @@ def task_specific_kwargs(p, model): 'width': width, 'height': height, } - elif (task_type == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: - if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'): + elif (task_type == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or task_type == sd_models.DiffusersTaskType.MODULAR or is_img2img_model) and (len(getattr(p, 'init_images', [])) > 0): + if (shared.sd_model_type == 'sdxl') and hasattr(model, 'register_to_config'): if model_cls in sd_models.i2i_pipes: pass else: @@ -115,7 +118,7 @@ def task_specific_kwargs(p, model): 'image': p.init_images, 'strength': p.denoising_strength, } - elif (task_type == sd_models.DiffusersTaskType.INPAINTING or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: + elif (task_type == sd_models.DiffusersTaskType.INPAINTING or task_type == sd_models.DiffusersTaskType.MODULAR or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'): if model_cls in [sd_models.i2i_pipes]: pass @@ -255,7 +258,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l possible = get_params(model) - log.debug(f'Pipeline: cls={cls} possible={possible}') + debug_log(f'Pipeline: cls={cls} possible={possible}') steps = kwargs.get("num_inference_steps", None) or len(getattr(p, 'timesteps', ['1'])) clip_skip = kwargs.pop("clip_skip", 1) diff --git a/modules/processing_callbacks.py b/modules/processing_callbacks.py index 1cc11dde5..9c0cefd2b 100644 --- a/modules/processing_callbacks.py +++ b/modules/processing_callbacks.py @@ -120,11 +120,11 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | No if step == 0: pipe._cfg_end_applied = False # pylint: disable=protected-access - cfg_end = getattr(p, "cfg_end", 1.0) or 1.0 + cfg_stop = getattr(p, "cfg_stop", None) or getattr(p, "cfg_end", None) or 1.0 total_steps = getattr(pipe, "num_timesteps", 0) - target_step = int(total_steps * cfg_end) if total_steps else 0 + target_step = int(total_steps * cfg_stop) if total_steps else 0 - if (cfg_end < 1.0) and not getattr(pipe, "_cfg_end_applied", False) and (step >= target_step): + if (cfg_stop < 1.0) and not getattr(pipe, "_cfg_end_applied", False) and (step >= target_step): pipe._cfg_end_applied = True # pylint: disable=protected-access if "PAG" in shared.sd_model.__class__.__name__: pipe._guidance_scale = 1.001 if pipe._guidance_scale > 1 else pipe._guidance_scale # pylint: disable=protected-access diff --git a/modules/processing_class.py b/modules/processing_class.py index 624e874b7..9b05182e8 100644 --- a/modules/processing_class.py +++ b/modules/processing_class.py @@ -45,15 +45,11 @@ class StableDiffusionProcessing: sampler_name: str | None = None, hr_sampler_name: str | None = None, eta: float | None = None, - # modular guidance - guidance_name: str = 'Default', - guidance_scale: float = 6.0, - guidance_rescale: float = 0.0, - guidance_start: float = 0.0, - guidance_stop: float = 1.0, - # legacy guidance + # guidance + cfg_name: str = 'Default', cfg_scale: float = 6.0, - cfg_end: float = 1, + cfg_start: float = 0.0, + cfg_stop: float = 1, cfg_rescale: float = 0.0, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, @@ -457,16 +453,6 @@ class StableDiffusionProcessing: self.do_not_save_grid = do_not_save_grid self.override_settings_restore_afterwards = override_settings_restore_afterwards self.eta = eta - self.guidance_name = guidance_name - self.guidance_scale = guidance_scale - self.guidance_rescale = guidance_rescale - self.guidance_start = guidance_start - self.guidance_stop = guidance_stop - self.cfg_scale = cfg_scale - self.cfg_end = cfg_end - self.cfg_rescale = cfg_rescale - self.cfg_true = cfg_true - self.cfg_adaptive = cfg_adaptive self.selected_scale_tab = selected_scale_tab self.mask_for_overlay = mask_for_overlay self.paste_to = paste_to @@ -510,6 +496,15 @@ class StableDiffusionProcessing: log.error(f'Override: {override_settings} {e}') self.override_settings = {} + # guidance + self.cfg_name = cfg_name + self.cfg_scale = cfg_scale + self.cfg_start = cfg_start + self.cfg_stop = cfg_stop + self.cfg_rescale = cfg_rescale + self.cfg_true = cfg_true + self.cfg_adaptive = cfg_adaptive + # scheduler/noise overrides self.schedulers_prediction_type = schedulers_prediction_type self.schedulers_beta_schedule = schedulers_beta_schedule diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 9ff88d4d1..ec172aea3 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -3,8 +3,9 @@ import os import time import numpy as np import torch +import diffusers from PIL import Image -from modules import shared, processing, sd_models, errors, sd_hijack_hypertile, processing_vae, sd_models_compile, timer, modelstats, extra_networks, attention +from modules import shared, processing, sd_models, errors, sd_hijack_hypertile, processing_vae, sd_models_compile, timer, modelstats, extra_networks, attention, modular from modules.logger import log from modules.processing_helpers import resize_hires, calculate_base_steps, calculate_hires_steps, calculate_refiner_steps, save_intermediate, update_sampler, is_txt2img, is_refiner_enabled, get_job_name from modules.processing_args import set_pipeline_args @@ -14,6 +15,7 @@ from modules.image import convert debug = os.environ.get('SD_DIFFUSERS_DEBUG', None) is not None +modular_debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None output_type = 'np' if os.environ.get('SD_VAE_DEFAULT', None) is not None else 'latent' last_p = None orig_pipeline = shared.sd_model @@ -68,12 +70,12 @@ def restore_state(p: processing.StableDiffusionProcessing): return p -def process_pre(p: processing.StableDiffusionProcessing): +def process_pre(p: processing.StableDiffusionProcessing, phase: str | None = None): from modules import ipadapter, sd_hijack_freeu, para_attention, teacache, hidiffusion, ras, pag, cfgzero, transformer_cache, token_merge, linfusion, cachedit if shared.sd_model is None: log.warning('Processing modifiers: model not loaded') return - log.info('Processing modifiers: apply') + log.info(f'Processing modifiers: phase={phase} apply') try: # apply-with-unapply # sd_hijack_compile.install() @@ -97,19 +99,10 @@ def process_pre(p: processing.StableDiffusionProcessing): errors.display(e, 'apply') shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model) - # if hasattr(shared.sd_model, 'unet'): - # sd_models.move_model(shared.sd_model.unet, devices.device) - # if hasattr(shared.sd_model, 'transformer'): - # sd_models.move_model(shared.sd_model.transformer, devices.device) - from modules import modular - if modular.is_compatible(shared.sd_model): - modular_pipe = modular.convert_to_modular(shared.sd_model) - if modular_pipe is not None: - shared.sd_model = modular_pipe if modular.is_guider(shared.sd_model): from modules import modular_guiders - modular_guiders.set_guider(p) + modular_guiders.set_guider(p, phase) timer.process.record('pre') @@ -143,7 +136,7 @@ def process_base(p: processing.StableDiffusionProcessing): shared.sd_model = update_pipeline(shared.sd_model, p) update_sampler(p, shared.sd_model) timer.process.record('prepare') - process_pre(p) + process_pre(p, 'base') sched_eta = p.scheduler_eta if p.scheduler_eta is not None else shared.opts.scheduler_eta desc = 'Base' if 'detailer' in p.ops: @@ -186,6 +179,8 @@ def process_base(p: processing.StableDiffusionProcessing): taskid = shared.state.begin('Inference') output = shared.sd_model(**base_args) shared.state.end(taskid) + if isinstance(output, diffusers.modular_pipelines.PipelineState) and modular_debug: + log.trace(f'Pipeline: output={output}') if isinstance(output, dict): output = SimpleNamespace(**output) if isinstance(output, list): @@ -194,7 +189,7 @@ def process_base(p: processing.StableDiffusionProcessing): output = SimpleNamespace(images=[output]) if not hasattr(output, 'frames') and hasattr(output, 'videos'): output.frames = output.videos # modular video pipelines emit videos, not frames - if hasattr(output, 'image'): + if hasattr(output, 'image') and getattr(output, 'images', None) is None: # for modular output.image may be input and output.images may be output so we dont want to overwrite output output.images = output.image if hasattr(output, 'images'): shared.history.add(output.images, info=processing.create_infotext(p), ops=p.ops) @@ -303,7 +298,7 @@ def process_hires(p: processing.StableDiffusionProcessing, output): orig_denoise = p.denoising_strength p.denoising_strength = strength orig_image = p.task_args.pop('image', None) # remove image override from hires - process_pre(p) + process_pre(p, 'hires') prompts = p.prompts reset_prompts = False diff --git a/modules/processing_info.py b/modules/processing_info.py index dca52112e..719fec0c6 100644 --- a/modules/processing_info.py +++ b/modules/processing_info.py @@ -59,9 +59,11 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No "Scheduler": shared.sd_model.scheduler.__class__.__name__ if getattr(shared.sd_model, 'scheduler', None) is not None else None, "Seed": all_seeds[index], "Seed resize from": None if p.seed_resize_from_w <= 0 or p.seed_resize_from_h <= 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}", + "CFG name": p.cfg_name if p.cfg_name != 'Default' else None, "CFG scale": p.cfg_scale if p.cfg_scale > -1 else None, "CFG rescale": p.cfg_rescale if p.cfg_rescale > -1 else None, - "CFG end": p.cfg_end if p.cfg_end < 1.0 else None, + "CFG start": p.cfg_start if p.cfg_start > 0.0 else None, + "CFG stop": p.cfg_stop if p.cfg_stop < 1.0 else None, "CFG true": p.cfg_true if p.cfg_true > 0 else None, "CFG adaptive": p.cfg_adaptive if p.cfg_adaptive != 0.5 else None, "CLiP-skip": p.clip_skip if p.clip_skip > 1 else None, diff --git a/modules/processing_prompt.py b/modules/processing_prompt.py index 6eac4a8bf..6df19a4be 100644 --- a/modules/processing_prompt.py +++ b/modules/processing_prompt.py @@ -68,11 +68,13 @@ def set_fallback_prompt(args: dict, possible: list[str], prompts, negative_promp debug_log(f'Prompt fallback: negative_prompt={negative_prompts}') args['negative_prompt'] = negative_prompts if ('prompt_2' in possible) and ('prompt_2' not in args) and (prompts_2 is not None) and len(prompts_2) > 0: - debug_log(f'Prompt fallback: prompt_2={prompts_2}') - args['prompt_2'] = prompts_2 + if (prompts_2 != prompts) and (prompts_2 != args.get('prompt', None)): + debug_log(f'Prompt fallback: prompt_2={prompts_2}') + args['prompt_2'] = prompts_2 if ('negative_prompt_2' in possible) and ('negative_prompt_2' not in args) and (negative_prompts_2 is not None) and len(negative_prompts_2) > 0: - debug_log(f'Prompt fallback: negative_prompt_2={negative_prompts_2}') - args['negative_prompt_2'] = negative_prompts_2 + if (negative_prompts_2 != negative_prompts) and (negative_prompts_2 != args.get('negative_prompt', None)): + debug_log(f'Prompt fallback: negative_prompt_2={negative_prompts_2}') + args['negative_prompt_2'] = negative_prompts_2 return args diff --git a/modules/safe.py b/modules/safe.py index d97721bf6..89b14ee45 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -5,9 +5,9 @@ import collections import zipfile import re +import _codecs import torch import numpy as np -import _codecs # PyTorch 1.13 and later have _TypedStorage renamed to TypedStorage TypedStorage = torch.storage.TypedStorage if hasattr(torch.storage, 'TypedStorage') else torch.storage._TypedStorage # pylint: disable=protected-access diff --git a/modules/sd_models.py b/modules/sd_models.py index a21877dc8..327f231a2 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1034,6 +1034,12 @@ def load_diffuser(checkpoint_info: CheckpointInfo | None = None, op='model', rev if debug_load: log.trace(f'Model components: {list(get_signature(sd_model).values())}') + from modules import modular + if modular.is_compatible(shared.sd_model): + modular_pipe = modular.convert_to_modular(shared.sd_model) + if modular_pipe is not None: + shared.sd_model = modular_pipe + from modules import textual_inversion sd_model.embedding_db = textual_inversion.EmbeddingDatabase() sd_model.embedding_db.add_embedding_dir(shared.opts.embeddings_dir) @@ -1244,7 +1250,7 @@ def switch_pipe(cls: type[diffusers.DiffusionPipeline] | str, pipeline: diffuser def clean_diffuser_pipe(pipe): - if pipe is not None and shared.sd_model_type == 'sdxl' and hasattr(pipe, 'config') and 'requires_aesthetics_score' in pipe.config and hasattr(pipe, '_internal_dict'): + if (pipe is not None) and (shared.sd_model_type == 'sdxl') and hasattr(pipe, 'config') and ('requires_aesthetics_score' in pipe.config) and hasattr(pipe, '_internal_dict'): debug_process(f'Pipeline clean: {pipe.__class__.__name__}') # diffusers adds requires_aesthetics_score with img2img and complains if requires_aesthetics_score exist in txt2img internal_dict = dict(pipe._internal_dict) # pylint: disable=protected-access diff --git a/modules/taesd/taehv.py b/modules/taesd/taehv.py index 9239ac864..8b65e41cd 100644 --- a/modules/taesd/taehv.py +++ b/modules/taesd/taehv.py @@ -337,6 +337,8 @@ class TAEHV(nn.Module): def decode(self, x, parallel=True, show_progress_bar=False, return_dict=False): # pylint: disable=unused-argument """Decode a sequence of frames.""" + if x.ndim == 4: + x = x.unsqueeze(0) return self.decode_video(x, parallel=False, show_progress_bar=False) def encode(self, x, parallel=True, show_progress_bar=False, return_dict=False): # pylint: disable=unused-argument diff --git a/modules/txt2img.py b/modules/txt2img.py index c79433443..af0b814bc 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -16,8 +16,7 @@ def txt2img(id_task, state, vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, n_iter, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, clip_skip, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, height, width, @@ -62,17 +61,14 @@ def txt2img(id_task, state, batch_size=batch_size, n_iter=n_iter, steps=steps, - guidance_name=guidance_name, - guidance_scale=guidance_scale, - guidance_rescale=guidance_rescale, - guidance_start=guidance_start, - guidance_stop=guidance_stop, + cfg_name=cfg_name, cfg_scale=cfg_scale, cfg_image=cfg_image, cfg_rescale=cfg_rescale, + cfg_start=cfg_start, + cfg_stop=cfg_stop, cfg_true=cfg_true, cfg_adaptive=cfg_adaptive, - cfg_end=cfg_end, clip_skip=clip_skip, width=width, height=height, diff --git a/modules/ui_control.py b/modules/ui_control.py index 11bda73bf..269e00aad 100644 --- a/modules/ui_control.py +++ b/modules/ui_control.py @@ -201,7 +201,7 @@ def create_ui(_blocks: gr.Blocks=None): mask_controls = masking.create_segment_ui() - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('control') + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('control') vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('control') grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('control') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('control') @@ -316,8 +316,8 @@ def create_ui(_blocks: gr.Blocks=None): prompt, negative, styles, steps, sampler_index, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, clip_skip, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, vae_type, tiling, hidiffusion, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, + clip_skip, vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires, grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, @@ -411,18 +411,17 @@ def create_ui(_blocks: gr.Blocks=None): (mask_controls[5], "Mask dilate"), (mask_controls[6], "Mask auto"), # guidance - (guidance_name, "Guidance"), - (guidance_scale, "Guidance scale"), - (guidance_rescale, "Guidance rescale"), - (guidance_start, "Guidance start"), - (guidance_stop, "Guidance stop"), - # advanced + (cfg_name, "CFG name"), (cfg_scale, "CFG scale"), - (cfg_end, "CFG end"), - (clip_skip, "CLiP-skip"), + (cfg_start, "CFG start"), + (cfg_stop, "CFG stop"), + (cfg_stop, "CFG end"), + (cfg_image, "CFG image"), (cfg_image, "Image CFG scale"), (cfg_image, "Hires CFG scale"), (cfg_rescale, "CFG rescale"), + # other + (clip_skip, "CLiP-skip"), (vae_type, "VAE type"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), diff --git a/modules/ui_guidance.py b/modules/ui_guidance.py index 4fffb1e2a..27bd82545 100644 --- a/modules/ui_guidance.py +++ b/modules/ui_guidance.py @@ -17,74 +17,54 @@ def create_guidance_inputs(tab): with gr.Group(): with gr.Row(elem_id=f"{tab}_guider_row", elem_classes=['flexbox'], visible=shared.opts.model_modular_enable): - guidance_name = gr.Dropdown(choices=guiders.keys(), value='Default', label='Guider', elem_id=f"{tab}_guider") - guidance_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_guider_docs") - guidance_btn.click(fn=None, _js='getGuidanceDocs', inputs=[guidance_name], outputs=[]) + cfg_name = gr.Dropdown(choices=guiders.keys(), value='Default', label='Guider', elem_id=f"{tab}_guider") + cfg_name_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_guider_docs") + cfg_name_btn.click(fn=None, _js='getGuidanceDocs', inputs=[cfg_name], outputs=[]) - base_group = gr.Group(visible=False) # default inherits from model + base_group = gr.Group() with base_group: - with gr.Row(visible=shared.opts.model_modular_enable): - guidance_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_guidance_scale") - guidance_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_guidance_rescale") - with gr.Row(visible=shared.opts.model_modular_enable): - guidance_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance start', value=0.0, elem_id=f"{tab}_guidance_start") - guidance_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance stop', value=1.0, elem_id=f"{tab}_guidance_stop") - guidance_args = [guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop] - - lsc_group = gr.Accordion(open=False, label='Layer skip guidance', elem_classes=["small-accordion"], visible=shared.opts.model_modular_enable) - with lsc_group: with gr.Row(): - guidance_lsc_enabled = gr.Checkbox(label='Enable LayerSkipConfig', value=False) - guidance_lsc_label = gr.Label(value='LSC: LayerSkipConfig', elem_id=f"{tab}_lsc_label", visible=False) - guidance_lsc_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_lsc_docs", elem_classes=["guidance-docs"]) - guidance_lsc_btn.click(fn=None, _js='getGuidanceDocs', inputs=[guidance_lsc_label], outputs=[]) + cfg_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_guidance_scale") + cfg_image = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance image', value=-1.0, elem_id=f"{tab}_guidance_image") with gr.Row(): - guidance_lsc_indices = gr.Textbox(label='LSC layer indices', value='1, 2, 3', placeholder='Comma-separated layer indices to skip') + cfg_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_guidance_rescale") with gr.Row(): - guidance_lsc_fqn = gr.Textbox(label='LSC fully qualified name', value='transformer_blocks', placeholder='Fully qualified name of the layer stack') - with gr.Row(): - guidance_lsc_skip_attention = gr.Checkbox(label='LSC skip attention blocks', value=True) - guidance_lsc_skip_ff = gr.Checkbox(label='LSC skip feed-forward blocks', value=True) - guidance_lsc_skip_attention_scores = gr.Checkbox(label='LSC skip attention scores', value=False) - with gr.Row(): - guidance_lsc_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='LSC dropout rate', value=1.0) - lsc_args = [guidance_lsc_enabled, guidance_lsc_indices, guidance_lsc_fqn, guidance_lsc_skip_attention, guidance_lsc_skip_ff, guidance_lsc_skip_attention_scores, guidance_lsc_dropout] + cfg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance start', value=0.0, elem_id=f"{tab}_guidance_start") + cfg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance stop', value=1.0, elem_id=f"{tab}_guidance_stop") + args_base = [cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop] auto_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with auto_group: - guidance_auto_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='AutoGuidance dropout', value=0.1) - guidance_auto_layers = gr.Textbox(label='AutoGuidance layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_auto_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='AutoGuidance config') - guidance_auto_args = [guidance_auto_dropout, guidance_auto_layers, guidance_auto_config] + guidance_auto_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='AutoGuidance dropout', value=1.0) + guidance_auto_layers = gr.Textbox(label='AutoGuidance layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_auto = [guidance_auto_dropout, guidance_auto_layers] zero_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with zero_group: guidance_zero_init_steps = gr.Slider(minimum=0, maximum=10, step=1, label='ZeroStar init steps', value=1) - guidance_zero_args = [guidance_zero_init_steps] + args_zero = [guidance_zero_init_steps] pag_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with pag_group: - guidance_cfg_true = gr.Slider(minimum=0.0, maximum=30.0, step=0.05, label='PAG scale', value=2.8) + guidance_pag_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.05, label='PAG scale', value=7.5) guidance_pag_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='PAG start', value=0.01) guidance_pag_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='PAG stop', value=0.2) - guidance_pag_layers = gr.Textbox(label='PAG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_pag_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='PAG config') - guidance_pag_args = [guidance_cfg_true, guidance_pag_start, guidance_pag_stop, guidance_pag_layers, guidance_pag_config] + guidance_pag_layers = gr.Textbox(label='PAG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_pag = [guidance_pag_scale, guidance_pag_start, guidance_pag_stop, guidance_pag_layers] apg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with apg_group: guidance_apg_momentum = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='APG momentum', value=-1.0) guidance_apg_rescale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='APG rescale', value=15.0) - guidance_apg_args = [guidance_apg_momentum, guidance_apg_rescale] + args_apg = [guidance_apg_momentum, guidance_apg_rescale] slg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with slg_group: guidance_slg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='SLG scale', value=2.8) guidance_slg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SLG start', value=0.01) guidance_slg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SLG stop', value=0.2) - guidance_slg_layers = gr.Textbox(label='SLG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_slg_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='SLG config') - guidance_slg_args = [guidance_slg_scale, guidance_slg_start, guidance_slg_stop, guidance_slg_layers, guidance_slg_config] + guidance_slg_layers = gr.Textbox(label='SLG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_slg = [guidance_slg_scale, guidance_slg_start, guidance_slg_stop, guidance_slg_layers] seg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with seg_group: @@ -93,20 +73,19 @@ def create_guidance_inputs(tab): guidance_seg_blur_threshold_inf = gr.Number(label='SEG blur threshold inf', value=9999.0) guidance_seg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SEG start', value=0.0) guidance_seg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SEG stop', value=1.0) - guidance_seg_layers = gr.Textbox(label='SEG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_seg_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='SEG config') - guidance_seg_args = [guidance_seg_scale, guidance_seg_blur_sigma, guidance_seg_blur_threshold_inf, guidance_seg_start, guidance_seg_stop, guidance_seg_layers, guidance_seg_config] + guidance_seg_layers = gr.Textbox(label='SEG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_seg = [guidance_seg_scale, guidance_seg_blur_sigma, guidance_seg_blur_threshold_inf, guidance_seg_start, guidance_seg_stop, guidance_seg_layers] tcfg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with tcfg_group: - pass + args_tcfg = [] fdg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with fdg_group: - guidance_fdg_scales = gr.Textbox(label='FDG scales', value='10.0, 5.0', placeholder='Comma-separated scales, e.g. 10.0,5.0') - guidance_fdg_weights = gr.Textbox(label='FDG weights', value='1.0', placeholder='Single float or comma-separated weights, e.g. 1.0 or 1.0,0.5') + guidance_fdg_scales = gr.Textbox(label='FDG scales', value='10.0, 5.0', placeholder='descending scales, e.g. 10.0,5.0') + guidance_fdg_weights = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='FDG weights', value=1.0) guidance_fdg_rescale_space = gr.Dropdown(choices=['data', 'freq'], value='data', label='FDG rescale space') - guidance_fdg_args = [guidance_fdg_scales, guidance_fdg_weights, guidance_fdg_rescale_space] + args_fdg = [guidance_fdg_scales, guidance_fdg_weights, guidance_fdg_rescale_space] def adv_visibility(guidance_name): return [ @@ -120,26 +99,24 @@ def create_guidance_inputs(tab): gr.update(visible=guidance_name.startswith('TCFG')), gr.update(visible=guidance_name.startswith('FDG')), ] - guidance_name.change(fn=adv_visibility, inputs=[guidance_name], outputs=[base_group, auto_group, zero_group, pag_group, apg_group, slg_group, seg_group, tcfg_group, fdg_group]) + cfg_name.change(fn=adv_visibility, inputs=[cfg_name], outputs=[base_group, auto_group, zero_group, pag_group, apg_group, slg_group, seg_group, tcfg_group, fdg_group]) - with gr.Row(elem_id=f"{tab}_cfg_row", elem_classes=['flexbox'], visible=not shared.opts.model_modular_enable): - cfg_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_cfg_scale") - cfg_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance end', value=1.0, elem_id=f"{tab}_cfg_end") - with gr.Row(visible=not shared.opts.model_modular_enable): - cfg_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_image_cfg_rescale") - cfg_image = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Refine guidance', value=-1.0, elem_id=f"{tab}_cfg_image") - with gr.Row(visible=not shared.opts.model_modular_enable): + legacy_group = gr.Row(visible=not shared.opts.model_modular_enable) + with legacy_group: cfg_true = gr.Slider(minimum=-1.0, maximum=30.0, step=0.05, label='Attention guidance', value=-1.0, elem_id=f"{tab}_cfg_true") cfg_adaptive = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Adaptive scaling', value=0.5, elem_id=f"{tab}_cfg_adaptive") + args_legacy = [cfg_true, cfg_adaptive] - _modular_args = guidance_args + lsc_args + guidance_auto_args + guidance_zero_args + guidance_pag_args + guidance_apg_args + guidance_slg_args + guidance_seg_args + guidance_fdg_args # TODO modular: guidance args are not implemented - def update_stored(component, label): - _stored_args[label] = component - for component in _modular_args: + modular_args = args_auto + args_zero + args_pag + args_apg + args_slg + args_seg + args_tcfg + args_fdg + standard_args = args_base + args_legacy + + def update_stored(component, name): + _stored_args[name] = component + for component in modular_args: label = getattr(component, 'label', None) value = getattr(component, 'value', None) - _stored_args[label] = value - component.change(fn=partial(update_stored, label=label), inputs=[component], outputs=[]) + name = label.lower().replace(' ', '_') if label is not None else None + _stored_args[name] = value + component.change(fn=partial(update_stored, name=name), inputs=[component], outputs=[]) - standard_args = [cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end] - return guidance_args + standard_args + return standard_args diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index 20890ed18..a1dd1d04d 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -137,7 +137,7 @@ def create_ui(): denoising_strength = gr.Slider(minimum=0.00, maximum=0.99, step=0.01, label='Denoising strength', value=0.30, elem_id="img2img_denoising_strength") refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="img2img_refiner_start") - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('img2img') + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('img2img') vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('img2img') grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('img2img') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('img2img') @@ -183,8 +183,7 @@ def create_ui(): vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, batch_count, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, refiner_start, clip_skip, denoising_strength, @@ -266,19 +265,8 @@ def create_ui(): (seed, "Seed"), (subseed, "Variation seed"), (subseed_strength, "Variation strength"), - # guidance - (guidance_name, "Guidance"), - (guidance_scale, "Guidance scale"), - (guidance_rescale, "Guidance rescale"), - (guidance_start, "Guidance start"), - (guidance_stop, "Guidance stop"), # advanced - (cfg_scale, "CFG scale"), - (cfg_end, "CFG end"), - (cfg_image, "Image CFG scale"), - (cfg_image, "Hires CFG scale"), (clip_skip, "CLiP-skip"), - (cfg_rescale, "CFG rescale"), (vae_type, "VAE type"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), @@ -309,7 +297,15 @@ def create_ui(): (refiner_steps, "Refiner steps"), (refiner_prompt, "refiner prompt"), (refiner_negative, "Refiner negative"), - # pag + # guidance + (cfg_name, "CFG name"), + (cfg_scale, "CFG scale"), + (cfg_image, "CFG image"), + (cfg_image, "Image CFG scale"), + (cfg_image, "Hires CFG scale"), + (cfg_rescale, "CFG rescale"), + (cfg_start, "CFG start"), + (cfg_stop, "CFG stop"), (cfg_true, "CFG true"), (cfg_adaptive, "CFG adaptive"), # inpaint diff --git a/modules/ui_txt2img.py b/modules/ui_txt2img.py index d639eb356..8988ead64 100644 --- a/modules/ui_txt2img.py +++ b/modules/ui_txt2img.py @@ -33,7 +33,7 @@ def create_ui(): with gr.Accordion(open=False, label="Samplers", elem_classes=["small-accordion"], elem_id="txt2img_sampler_group"): ui_sections.create_sampler_options('txt2img') seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('txt2img') - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('txt2img') + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('txt2img') vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('txt2img') grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('txt2img') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('txt2img') @@ -58,8 +58,7 @@ def create_ui(): vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, batch_count, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, clip_skip, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, height, width, @@ -114,19 +113,8 @@ def create_ui(): (seed, "Seed"), (subseed, "Variation seed"), (subseed_strength, "Variation strength"), - # guidance - (guidance_name, "Guidance"), - (guidance_scale, "Guidance scale"), - (guidance_rescale, "Guidance rescale"), - (guidance_start, "Guidance start"), - (guidance_stop, "Guidance stop"), # advanced - (cfg_scale, "CFG scale"), - (cfg_end, "CFG end"), (clip_skip, "CLiP-skip"), - (cfg_image, "Image CFG scale"), - (cfg_image, "Hires CFG scale"), - (cfg_rescale, "CFG rescale"), (vae_type, "VAE type"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), @@ -156,7 +144,15 @@ def create_ui(): (refiner_steps, "Refiner steps"), (refiner_prompt, "refiner prompt"), (refiner_negative, "Refiner negative"), - # pag + # guidance + (cfg_name, "CFG name"), + (cfg_scale, "CFG scale"), + (cfg_image, "CFG image"), + (cfg_image, "Image CFG scale"), + (cfg_image, "Hires CFG scale"), + (cfg_rescale, "CFG rescale"), + (cfg_start, "CFG start"), + (cfg_stop, "CFG stop"), (cfg_true, "CFG true"), (cfg_adaptive, "CFG adaptive"), # hidden diff --git a/modules/vae/sd_vae_taesd.py b/modules/vae/sd_vae_taesd.py index 0436339af..5bbc6a46e 100644 --- a/modules/vae/sd_vae_taesd.py +++ b/modules/vae/sd_vae_taesd.py @@ -220,7 +220,8 @@ def decode(latents, fast=False): image = image[0] else: image = vae.decode(tensor, return_dict=False)[0] - image = (image / 2.0 + 0.5).clamp(0, 1).detach() + # image = (image / 2.0 + 0.5).clamp(0, 1).detach() + image = image.clamp(0, 1).detach() image = restore_preview_size(image, vae) t1 = time.time() if (t1 - t0) > 5.0 and not first_run: diff --git a/scripts/xyz/xyz_grid_classes.py b/scripts/xyz/xyz_grid_classes.py index 655fc6dfb..c4947b835 100644 --- a/scripts/xyz/xyz_grid_classes.py +++ b/scripts/xyz/xyz_grid_classes.py @@ -47,7 +47,7 @@ from scripts.xyz.xyz_grid_shared import ( # pylint: disable=no-name-in-module, u format_nothing, str_permutations, ) -from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet, attention +from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet, attention, modular_guiders from modules.control.units import controlnet, t2iadapter from modules.control import processor @@ -260,10 +260,12 @@ axis_options = [ AxisOption("[Sampler] Max shift", float, apply_setting("schedulers_max_shift")), AxisOption("[Sampler] ETA delta", float, apply_setting("eta_noise_seed_delta")), AxisOption("[Sampler] ETA multiplier", float, apply_setting("scheduler_eta")), + AxisOption("[Guidance] Name", str, apply_field("cfg_name"), cost=0.2, choices=lambda: list(modular_guiders.guiders.keys())), AxisOption("[Guidance] Scale", float, apply_field("cfg_scale")), - AxisOption("[Guidance] End", float, apply_field("cfg_end")), - AxisOption("[Guidance] Image scale", float, apply_field("cfg_image")), AxisOption("[Guidance] Rescale", float, apply_field("cfg_rescale")), + AxisOption("[Guidance] Start", float, apply_field("cfg_start")), + AxisOption("[Guidance] Stop", float, apply_field("cfg_stop")), + AxisOption("[Guidance] Image scale", float, apply_field("cfg_image")), AxisOption("[Refine] Upscaler", str, apply_field("hr_upscaler"), cost=0.3, choices=lambda: [x.name for x in shared.sd_upscalers]), AxisOption("[Refine] Sampler", str, apply_hr_sampler_name, fmt=format_value_add_label, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.visible_samplers()]), AxisOption("[Refine] Denoising strength", float, apply_field("denoising_strength")), diff --git a/ui/autocomplete.ts b/ui/autocomplete.ts index 51f7338e2..e96068e95 100644 --- a/ui/autocomplete.ts +++ b/ui/autocomplete.ts @@ -239,7 +239,7 @@ const engine = { await Promise.all(toLoad.map(async (name) => { try { const resp = await authFetch(`${window.api}/autocomplete/${name}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); const data = await resp.json(); this.indices.set(name, new TagIndex(data)); // Extract category colors from first loaded file diff --git a/ui/autocomplete_xn.ts b/ui/autocomplete_xn.ts index 78d38fe36..2162fb772 100644 --- a/ui/autocomplete_xn.ts +++ b/ui/autocomplete_xn.ts @@ -88,7 +88,7 @@ export const xnEngine: XnEngine = { try { // const resp = await fetch(`${window.api}${path}`, { credentials: 'include' }); const resp = await authFetch(`${window.api}${path}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); return await resp.json(); } catch (e) { log('autoComplete', { xnFetchFailed: path, error: String(e) }); diff --git a/ui/dist/sdnext.mjs b/ui/dist/sdnext.mjs index f33d9f5bd..dcfeb96db 100644 --- a/ui/dist/sdnext.mjs +++ b/ui/dist/sdnext.mjs @@ -11231,7 +11231,7 @@ async function updateUI(model) { } async function updateModel() { const req = await authFetch2(`${window.api}/checkpoint`); - if (req.ok) { + if (req && req.ok) { const model = await req.json(); if (model?.type?.length > 0) updateUI(model); } @@ -11348,7 +11348,7 @@ async function setTheme(val, old) { for (const link of links) { const href = link.href.replace(old, val); const res = await authFetch2(href); - if (res.ok) { + if (res?.ok) { log("setTheme", old, val); link.href = link.href.replace(old, val); } else { @@ -12445,7 +12445,7 @@ async function initModels() { const en = gradioApp().getElementById("txt2img_extra_networks"); if (!el2 || !en) return; const req = await authFetch2(`${window.api}/sd-models`); - const res = req.ok ? await req.json() : []; + const res = req && req.ok ? await req.json() : []; log("initModels", res.length); const ready = () => `Ready
@@ -13493,7 +13493,7 @@ async function delayFetchThumb(fn, signal) { outstanding++; const ts = t0.toString(); const res = await authFetch2(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: "low" }); - if (!res.ok) { + if (!res?.ok) { error(`fetchThumb: ${res.statusText}`); return void 0; } @@ -14260,6 +14260,7 @@ async function observeImageError(img) { img.src = loadingSvg; const { default: heic2any } = await import("https://esm.sh/heic2any@0.0.4"); const res = await authFetch2(origSrc); + if (!res || res.status !== 200) return; const imageBlob = await res.blob(); if (!imageBlob || imageBlob.size <= 1024) { error("imageHEIC", { src: origSrc, res, blob: imageBlob }); @@ -14735,7 +14736,7 @@ var xnEngine = { async fetchJson(path) { try { const resp = await authFetch(`${window.api}${path}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); return await resp.json(); } catch (e) { log("autoComplete", { xnFetchFailed: path, error: String(e) }); @@ -14984,7 +14985,7 @@ var engine = { await Promise.all(toLoad.map(async (name) => { try { const resp = await authFetch(`${window.api}/autocomplete/${name}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); const data = await resp.json(); this.indices.set(name, new TagIndex(data)); if (data.categories) { diff --git a/ui/dist/sdnext.mjs.map b/ui/dist/sdnext.mjs.map index 0e5482d30..e8fa350af 100644 --- a/ui/dist/sdnext.mjs.map +++ b/ui/dist/sdnext.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist/jquery.js", "../js/iframeResizer.js", "../../node_modules/.pnpm/exifr@7.1.3/node_modules/exifr/dist/full.umd.js", "../../node_modules/.pnpm/wheel@1.0.0/node_modules/wheel/index.js", "../../node_modules/.pnpm/bezier-easing@2.1.0/node_modules/bezier-easing/src/index.js", "../../node_modules/.pnpm/amator@1.1.0/node_modules/amator/index.js", "../../node_modules/.pnpm/ngraph.events@1.4.0/node_modules/ngraph.events/index.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/kinetic.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeTextSelectionInterceptor.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/transform.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeSvgController.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeDomController.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/index.js", "../../node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist-module/wrappers/jquery.node-module-wrapper.js", "../vendor.ts", "../logger.ts", "../authWrap.ts", "../timers.ts", "../script.ts", "../changelog.ts", "../control.ts", "../extraNetworks.ts", "../generationParams.ts", "../imageParams.ts", "../notification.ts", "../progressBar.ts", "../dynamicUI.ts", "../ui.ts", "../inputAccordion.ts", "../indexdb.ts", "../logMonitor.ts", "../settings.ts", "../monitor.ts", "../promptChecker.ts", "../js/sha256.ts", "../gallery.ts", "../imageViewer.ts", "../autocomplete_xn.ts", "../autocomplete.ts", "../setHints.ts", "../contextMenus.ts", "../uiConfig.ts", "../loader.ts", "../legacy.ts", "../startup.ts", "../extensions.ts", "../dragDrop.ts", "../civitai.ts", "../guidance.ts", "../timesheet.ts", "../history.ts", "../storage.ts", "../aspectRatioOverlay.ts", "../resolutionLock.ts", "../editAttention.ts", "../../node_modules/.pnpm/jquery-sparkline@2.4.0/node_modules/jquery-sparkline/jquery.sparkline.js", "../gpu.ts"], - "sourcesContent": ["/*!\n * jQuery JavaScript Library v4.0.0\n * https://jquery.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.com/license/\n *\n * Date: 2026-01-18T00:20Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\tmodule.exports = factory( global, true );\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n\"use strict\";\n\nif ( !window.document ) {\n\tthrow new Error( \"jQuery requires a window with a document\" );\n}\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\n// Support: IE 11+\n// IE doesn't have Array#flat; provide a fallback.\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\n// [[Class]] -> type pairs\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\n// All support tests are defined in their respective modules.\nvar support = {};\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\treturn typeof obj === \"object\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n\nfunction isWindow( obj ) {\n\treturn obj != null && obj === obj.window;\n}\n\nfunction isArrayLike( obj ) {\n\n\tvar length = !!obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( typeof obj === \"function\" || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\n\nvar document$1 = window.document;\n\nvar preservedScriptAttributes = {\n\ttype: true,\n\tsrc: true,\n\tnonce: true,\n\tnoModule: true\n};\n\nfunction DOMEval( code, node, doc ) {\n\tdoc = doc || document$1;\n\n\tvar i,\n\t\tscript = doc.createElement( \"script\" );\n\n\tscript.text = code;\n\tfor ( i in preservedScriptAttributes ) {\n\t\tif ( node && node[ i ] ) {\n\t\t\tscript[ i ] = node[ i ];\n\t\t}\n\t}\n\n\tif ( doc.head.appendChild( script ).parentNode ) {\n\t\tscript.parentNode.removeChild( script );\n\t}\n}\n\nvar version = \"4.0.0\",\n\n\trhtmlSuffix = /HTML$/i,\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t}\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && typeof target !== \"function\" ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\n\t// Retrieve the text value of an array of DOM nodes\n\ttext: function( elem ) {\n\t\tvar node,\n\t\t\tret = \"\",\n\t\t\ti = 0,\n\t\t\tnodeType = elem.nodeType;\n\n\t\tif ( !nodeType ) {\n\n\t\t\t// If no nodeType, this is expected to be an array\n\t\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t\t// Do not traverse comment nodes\n\t\t\t\tret += jQuery.text( node );\n\t\t\t}\n\t\t}\n\t\tif ( nodeType === 1 || nodeType === 11 ) {\n\t\t\treturn elem.textContent;\n\t\t}\n\t\tif ( nodeType === 9 ) {\n\t\t\treturn elem.documentElement.textContent;\n\t\t}\n\t\tif ( nodeType === 3 || nodeType === 4 ) {\n\t\t\treturn elem.nodeValue;\n\t\t}\n\n\t\t// Do not include comment or processing instruction nodes\n\n\t\treturn ret;\n\t},\n\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tisXMLDoc: function( elem ) {\n\t\tvar namespace = elem && elem.namespaceURI,\n\t\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t\t// Assume HTML when documentElement doesn't yet exist, such as inside\n\t\t// document fragments.\n\t\treturn !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n\t},\n\n\t// Note: an element does not contain itself\n\tcontains: function( a, b ) {\n\t\tvar bup = b && b.parentNode;\n\n\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\n\t\t\t// Support: IE 9 - 11+\n\t\t\t// IE doesn't have `contains` on SVG.\n\t\t\ta.contains ?\n\t\t\t\ta.contains( bup ) :\n\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t) );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction nodeName( elem, name ) {\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n}\n\nvar pop = arr.pop;\n\n// https://www.w3.org/TR/css3-selectors/#whitespace\nvar whitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\";\n\nvar isIE = document$1.documentMode;\n\nvar rbuggyQSA = isIE && new RegExp(\n\n\t// Support: IE 9 - 11+\n\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\":enabled|:disabled|\" +\n\n\t// Support: IE 11+\n\t// IE 11 doesn't find elements on a `[name='']` query in some cases.\n\t// Adding a temporary attribute to the document before the selection works\n\t// around the issue.\n\t\"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\twhitespace + \"*(?:''|\\\"\\\")\"\n\n);\n\nvar rtrimCSS = new RegExp(\n\t\"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\",\n\t\"g\"\n);\n\n// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\nvar identifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\";\n\nvar rleadingCombinator = new RegExp( \"^\" + whitespace + \"*([>+~]|\" +\n\twhitespace + \")\" + whitespace + \"*\" );\n\nvar rdescend = new RegExp( whitespace + \"|>\" );\n\nvar rsibling = /[+~]/;\n\nvar documentElement$1 = document$1.documentElement;\n\n// Support: IE 9 - 11+\n// IE requires a prefix.\nvar matches = documentElement$1.matches || documentElement$1.msMatchesSelector;\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties\n\t\t// (see https://github.com/jquery/sizzle/issues/157)\n\t\tif ( keys.push( key + \" \" ) > jQuery.expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Checks a node for validity as a jQuery selector context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors\nvar attributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t// Operator (capture 2)\n\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\twhitespace + \"*\\\\]\";\n\nvar pseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t// 2. simple (capture 6)\n\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t// 3. anything else (capture 2)\n\t\".*\" +\n\t\")\\\\)|)\";\n\nvar filterMatchExpr = {\n\tID: new RegExp( \"^#(\" + identifier + \")\" ),\n\tCLASS: new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\tTAG: new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\tATTR: new RegExp( \"^\" + attributes ),\n\tPSEUDO: new RegExp( \"^\" + pseudos ),\n\tCHILD: new RegExp(\n\t\t\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" )\n};\n\nvar rpseudo = new RegExp( pseudos );\n\n// CSS escapes\n// https://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\nvar runescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\tif ( nonHex ) {\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\treturn nonHex;\n\t\t}\n\n\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t// Support: IE <=11+\n\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t// surrogate pair\n\t\treturn high < 0 ?\n\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\nfunction unescapeSelector( sel ) {\n\treturn sel.replace( runescape, funescape );\n}\n\nfunction selectorError( msg ) {\n\tjQuery.error( \"Syntax error, unrecognized expression: \" + msg );\n}\n\nvar rcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" );\n\nvar tokenCache = createCache();\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = jQuery.expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rleadingCombinator.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrimCSS, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in filterMatchExpr ) {\n\t\t\tif ( ( match = jQuery.expr.match[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\tif ( parseOnly ) {\n\t\treturn soFar.length;\n\t}\n\n\treturn soFar ?\n\t\tselectorError( selector ) :\n\n\t\t// Cache the tokens\n\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nvar preFilter = {\n\tATTR: function( match ) {\n\t\tmatch[ 1 ] = unescapeSelector( match[ 1 ] );\n\n\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\tmatch[ 3 ] = unescapeSelector( match[ 3 ] || match[ 4 ] || match[ 5 ] || \"\" );\n\n\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t}\n\n\t\treturn match.slice( 0, 4 );\n\t},\n\n\tCHILD: function( match ) {\n\n\t\t/* matches from filterMatchExpr[\"CHILD\"]\n\t\t\t1 type (only|nth|...)\n\t\t\t2 what (child|of-type)\n\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t5 sign of xn-component\n\t\t\t6 x of xn-component\n\t\t\t7 sign of y-component\n\t\t\t8 y of y-component\n\t\t*/\n\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t// nth-* requires argument\n\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\tselectorError( match[ 0 ] );\n\t\t\t}\n\n\t\t\t// numeric x and y parameters for jQuery.expr.filter.CHILD\n\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" )\n\t\t\t);\n\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t// other types prohibit arguments\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tselectorError( match[ 0 ] );\n\t\t}\n\n\t\treturn match;\n\t},\n\n\tPSEUDO: function( match ) {\n\t\tvar excess,\n\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\tif ( filterMatchExpr.CHILD.test( match[ 0 ] ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Accept quoted arguments as-is\n\t\tif ( match[ 3 ] ) {\n\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t// Strip excess characters from unquoted arguments\n\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t// Get excess from tokenize (recursively)\n\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t// advance to the next closing parenthesis\n\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) -\n\t\t\t\tunquoted.length ) ) {\n\n\t\t\t// excess is a negative index\n\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t}\n\n\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\treturn match.slice( 0, 3 );\n\t}\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nfunction access( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( typeof value !== \"function\" ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\t\tvalue :\n\t\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n}\n\n// Only count HTML whitespace\n// Other whitespace should count in values\n// https://infra.spec.whatwg.org/#ascii-whitespace\nvar rnothtmlwhite = /[^\\x20\\t\\r\\n\\f]+/g;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ||\n\n\t\t\t\t// For compat with previous handling of boolean attributes,\n\t\t\t\t// remove when `false` passed. For ARIA attributes -\n\t\t\t\t// many of which recognize a `\"false\"` value - continue to\n\t\t\t\t// set the `\"false\"` value as jQuery <4 did.\n\t\t\t\t( value === false && name.toLowerCase().indexOf( \"aria-\" ) !== 0 ) ) {\n\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = elem.getAttribute( name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Support: IE <=11+\n// An input loses its value after becoming a radio\nif ( isIE ) {\n\tjQuery.attrHooks.type = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( value === \"radio\" && nodeName( elem, \"input\" ) ) {\n\t\t\t\tvar val = elem.value;\n\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\tif ( val ) {\n\t\t\t\t\telem.value = val;\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t};\n}\n\n// CSS string/identifier serialization\n// https://drafts.csswg.org/cssom/#common-serializing-idioms\nvar rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\n\nfunction fcssescape( ch, asCodePoint ) {\n\tif ( asCodePoint ) {\n\n\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\tif ( ch === \"\\0\" ) {\n\t\t\treturn \"\\uFFFD\";\n\t\t}\n\n\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t}\n\n\t// Other potentially-special ASCII characters get backslash-escaped\n\treturn \"\\\\\" + ch;\n}\n\njQuery.escapeSelector = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nvar sort = arr.sort;\n\nvar splice = arr.splice;\n\nvar hasDuplicate;\n\n// Document order sorting\nfunction sortOrder( a, b ) {\n\n\t// Flag for duplicate removal\n\tif ( a === b ) {\n\t\thasDuplicate = true;\n\t\treturn 0;\n\t}\n\n\t// Sort on method existence if only one input has compareDocumentPosition\n\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\tif ( compare ) {\n\t\treturn compare;\n\t}\n\n\t// Calculate position if both inputs belong to the same document\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\ta.compareDocumentPosition( b ) :\n\n\t\t// Otherwise we know they are disconnected\n\t\t1;\n\n\t// Disconnected nodes\n\tif ( compare & 1 ) {\n\n\t\t// Choose the first element that is related to the document\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( a == document$1 || a.ownerDocument == document$1 &&\n\t\t\tjQuery.contains( document$1, a ) ) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( b == document$1 || b.ownerDocument == document$1 &&\n\t\t\tjQuery.contains( document$1, b ) ) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Maintain original order\n\t\treturn 0;\n\t}\n\n\treturn compare & 4 ? -1 : 1;\n}\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\njQuery.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\thasDuplicate = false;\n\n\tsort.call( results, sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tsplice.call( results, duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\treturn results;\n};\n\njQuery.fn.uniqueSort = function() {\n\treturn this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) );\n};\n\nvar i,\n\toutermostContext,\n\n\t// Local document vars\n\tdocument,\n\tdocumentElement,\n\tdocumentIsHTML,\n\n\t// Instance-specific data\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\n\t// Regular expressions\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = jQuery.extend( {\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\tneedsContext: new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t}, filterMatchExpr ),\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr$1 = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\t// Used for iframes; see `setDocument`.\n\t// Support: IE 9 - 11+\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE.\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && nodeName( elem, \"fieldset\" );\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\nfunction find( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr$1.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn results;\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tjQuery.contains( context, elem ) ) {\n\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( !nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// Outside of IE, if we're not changing the context we can\n\t\t\t\t\t// use :scope instead of an ID.\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( newContext != context || isIE ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = jQuery.escapeSelector( nid );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = jQuery.expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === jQuery.expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrimCSS, \"$1\" ), context, results, seed );\n}\n\n/**\n * Mark a function for special use by jQuery selector module\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ jQuery.expando ] = true;\n\treturn fn;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn nodeName( elem, \"input\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn ( nodeName( elem, \"input\" ) || nodeName( elem, \"button\" ) ) &&\n\t\t\telem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11+\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [node] An element or document object to use to set the document\n */\nfunction setDocument( node ) {\n\tvar subWindow,\n\t\tdoc = node ? node.ownerDocument || node : document$1;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 ) {\n\t\treturn;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocumentElement = document.documentElement;\n\tdocumentIsHTML = !jQuery.isXMLDoc( document );\n\n\t// Support: IE 9 - 11+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (see trac-13936)\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( isIE && document$1 != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\t\tsubWindow.addEventListener( \"unload\", unloadHandler );\n\t}\n}\n\nfind.matches = function( expr, elements ) {\n\treturn find( expr, null, null, elements );\n};\n\nfind.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\treturn matches.call( elem, expr );\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn find( expr, document, null, [ elem ] ).length > 0;\n};\n\njQuery.expr = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tfind: {\n\t\tID: function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t},\n\n\t\tTAG: function( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t},\n\n\t\tCLASS: function( className, context ) {\n\t\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\t\treturn context.getElementsByClassName( className );\n\t\t\t}\n\t\t}\n\t},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: preFilter,\n\n\tfilter: {\n\t\tID: function( id ) {\n\t\t\tvar attrId = unescapeSelector( id );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t},\n\n\t\tTAG: function( nodeNameSelector ) {\n\t\t\tvar expectedNodeName = unescapeSelector( nodeNameSelector ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn nodeName( elem, expectedNodeName );\n\t\t\t\t};\n\t\t},\n\n\t\tCLASS: function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace + \")\" + className +\n\t\t\t\t\t\"(\" + whitespace + \"|$)\" ) ) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\tATTR: function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = jQuery.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\tif ( operator === \"=\" ) {\n\t\t\t\t\treturn result === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"!=\" ) {\n\t\t\t\t\treturn result !== check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"^=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) === 0;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"*=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"$=\" ) {\n\t\t\t\t\treturn check && result.slice( -check.length ) === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"~=\" ) {\n\t\t\t\t\treturn ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" )\n\t\t\t\t\t\t.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"|=\" ) {\n\t\t\t\t\treturn result === check || result.slice( 0, check.length + 1 ) === check + \"-\";\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t};\n\t\t},\n\n\t\tCHILD: function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t( parent[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\touterCache = elem[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t( elem[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\tPSEUDO: function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// https://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar fn = jQuery.expr.pseudos[ pseudo ] ||\n\t\t\t\tjQuery.expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\tselectorError( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as jQuery does\n\t\t\tif ( fn[ jQuery.expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\tnot: markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrimCSS, \"$1\" ) );\n\n\t\t\treturn matcher[ jQuery.expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element\n\t\t\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\thas: markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn find( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\tcontains: markFunction( function( text ) {\n\t\t\ttext = unescapeSelector( text );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// https://www.w3.org/TR/selectors/#lang-pseudo\n\t\tlang: markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tselectorError( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = unescapeSelector( lang ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\ttarget: function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\troot: function( elem ) {\n\t\t\treturn elem === documentElement;\n\t\t},\n\n\t\tfocus: function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\tdocument.hasFocus() &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\tenabled: createDisabledPseudo( false ),\n\t\tdisabled: createDisabledPseudo( true ),\n\n\t\tchecked: function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\treturn ( nodeName( elem, \"input\" ) && !!elem.checked ) ||\n\t\t\t\t( nodeName( elem, \"option\" ) && !!elem.selected );\n\t\t},\n\n\t\tselected: function( elem ) {\n\n\t\t\t// Support: IE <=11+\n\t\t\t// Accessing the selectedIndex property\n\t\t\t// forces the browser to treat the default option as\n\t\t\t// selected when in an optgroup.\n\t\t\tif ( isIE && elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\tempty: function( elem ) {\n\n\t\t\t// https://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t// but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\tparent: function( elem ) {\n\t\t\treturn !jQuery.expr.pseudos.empty( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\theader: function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\tinput: function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\tbutton: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"button\" ||\n\t\t\t\tnodeName( elem, \"button\" );\n\t\t},\n\n\t\ttext: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"text\";\n\t\t},\n\n\t\t// Position-in-collection\n\t\tfirst: createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\tlast: createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\teq: createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\teven: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\todd: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tlt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i;\n\n\t\t\tif ( argument < 0 ) {\n\t\t\t\ti = argument + length;\n\t\t\t} else if ( argument > length ) {\n\t\t\t\ti = length;\n\t\t\t} else {\n\t\t\t\ti = argument;\n\t\t\t}\n\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tgt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\njQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tjQuery.expr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tjQuery.expr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = jQuery.expr.pseudos;\njQuery.expr.setFilters = new setFilters();\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ jQuery.expando ] || ( elem[ jQuery.expando ] = {} );\n\n\t\t\t\t\t\tif ( skip && nodeName( elem, skip ) ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = outerCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tfind( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ jQuery.expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ jQuery.expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem, matcherOut,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed ||\n\t\t\t\tmultipleContexts( selector || \"*\",\n\t\t\t\t\tcontext.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems;\n\n\t\tif ( matcher ) {\n\n\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter\n\t\t\t// or preexisting results,\n\t\t\tmatcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t[] :\n\n\t\t\t\t// ...otherwise use results directly\n\t\t\t\tresults;\n\n\t\t\t// Find primary matches\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t} else {\n\t\t\tmatcherOut = matcherIn;\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = jQuery.expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || jQuery.expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\n\t\t\t// Support: IE 11+\n\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tvar ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element\n\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = jQuery.expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = jQuery.expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ jQuery.expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( jQuery.expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 )\n\t\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrimCSS, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && jQuery.expr.find.TAG( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 );\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+\n\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\tfor ( ; ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tjQuery.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\nfunction compile( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ jQuery.expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n}\n\n/**\n * A low-level selection function that works with jQuery's compiled\n * selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n * selector function built with jQuery selector compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML &&\n\t\t\t\tjQuery.expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( jQuery.expr.find.ID(\n\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\tcontext\n\t\t\t) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( jQuery.expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = jQuery.expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) || context\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n}\n\n// Initialize against the default document\nsetDocument();\n\njQuery.find = find;\n\n// These have always been private, but they used to be documented as part of\n// Sizzle so let's maintain them for now for backwards compatibility purposes.\nfind.compile = compile;\nfind.select = select;\nfind.setDocument = setDocument;\nfind.tokenize = tokenize;\n\nfunction dir( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n}\n\nfunction siblings( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n}\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n// rsingleTag matches a string consisting of a single HTML element with no attributes\n// and captures the element's name\nvar rsingleTag = /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;\n\nfunction isObviousHtml( input ) {\n\treturn input[ 0 ] === \"<\" &&\n\t\tinput[ input.length - 1 ] === \">\" &&\n\t\tinput.length >= 3;\n}\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( typeof qualifier === \"function\" ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n// Initialize a jQuery object\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over