Snippets Collections
<body class="p- md:p-">

  <div class="container mx-auto">

    <h1 class="text-4xl md:text-xl mb- md:mb-8 text-center">Neo Brutalist Component Library</h1>
4
​
5
    <!-- Component Grid -->
6
    <div id="components" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-2 gap-6">

      <!-- Components will be injected here by JavaScript -->
8
    </div>

  </div>

  

  

<a target="_blank" href="https://www.rustcodeweb.com/" 

   style="position: fixed; bottom: 0.6rem; right: 0.6rem; background: #FFD6; color: #073B4C; text-decoration: none; padding: 0.5rem 1rem; border: 3px solid #073B4C; box-shadow: 3px 3px 0 #073B4C; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 600; font-size: 0.875rem; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 1200; border-radius: 2px; display: flex; align-items: center; gap: 0.5rem;"

   onmouseover="this.style.background='#F8F9FA'; this.style.transform='translate(-1px, -1px)'; this.style.boxShadow='4px 4px 0 #073B4C';"

   onmouseout="this.style.background='#FFD166'; this.style.transform='translate(0, 0)'; this.style.boxShadow='3px 3px 0 #073B4C';"
16
   onmousedown="this.style.transform='translate(0, 0)'; this.style.boxShadow='2px 2px 0 #073B4C';"

   onmouseup="this.style.transform='translate(-1px, -1px)'; this.style.boxShadow='4px 4px 0 #073B4C';"
<body class="p- md:p-">

  <div class="container mx-auto">

    <h1 class="text-4xl md:text-xl mb- md:mb-8 text-center">Neo Brutalist Component Library</h1>
4
​
5
    <!-- Component Grid -->
6
    <div id="components" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-2 gap-6">

      <!-- Components will be injected here by JavaScript -->
8
    </div>

  </div>

  

  

<a target="_blank" href="https://www.rustcodeweb.com/" 

   style="position: fixed; bottom: 0.6rem; right: 0.6rem; background: #FFD6; color: #073B4C; text-decoration: none; padding: 0.5rem 1rem; border: 3px solid #073B4C; box-shadow: 3px 3px 0 #073B4C; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 600; font-size: 0.875rem; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 1200; border-radius: 2px; display: flex; align-items: center; gap: 0.5rem;"

   onmouseover="this.style.background='#F8F9FA'; this.style.transform='translate(-1px, -1px)'; this.style.boxShadow='4px 4px 0 #073B4C';"

   onmouseout="this.style.background='#FFD166'; this.style.transform='translate(0, 0)'; this.style.boxShadow='3px 3px 0 #073B4C';"
16
   onmousedown="this.style.transform='translate(0, 0)'; this.style.boxShadow='2px 2px 0 #073B4C';"

   onmouseup="this.style.transform='translate(-1px, -1px)'; this.style.boxShadow='4px 4px 0 #073B4C';"
php-nativo:
php -S 192.168.1.50:9000
php -S localhost:9000
php -S 127.0.0.1:9000 //localhost

php-yii2
php -S localhost:8001 -t backend/web
php -S 172.xx.xx.xx:8081 -t backend/web

php-laravel
php artisan serve --port=8080
php -S 192.168.1.50:9000 -t public

laravel
php artisan serve
php artisan serve --host=172.xx.xx.xx:8081 --port=8000
php artisan serve --host=localhost --port=8000


yii2
php yii serve --port=8080
php yii serve --docroot="backend/web"
php yii serve --docroot="backend/web" --address=192.168.1.50 --port=9000
import json
import os
from typing import Dict

import torch
import torch.fx as fx
import torch.nn as nn
from core.frameworks.pytorch.quantization.sdk.graph_utils import ModelGraphUtils
from core.frameworks.pytorch.quantization.sdk.model_preparer import (
    _get_module_for_dotted_name,
    prepare_model,
)
from core.frameworks.pytorch.quantization.sdk.modules.fake_quantize import (
    FakeQuantize as CustomFakeQuantize,
)
from core.frameworks.pytorch.quantization.sdk.modules.module_replacement_registry import (
    ModuleReplacements,
)
from core.frameworks.pytorch.quantization.sdk.modules.quantized_modules import (
    QuantizationMixin,
)
from core.frameworks.pytorch.quantization.sdk.quantization_utils import (
    build_clean_onnx_path,
    build_onnx_path_from_torch_name,
    get_bitwidth_from_string_dtype,
    normalize_class_name,
    print_quant_summary,
)
from core.frameworks.pytorch.utils.utils import is_leaf_module
from logger.logger_registry import get_logger
from utils.config_utils import (
    get_model_configs,
    get_task_configs,
)
from utils.helpers import set_nested_attr

from .modules.function_modules import REPLACEMENTS
from .quantsim_config.quantsim_parser import QuantSimConfigParser

logger = get_logger("main")


class QuantizerEnginer:
    def __init__(
        self,
        model: torch.nn.Module,
        configs,
        device: torch.device,
    ):
        self._model: torch.nn.Module = model
        self.config = configs
        self.logger = get_logger("main")
        self.device = device
        self.task_type = (
            "qft" if self.config["qft"] else "ptq" if self.config["ptq"] else "pruning"
        )

        self.quantsim_config = QuantSimConfigParser()

    def update_model(self, model: torch.nn.Module):
        self._model = model

    def fuse_all_conv_bn(self, module):
        fusion_list = []
        module_list = list(module.named_modules())

        for (name1, mod1), (name2, mod2) in zip(module_list, module_list[1:]):
            if isinstance(mod1, torch.nn.Conv2d) and isinstance(
                mod2, torch.nn.BatchNorm2d
            ):
                fusion_list.append([name1, name2])

        if fusion_list:
            torch.ao.quantization.fuse_modules(module, fusion_list, inplace=True)

    def _check_super_groups_module(self, layer_name: str) -> bool:
        super_groups = self.quantsim_config.get_super_groups_ops()
        next_node_name = self.graphutils.get_next_non_identity_module(layer_name)
        if not next_node_name:
            return self.quantsim_config.is_default_ops_output_quantized()
        layer_name = self.graphutils.get_normalized_layer_name(layer_name)
        next_node_name = self.graphutils.get_normalized_layer_name(next_node_name)
        if next_node_name:
            next_node_name_lower = next_node_name.lower()
            node_name_lower = layer_name.lower()
            for super_group in super_groups:
                super_group_first = super_group[0].lower()
                super_group_second = super_group[1].lower()
                if (
                    node_name_lower in super_group_first
                    and next_node_name_lower in super_group_second
                ):
                    return False
                elif next_node_name_lower in super_group_second:
                    return True
        return self.quantsim_config.is_default_ops_output_quantized()

    def apply_io_quantizer_flags_to_graph(
        self, graph: torch.fx.GraphModule
    ) -> dict[str, tuple[bool, bool]]:
        """
        Iterate over all nodes in the graph and determine IO quantizer flags.

        Returns:
            A dictionary mapping node names to (add_input_quantizer, add_output_quantizer) flags.
        """
        io_flags = {}
        for node in graph.graph.nodes:
            if node.op == "call_module":
                flags = self.__get_io_quantizer_flags(graph, node, None)
                io_flags[node.name] = flags
                print(
                    f"[IO Quantizer Flags] {node.name}: Input={flags[0]}, Output={flags[1]}"
                )
                module: QuantizationMixin = _get_module_for_dotted_name(
                    graph, node.target
                )
                if not isinstance(module, QuantizationMixin):
                    continue
                if not flags[0]:
                    module.disable_input_quantization()
                if not flags[1]:
                    module.disable_output_quantization()
                if flags[0]:
                    module.enable_input_quantization()
                if flags[1]:
                    module.enable_output_quantization()

        return io_flags

    def _check_super_groups_node(
        self,
        layer_name: str,
        node: torch.fx.Node,
        next_node: torch.fx.Node,
        next_node_name: str,
    ) -> bool:
        super_groups = self.quantsim_config.get_super_groups_ops()
        for super_group in super_groups:
            if (
                layer_name in super_group[0].lower()
                and next_node
                and next_node_name in super_group[1].lower()
            ):
                print("#" * 20, layer_name, next_node_name, "#" * 20)
                return False
            elif layer_name in super_group[1].lower():
                return True
        return True

    def __is_quantizable_module(self, module: torch.nn.Module):
        return ModuleReplacements.get_replacement(module) is not None

    @classmethod
    def __is_quantized_module(cls, module: torch.nn.Module):
        return isinstance(module, QuantizationMixin)

    def _normalized_op_name(self, module: torch.nn.Module) -> str:
        """Map a module to the normalized op name used in your config."""
        return self.graphutils.get_normalized_layer_name(module)

    def _match_pattern_from(
        self,
        graph: torch.fx.GraphModule,
        start_node: torch.fx.Node,
        pattern_ops: list[str],
    ):
        """
        Try to match a supergroup pattern starting at start_node.
        Returns list of nodes if matched, else None.
        """
        if start_node.op != "call_module":
            return None

        try:
            first_module = _get_module_for_dotted_name(graph, start_node.target)
        except Exception:
            return None

        first_name = self._normalized_op_name(first_module)
        if first_name != pattern_ops[0]:
            return None

        matched_nodes = [start_node]
        curr = start_node
        for expected in pattern_ops[1:]:
            next_node = self.graphutils.get_next_non_identity_node(curr)
            if not next_node or next_node.op != "call_module":
                return None
            try:
                next_module = _get_module_for_dotted_name(graph, next_node.target)
            except Exception:
                return None
            next_name = self._normalized_op_name(next_module)
            if next_name != expected:
                return None
            matched_nodes.append(next_node)
            curr = next_node

        return matched_nodes

    def _collect_supergroup_patterns(self):
        """
        Read patterns from your quantsim config.
        Expected structure: [["Conv", "BatchNorm", "Relu"], ["MatMul", "Add"]]
        """
        cfg = self.quantsim_config.get_model_quantization_config()
        patterns = cfg.get("supergroups", [])
        cleaned = []
        for pat in patterns:
            if isinstance(pat, (list, tuple)) and len(pat) >= 2:
                cleaned.append([str(x) for x in pat])
        return cleaned

    def _apply_super_groups_config(self, graph: torch.fx.GraphModule):
        """
        Find and apply super-group quantization configuration.
        Works for groups of any length >= 2. Prevents overlaps.
        """
        patterns = self._collect_supergroup_patterns()
        self._supergroup_members = {}
        claimed = set()
        group_id = 0

        for node in graph.graph.nodes:
            if node.op != "call_module" or node in claimed:
                continue

            for pat in patterns:
                match = self._match_pattern_from(graph, node, pat)
                if not match:
                    continue
                if any(n in claimed for n in match):
                    continue

                size = len(match)
                for idx, member in enumerate(match):
                    self._supergroup_members[member] = (group_id, idx, size)
                    claimed.add(member)

                # Gather actual modules
                modules = []
                for mnode in match:
                    m = _get_module_for_dotted_name(graph, mnode.target)
                    modules.append(m)

                # Apply quantizer sharing
                self._apply_super_group_action_general(modules)

                if getattr(self, "verbose", False):
                    names = [self._normalized_op_name(m) for m in modules]
                    print(f"[SuperGroup] id={group_id} matched: {' -> '.join(names)}")

                group_id += 1
                break

    def _belongs_to_super_group(self, node: torch.fx.Node) -> bool:
        return hasattr(self, "_supergroup_members") and node in self._supergroup_members

    def _supergroup_position(self, node: torch.fx.Node):
        """Return (group_id, idx, size) if node is in a supergroup, else None."""
        if self._belongs_to_super_group(node):
            return self._supergroup_members[node]
        return None

    def _apply_super_group_action_general(self, modules: list):
        n = len(modules)
        if n < 2:
            return

        last_module = modules[-1]
        if not hasattr(last_module, "output_quantizer"):
            return

        shared_output_q = last_module.output_quantizer

        for m in modules[:-1]:
            if hasattr(m, "output_quantizer"):
                m.output_quantizer = shared_output_q

    def __get_io_quantizer_flags(
        self, graph, node: torch.fx.Node, layer_name: str | None
    ) -> tuple[bool, bool]:
        """
        Decide whether to add input/output quantizers for a node,
        respecting model IO policy and per-layer overrides.
        """
        layer_name = layer_name or self.graphutils.get_normalized_layer_name(node)
        model_quant_config = self.quantsim_config.get_model_quantization_config()

        add_input_quantizer = self.quantsim_config.is_default_ops_input_quantized()
        add_output_quantizer = self.quantsim_config.is_default_ops_output_quantized()

        if self.graphutils._is_first(node, layer_name):
            add_input_quantizer = model_quant_config.get("input_quantized", False)
        if self.graphutils._is_last(node, layer_name):
            add_output_quantizer = model_quant_config.get("output_quantized", False)

        # No need for explicit supergroup override:
        # all sharing is already handled in _apply_super_group_action_general.

        add_input_quantizer = self._apply_layer_override(
            layer_name, add_input_quantizer, is_input=True
        )
        add_output_quantizer = self._apply_layer_override(
            layer_name, add_output_quantizer, is_input=False
        )
        _module = _get_module_for_dotted_name(graph, node.target)
        return add_input_quantizer, add_output_quantizer

    def _apply_layer_override(
        self, layer_name: str, current_value: bool, is_input: bool
    ) -> bool:
        if is_input:
            if (
                layer_name
                in self.quantsim_config.get_layers_to_skip_from_input_quantizers()
            ):
                return False
            if layer_name in self.quantsim_config.get_layers_to_add_input_quantizers():
                return True
        else:
            if (
                layer_name
                in self.quantsim_config.get_layers_to_skip_from_output_quantizers()
            ):
                return False
            if layer_name in self.quantsim_config.get_layers_to_add_output_quantizers():
                return True
        return current_value

    def _add_quantization_wrappers(self, module, prefix=""):

        if self.__is_quantized_module(module):
            return
        for module_name, module_ref in module.named_children():
            full_name = f"{prefix}.{module_name}" if prefix else module_name
            self.logger.info("nn.Module found : %s", module_ref)
            print("nn.Module found : %s", module_ref)

            if self.__is_quantizable_module(module_ref) and is_leaf_module(module_ref):
                quantized_module = self._create_quantizer_module(module_ref, full_name)
                if not quantized_module:
                    self.logger.info(f"Please register {full_name}")
                    continue
                setattr(module, module_name, quantized_module)
            else:
                self._add_quantization_wrappers(module_ref, prefix=full_name)

    def _create_quantizer_module(
        self, module_to_quantize: torch.nn.Module, module_name: str
    ):

        param_per_channel = get_task_configs(
            self.config, "ptq", "parameter_per_channel", False
        )
        act_per_channel = get_task_configs(
            self.config, "ptq", "activation_per_channel", False
        )
        param_per_tensor = get_task_configs(
            self.config, "ptq", "parameter_per_tensor", True
        )
        act_per_tensor = get_task_configs(
            self.config, "ptq", "activation_per_tensor", True
        )
        param_is_symmetric = get_task_configs(
            self.config, "ptq", "parameter_is_symmetric", True
        )
        act_is_symmetric = get_task_configs(
            self.config, "ptq", "activation_is_symmetric", False
        )

        global_activation_dtype = get_task_configs(
            self.config, "ptq", "activation_dtype", "int4"
        )
        global_param_dtype = get_task_configs(
            self.config, "ptq", "parameter_dtype", "int4"
        )
        global_activation_observer = get_task_configs(
            self.config, "ptq", "activation_observer"
        )
        global_weight_observer = get_task_configs(self.config, "ptq", "weight_observer")

        quantizer = ModuleReplacements.get_replacement(module_to_quantize)

        if not quantizer:
            self.logger.info(f"Please register {type(module_to_quantize)}")
            return None

        # registering parameter and activation dtype
        setattr(module_to_quantize, "activation_dtype", global_activation_dtype)
        setattr(module_to_quantize, "parameter_dtype", global_param_dtype)
        setattr(module_to_quantize, "parameter_observer", global_weight_observer)
        setattr(module_to_quantize, "activation_observer", global_activation_observer)
        setattr(module_to_quantize, "param_per_channel", param_per_channel)
        setattr(module_to_quantize, "act_per_channel", act_per_channel)
        setattr(module_to_quantize, "param_per_tensor", param_per_tensor)
        setattr(module_to_quantize, "act_per_tensor", act_per_tensor)
        setattr(module_to_quantize, "param_is_symmetric", param_is_symmetric)
        setattr(module_to_quantize, "act_is_symmetric", act_is_symmetric)

        self.logger.info(
            f"Replacing {type(module_to_quantize)} with {quantizer.__name__} for quantization"
        )
        quantized_module = quantizer(
            _module_to_wrap=module_to_quantize,
            # add_input_quantizers=add_input_quantizers,
            # add_output_quantizers=add_output_quantizers,
        )
        return quantized_module

    def prepare(
        self,
    ):
        """
        Recursively replace every weight-bearing layer with a QuantWrapper.

        Args:
            layer_types: if provided, only wrap these types; else wrap all with 'weight'.
            model:       internal use for recursion (initially None → uses self._model).
        """
        self.logger.info("=" * 60)
        self.logger.info("Preparing model for QFT (Quantization-Aware Fine-Tuning)")
        self.logger.info("=" * 60)
        self._model.eval()
        self.fuse_all_conv_bn(self._model)

        # try:
        self.traced_graph = fx.symbolic_trace(self._model)
        self.graphutils = ModelGraphUtils(self._model, self.traced_graph)
        self._model = prepare_model(self._model)
        self.graphutils.update_model(self._model)
        self._add_quantization_wrappers(self._model)
        self.graphutils.update_graph(self._model)
        self.apply_io_quantizer_flags_to_graph(self._model)
        self.logger.info(self._model)

        # except Exception as e:
        #     print(e)
        #     self.graphutils = ModelGraphUtils(self._model, None)
        #     self.logger.info("Model is not graph tracable. Cannot replace math ops.")
        #     self._add_quantization_wrappers(self._model)

        self.logger.info("Model after preparing")
        self.logger.info(self._model)
        print_quant_summary(self._model)
        return self._model

    def convert(self, model) -> None:
        """
        Convert the model to a quantized model.
        This method is called after the training and preparation steps.
        """

        for name, child in list(model.named_children()):
            if isinstance(child, QuantizationMixin):
                self.logger.info(f"Replacing Quantized module: {name}")
                module: QuantizationMixin = child
                scale_fp = module.get_scale_fp()
                wrapped_module: nn.Module = module._module_to_wrap
                for k, v in scale_fp.items():
                    wrapped_module.register_buffer(f"{k}_scale", v["scale"])
                    wrapped_module.register_buffer(f"{k}_zero_point", v["zero_point"])
                    setattr(wrapped_module, f"{k}_scale", v["scale"])
                    setattr(wrapped_module, f"{k}_zero_point", v["zero_point"])

                setattr(model, name, wrapped_module)
                continue

            self.convert(child)

    def export_model(self, model: torch.nn.Module, task_type: str) -> None:
        """
        Export the quantized model to a format suitable for deployment.
        """
        self.model_name = get_model_configs(self.config)["name"]
        export_format = self.config["export"]["format"]
        output_dir = self.config["export"]["output_dir"] + "/" + self.model_name
        if export_format == "onnx":
            export_model = model.apply(torch.ao.quantization.disable_observer)
            export_model.cpu()
            if not os.path.exists(output_dir):
                os.makedirs(output_dir, exist_ok=True)

            param_dtype = get_task_configs(
                self.config, task_type, "parameter_dtype", "int4"
            )
            opset = get_task_configs(self.config, "export", "opset", 13)
            attribute = get_task_configs(self.config, "export", "attribute", None)
            if attribute is not None:
                if not hasattr(export_model, attribute):
                    raise ValueError(f"Model has no attribute '{attribute}' for export")
                export_model = getattr(export_model, attribute)

            onnx_file = (
                f"{self.model_name}_quantized_model_{task_type}_{param_dtype}.onnx"
            )

            output_path = os.path.join(output_dir, onnx_file)

            self.logger.info("=" * 60)
            self.logger.info("Exporting the quantized model")
            self.logger.info("=" * 60)
            self.logger.info(f"Model Name      : {self.model_name}")
            self.logger.info(f"Export Format   : {export_format}")
            self.logger.info(f"Output Path     : {output_path}")
            self.logger.info("=" * 60)
            try:
                torch.onnx.export(
                    export_model,
                    torch.randn(self._input_shape),  # type: ignore
                    output_path,
                    export_params=True,
                    opset_version=opset,
                    do_constant_folding=True,
                    input_names=["input_image"],
                    output_names=["output"],
                )
                self.logger.info("Model export completed successfully.")
            except Exception as e:
                self.logger.error("Model export failed.")
                self.logger.exception(e)

    def __extract_encoding(self, module: CustomFakeQuantize) -> Dict:
        scale = module.scale
        zero_point = module.zero_point
        quant_min = module.quant_min
        quant_max = module.quant_max
        qscheme = module.qscheme
        dtype = str(module.dtype)

        bitwidth = get_bitwidth_from_string_dtype(dtype)

        is_symmetric = qscheme in [
            torch.per_tensor_symmetric,
            torch.per_channel_symmetric,
        ]

        if is_symmetric:
            encoding_min = -scale * ((quant_max - quant_min) / 2)
            encoding_max = scale * ((quant_max - quant_min) / 2)
        else:
            encoding_min = scale * (quant_min - zero_point)
            encoding_max = scale * (quant_max - zero_point)

        base_info = {
            "bitwidth": bitwidth,
            "quant_min": quant_min,
            "quant_max": quant_max,
            "qscheme": str(qscheme),
            "dtype": dtype,
            "is_symmetric": is_symmetric,
        }

        if scale.numel() == 1:
            return {
                **base_info,
                "encodings": [
                    {
                        "scale": scale.item(),
                        "offset": zero_point.item(),
                        "min": encoding_min.item(),
                        "max": encoding_max.item(),
                    }
                ],
            }

        else:
            encodings = []
            for i in range(scale.numel()):
                encodings.append(
                    {
                        "scale": scale[i].item(),
                        "offset": zero_point[i].item(),
                        "min": encoding_min[i].item(),
                        "max": encoding_max[i].item(),
                    }
                )
        return {**base_info, "encodings": encodings}

    def __get_quant_min_max(self, dtype):
        dtype = dtype.lower()
        if dtype == "int4":
            return -8, 7, torch.qint8
        elif dtype == "uint4":
            return 0, 15, torch.quint8
        elif dtype == "int8":
            return -128, 127, torch.qint8
        elif dtype == "uint8":
            return 0, 255, torch.quint8
        elif dtype == "int16":
            return -32768, 32767, torch.qint32
        #     return 0, 65535, torch.qint32
        else:
            raise ValueError(f"Unsupported dtype: {dtype}")

    def __get_encodings_from_model(self, model, encoding_dict=None) -> Dict[str, Dict]:
        """
        Extracts quantization parameters (scale, zero_point, min, max, etc.)
        from a model prepared using torch.ao.quantization.prepare_qat.

        Returns a hierarchical dictionary of encodings per FakeQuantize module.
        """
        encoding_dict = {}

        for name, child in model.named_modules():
            if not name:
                continue
            if "quant" in name:
                continue
            onnx_path = build_onnx_path_from_torch_name(name)
            cls_name = normalize_class_name(child.__class__.__name__)
            output_name = build_clean_onnx_path(f"{onnx_path}/{cls_name}")
            output_name = output_name.replace("Quantized", "")
            if "module_" in output_name:
                output_name.replace("module_", "")
            if isinstance(child, QuantizationMixin):
                data = {}
                for sub_name, sub_module in child.named_modules():
                    if isinstance(sub_module, (CustomFakeQuantize)):
                        encoding_info = self.__extract_encoding(sub_module)
                        data[f"{sub_name.replace('_quantizers','')}"] = encoding_info
                encoding_dict[output_name] = data

        return encoding_dict

    def generate_embeddings(self, attribute):
        """
        Iterates through model modules, collects quantization encodings from QuantizationMixin modules,
        and writes them to a JSON file as a list.
        """
        output_dir = (
            self.config["export"]["output_dir"]
            + "/"
            + get_model_configs(self.config, "name")
        )
        # if attribute is not None:
        #     if not hasattr(model, attribute):
        #         raise ValueError(f"Model has no attribute '{attribute}' for export")
        #     model = getattr(model, attribute)

        all_encodings = self.__get_encodings_from_model(
            self._model
            # if  isinstance(attribute, str) and not hasattr(self._model, attribute)
            # else  isinstance(attribute, str) and getattr(self._model, attribute)
        )

        task_type = (
            "qft"
            if get_model_configs(self.config, "qft")
            else "ptq" if get_model_configs(self.config, "ptq") else "pruning"
        )
        output_path = os.path.join(
            output_dir,
            f'{get_model_configs(self.config, "name")}_{task_type}_quantization_encodings.json',
        )
        os.makedirs(output_dir, exist_ok=True)

        with open(output_path, "w") as f:
            json.dump(all_encodings, f, indent=4)

        print(f"Quantization encodings saved to: {output_path}")
Update all method according to my quantsimparse
ignore aimet
i have sent one quantsimparser class right
some methods that you have used here is wrong
South Goa is a tranquil haven for travelers seeking a blend of luxury, nature, and authentic Goan charm. Unlike the bustling beaches of the North, South Goa offers serene stretches of sand, lush coconut groves, and a more laid-back vibe — making it the ideal destination for those who prefer a peaceful and personalized vacation experience. One of the best ways to enjoy this unique region is by staying in boutique resorts, which offer a mix of exclusivity, style, and local flavor that big hotel chains often lack.

Boutique resorts in South Goa are known for their distinctive charm and personalized hospitality. These resorts are typically smaller in size but big on experience — offering beautifully designed rooms, curated wellness programs, gourmet cuisine, and easy access to quiet beaches. If you're looking for an intimate getaway, a boutique resort like Soul Vacation
 offers the perfect escape. Located near Colva Beach, Soul Vacation blends Mediterranean-inspired design with Goan warmth, making it one of the top boutique choices in the region. Whether you're on a romantic holiday or a solo retreat, this resort offers tranquility and luxury in equal measure.

What sets boutique resorts apart in South Goa is their focus on individuality and attention to detail. Many of these properties are set in heritage homes or artistically crafted villas that reflect the cultural essence of Goa. With fewer rooms and a focus on bespoke service, guests enjoy a more intimate and relaxing experience. You’ll often find yoga sessions by the beach, spa treatments using local ingredients, and home-style meals that highlight traditional Goan recipes.

Beyond the resorts themselves, South Goa offers plenty to explore — from hidden waterfalls and spice plantations to historic churches and quiet fishing villages. Staying in a boutique resort puts you closer to these unique experiences, away from the crowds, while still enjoying all the comforts of a luxury holiday. It’s not just about accommodation; it’s about creating lasting memories in an environment that feels both indulgent and authentic.

Whether you're escaping the hustle of daily life or planning a special celebration, boutique resorts in South Goa offer a soulful, immersive, and unforgettable stay.

Visit: https://soulvacation.in/resort-in-south-goa/
{
	"blocks": [
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":star: What's on in Melbourne this week! :star:"
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n\n Hey Melbourne, happy Monday and hope you all had a Beautiful weekend! Please see below for what's on this week. "
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Xero Café :coffee:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n :new-thing: *This week we are offering:* \n\n :caramel-slice: *Sweet Treats*: Selection of cookies \n\n :coffee: *Weekly Café Special*: English Toffee Coffee"
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": " Wednesday, 27th August :calendar-date-27:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n\n:lunch: :flag-fr: Join us for an French lunch From *12pm* in the Wominjeka breakout space! Menu in the:thread: "
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Thursday, 28th August :calendar-date-28:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":breakfast: *Breakfast*: Join us for Breakfast from *8:30am - 10:30am* in the Wominjeka Breakout Space. Menu in the :thread: \n\n\n\n *What Else? :green_heart:*"
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": " Feedback on our Boost Offerings? We want to hear more. Let us know what you love by filling out our form <https://docs.google.com/forms/d/e/1FAIpQLScGOSeS5zUI8WXEl0K4WGoQUkmpIHzAjLlEKWBob4sMPhDXmA/viewform|here.>  \n\n Stay tuned to this channel, and make sure you're subscribed to the <https://calendar.google.com/calendar/u/0?cid=Y19xczkyMjk5ZGlsODJzMjA4aGt1b3RnM2t1MEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Melbourne Social Calendar*> :party-wx:"
			}
		}
	]
}
C:\Users\Ismingiz>python --version
<style>
	/* menu open */
body{
	  overflow-x: hidden;
}
body.open-menu{
	overflow: hidden;
}
#header-main{
	transition: all 0.5s;
}
.scroll-web #header-main {
	background-color: #1B101D !important;
	top: 20px;
}
#menu-menu-header .menu-item.menu-item-has-children {
    margin-top: 0;
    padding: 0 25px;
}
#menu-menu-header .menu-item.menu-item-has-children > a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0;
}
#menu-menu-header .menu-item.menu-item-has-children > a:first-child:after {
    content: "";
    background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI1IiB2aWV3Qm94PSIwIDAgOSA1IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNC4xNjc5NyA0Ljk0OTIyTDAgMC43ODEyNUwwLjczMDQ2OSAwLjA1MDc4MTJMMS4wOTU3IDAuNDE2MDE2TDQuMTY3OTcgMy41MDk3N0w3LjYwNTQ3IDAuMDcyMjY1Nkw4LjMzNTk0IDAuNzgxMjVMNC4xNjc5NyA0Ljk0OTIyWiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==);
    width: 8.336px;
    height: 4.898px;
    position: unset;
    display: block;
}
.menu-icon {
	width: 50px;
	height: 50px;
	background: #f15a29; 
	display: flex;
	justify-content: center;
	align-items: center;
	cursor: pointer;
	flex-direction: column;
	transition: background 0.3s ease;
}
 
.menu-icon:hover {
	background: #27b4b2; 
}
 
.menu-icon span {
	display: block;
	width: 30px;
	height: 2px;
	background: white;
	margin: 2.5px 0;
	transition: width 0.3s ease;
}
 
.menu-icon:hover span:nth-child(2) {
	width: 16px;
}
@media(min-width: 981px){
	#menu-open{
		display: none !important;
	}
}
#menu-mobile-section{
	opacity: 0;
	visibility: hidden;
	transition: all 0.5s;
}
#menu-mobile-section.active {
    opacity: 1 !important;
    visibility: visible !important;
    z-index: 1000 !important;
}
#menu-mobile-section #menu-box {
    transition: all 0.5s;
}
#menu-mobile-section.active #menu-box {
    right: 0;
}
.header-menu-custom{
		height: calc(100% - 30px);
    overflow: scroll;
	 scrollbar-width: none;
    -ms-overflow-style: none;
}
.header-menu-custom::-webkit-scrollbar{
	display: none;
}
.header-menu-custom .menu {
    list-style: none;
    padding: 0;
}
#menu-mobile-section .header-menu-custom .sub-menu {
    list-style: none;
    padding: 0 0 0 20px !important;
    display: none;
}
#menu-mobile-section .header-menu-custom .et-show-dropdown ul.sub-menu {
    display: block;
}
#menu-mobile-section .header-menu-custom .menu a {
    color: #323D62;
    font-family: Figtree;
    font-size: 18px;
    font-style: normal;
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0.24px;
    padding: 10px;
    width: 100%;
    display: block;
    position: relative;
}
#menu-mobile-section .header-menu-custom .menu .sub-menu a {
    font-size: 16px;
    line-height: 1.2;
    padding: 8px 0;
}
#menu-mobile-section .header-menu-custom .menu .menu-item-has-children >  a:after {
    content: "";
    width: 12px;
    height: 12px;
    position: absolute;
    background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI1IiB2aWV3Qm94PSIwIDAgOSA1IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNC4xNjc5NyA0Ljk0OTIyTDAgMC43ODEyNUwwLjczMDQ2OSAwLjA1MDc4MTJMMS4wOTU3IDAuNDE2MDE2TDQuMTY3OTcgMy41MDk3N0w3LjYwNTQ3IDAuMDcyMjY1Nkw4LjMzNTk0IDAuNzgxMjVMNC4xNjc5NyA0Ljk0OTIyWiIgZmlsbD0iIzFCMTAxRCIvPgo8L3N2Zz4K);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    top: 50%;
    transform: translateY(-50%);
    right: 0;
	  transition: all 0.3s;
}
#menu-mobile-section .header-menu-custom .menu .menu-item-has-children.et-hover >  a:after{
	transform: translateY(-50%) rotate(180deg);
}
 
.close-button {
    width: 30px;
    height: 30px;
    padding: 5px;
    position: relative;
    cursor: pointer;
    margin: 0 0 0 auto;
    background: #ED5D2C;
}
.close-button span {
    position: absolute;
    width: 2px;
    height: 60%;
    background-color: #ffffff;
    top: 50%;
    left: 50%;
    transform-origin: center;
    transition: all 0.3s;
}
.close-button:hover{
	background: #32B4B8;
}
.close-button .line1 {
    transform: translate(-50%, -50%) rotate(45deg);
}
.close-button .line2 {
    transform: translate(-50%, -50%) rotate(-45deg);
}
 
@media(min-width: 982px){
	.menu-icon.menu-open {
			display: none;
	}
}
@media(min-width: 767px){
	#menu-mobile-section.active #menu-box {
			width: 80%;
      max-width: 520px;
	}
}
@media(max-width: 767px){
	.menu-icon {
    width: 40px;
    height: 40px;
	}
}
@media(max-width: 520px){
	#menu-mobile-section.active #menu-box {
			width: 100%;
	}
	.menu-icon {
    width: 40px;
    height: 40px;
	}
}
</style>
// Menu
function custom_menu_shortcode( $atts ) {
    $atts = shortcode_atts(
        array(
            'name' => 'Menu Header',
        ),
        $atts
    );
 
    $menu = wp_nav_menu(
        array(
            'menu'            => $atts['name'],
            'container'       => 'nav',
            'container_class' => 'header-menu-custom',
            'echo'            => false,
            'depth'           => 0,
            'fallback_cb'     => false,
        )
    );
 
    return $menu ?: '';
}
add_shortcode( 'show_menu', 'custom_menu_shortcode' );
jQuery(document).ready(function($) {
    $('.menu-icon').click(function() {
        $('#menu-mobile-section').addClass('active');
        $('body').addClass('open-menu');
    });
 
    $('.menu-close').click(function() {
        $('#menu-mobile-section').removeClass('active');
        $('body').removeClass('open-menu');
    });
 
    $(document).click(function(event) {
        if (!$(event.target).closest('#menu-box, .menu-open').length) {
            $('#menu-mobile-section').removeClass('active');
            $('body').removeClass('open-menu');
        }
    });
 
    $('.header-menu-custom .menu .menu-item-has-children > a').on('click', function(e) {
        var $this = $(this);
        var subMenu = $this.siblings('.sub-menu');
        if (subMenu.length) {
            if (!subMenu.is(':visible')) {
                e.preventDefault();
                $('.header-menu-custom .menu .sub-menu').slideUp();
                $('.header-menu-custom .menu .menu-item-has-children').removeClass('active-sub');
                subMenu.slideDown();
                $this.parent().addClass('active-sub');
            }
        }
    });
	
	$(window).scroll(function() {
        if ($(this).scrollTop() > 0) {
            $('body').addClass('scroll-web');
        } else {
            $('body').removeClass('scroll-web');
        }
    });
});
// Utility function for delay
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// Function to hit API with retries and delay
function hitApiWithRetry(url, options = {}, retries = 3, delay = 1000, callbacks = {}) {
  return new Promise(async (resolve, reject) => {
    for (let attempt = 1; attempt <= retries; attempt++) {
      try {
        console.log(`Attempt ${attempt}...`);
        let response = await fetch(url, options);

        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }

        let data = await response.json();

        // success callback
        if (callbacks.onSuccess) {
          callbacks.onSuccess(data, attempt);
        }

        return resolve(data); // resolve promise if success
      } catch (err) {
        console.error(`Error on attempt ${attempt}: ${err.message}`);

        // error callback
        if (callbacks.onError) {
          callbacks.onError(err, attempt);
        }

        if (attempt < retries) {
          console.log(`Retrying in ${delay}ms...`);
          await wait(delay);
        } else {
          return reject(`Failed after ${retries} attempts`);
        }
      }
    }
  });
}

// Usage example:
hitApiWithRetry(
  "https://jsonplaceholder.typicode.com/posts/1",
  {},
  3,  // retries
  2000, // delay (ms)
  {
    onSuccess: (data, attempt) => {
      console.log(`✅ Success on attempt ${attempt}`, data);
    },
    onError: (err, attempt) => {
      console.log(`❌ Failed on attempt ${attempt}: ${err.message}`);
    }
  }
)
.then(data => console.log("Final Data:", data))
.catch(err => console.log("Final Error:", err));
const apiserver = new Promise((resolve, reject) => {
    const user = {
        name: "tanishq dhingra",
        age: 19,
    };

    const status = 200;

    if (status === 200) {
        resolve(user);
    } else {
        reject("some error occurred here");
    }
});

apiserver
    .then((result) => {
        console.log(result);
    })
    .catch((err) => {
        console.log(err); // shows actual error message
    });
public LedgerDimensionAccount getLedgerDimensionModified(
    LedgerDimensionAccount _ledgerDimension,
    DimensionValue         _toDimTaxDeductionVal)
{
    LedgerDimensionAccount          ledgerDimension;
    DimensionDefault                defaultDimension;
    LedgerDimensionDefaultAccount   defaultAccount;

    DimensionAttribute                  dimAttr;
    DimensionAttributeValue             dimAttrValue;
    DimensionAttributeValueSetStorage   dimAttrValDimStorage;
    DimensionStorage                    dimAttrStorage;
    int                                 i;

    // Name of dimension attribute to change, example: TaxDeduction
    #define.DimAttrTaxDeductionName('TaxDeduction')
    ;

    dimAttr = DimensionAttribute::findByName(#DimAttrTaxDeductionName);

    if (_toDimTaxDeductionVal != '')
    {
        // convert to Default dimensions
        defaultDimension = DimensionStorage::getDefaultDimensionFromLedgerDimension(_ledgerDimension);
        dimAttrValDimStorage = DimensionAttributeValueSetStorage::find(defaultDimension);

        // find DimensionAttributeValue for specified display value of TaxDeduction dimension
        dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttr, _toDimTaxDeductionVal);

        // add dimension value to Default dimension
        dimAttrValDimStorage.addItemValues(dimAttr.RecId, dimAttrValue.RecId, dimAttrValue.HashKey);
        defaultDimension = dimAttrValDimStorage.save();

        // combine default dimension with ledger dimension representing main account
        defaultAccount = DimensionStorage::getLedgerDefaultAccountFromLedgerDim(_ledgerDimension);
        ledgerDimension = DimensionDefaultingService::serviceCreateLedgerDimension(defaultAccount, defaultDimension);
    }
    // remove dimension from combination
    else
    {
        dimAttrStorage = DimensionStorage::findById(_ledgerDimension);
        for (i = 1; i <= dimAttrStorage.segmentCount(); i++)
        {
            if (dimAttrStorage.getAttributeIdForSegment(i) == dimAttr.RecId)
                dimAttrStorage.clearSegment(i);
        }
        ledgerDimension = dimAttrStorage.save();
    }

    return ledgerDimension;
}

// https://daxtarkowski.wordpress.com/2014/04/16/changing-value-in-ledger-dimension-combination/
(function($){
	$('body').off("click", ".qib-button").on('click','.woocommerce-mini-cart-item-info-price .qib-button',function(e){
		e.preventDefault();
		var $this	= $(this),
			$qty	= $this.parent().find('.qty'),
			$qty_val = $qty.val(),
			currentVal	= parseFloat($qty.val()),
			max			= parseFloat($qty.attr('max')),
			min			= parseFloat($qty.attr('min')),
			step		= $qty.attr('step');
		
		$(this).addClass('loading');
		// Format values
		if (!currentVal || currentVal === '' || currentVal === 'NaN') currentVal = 0;
		if (max === '' || max === 'NaN') max = '';
		if (min === '' || min === 'NaN') min = 0;
		if (step === 'any' || step === '' || step === undefined || parseFloat(step) === 'NaN') step = 1;
		
		// Change the value
		if ($this.hasClass('plus')) {
			if (max && (max == currentVal || currentVal > max)) {
				$qty_val = max;
				
			} else {
				$qty_val = currentVal + parseFloat(step);
				
				//clickThrottle = setTimeout(function() { self.quantityInputsTriggerEvents($qty); }, clickThrottleTimeout);
			}
		} else {
			if (min && (min == currentVal || currentVal < min)) {
				$qty_val = min;
				
			} else if (currentVal > 0) {
				$qty_val = currentVal - parseFloat(step);
				
				//clickThrottle = setTimeout(function() { self.quantityInputsTriggerEvents($qty); }, clickThrottleTimeout);
			}
		}
		$qty.val($qty_val);
		//console.log($qty_val);
		callChangeQTYAddToCart($qty,$qty_val);
	});
	$('body').on('added_to_cart',function(e,data) {
		$(document.body).trigger('wc_fragment_refresh').trigger('updated_cart_totals');
	});
	$(document).ajaxComplete(function () {
		//alert(1);
		/*if (cartOpen) {
		  setTimeout(function () {
			openCart();
		  }, 100);
		}
		*/
		
	  });
	$(document).on('removed_from_cart', function(event, cart_item_key) {
        console.log("Item removed with key: " + cart_item_key);
        preventRedirect = true;
		//alert(11);
		return false;
		jQuery('body').addClass('is-visible');
    });
	jQuery(document.body).on('removed_from_cart updated_cart_totals',
		function() {
			
		  	jQuery(document.body).trigger('update_checkout');
		}
	);
	jQuery('body').on('change','.woocommerce-mini-cart-item-info-price .qty',function(e){
		e.preventDefault();
		var $this	= $(this),
			$qty_val = $this.val();
		callChangeQTYAddToCart($this,$qty_val);
	})
	function callChangeQTYAddToCart($qty,$qty_val){
		var self = this;
		if (self.cartPanelAjax) {
			self.cartPanelAjax.abort();
		}
		var $cartForm = $('#nm-cart-panel-form'), 
                $cartFormNonce = $cartForm.find('#_wpnonce'),
                data = {};
		if ( ! $cartFormNonce.length ) {
			return;
		}
		data['nm_cart_panel_update'] = '1';
		data['update_cart'] = '1';
		data[$qty.attr('name')] = $qty_val;
		data['_wpnonce'] = $cartFormNonce.val();
        
		// Make call to actual form post URL.
		self.cartPanelAjax = $.ajax({
			type:     'POST',
			url:      $cartForm.attr('action'),
			data:     data,
			dataType: 'html',
			error: function(XMLHttpRequest, textStatus, errorThrown) {
				console.log('NM: AJAX error - widgetPanelCartUpdate() - ' + errorThrown);
			},
			success:  function(response) {
				$(document.body).trigger('wc_fragment_refresh').trigger('updated_cart_totals');
				if($('body').hasClass('woocommerce-checkout'))
					jQuery(document.body).trigger('update_checkout');
			},
			complete: function() {
				self.cartPanelAjax = null; // Reset Ajax state
			}
		});
	}
})(jQuery)
jQuery(document.body).on('wc_fragment_refresh', function() {
	
    // Send AJAX to get content of minicart
    jQuery.ajax({
        url: wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'get_refreshed_fragments'),
        type: 'POST',
        success: function(data) {
            if (data && data.fragments) {
                // Update element
                //debugger;
                jQuery.each(data.fragments, function(key, value) {
                    jQuery(key).replaceWith(value);
                });
             
                console.log('Minicart has been refreshed');

            }
        }
    });
	
});
function smo_add_to_cart_func($atts) {
    ob_start();
	$atts = shortcode_atts(
        array(
            'product_id' => '',
        ), 
        $atts, 
        'smo_add_to_cart'
    );
	$product_id = $atts['product_id'];
	if ( ! class_exists( 'WooCommerce' ) ) {
        return;
    }
    $product = wc_get_product( $product_id );
    if ( ! $product || ! $product->is_purchasable() || ! $product->is_in_stock() ) {
        return;
    }
	
    echo '<form action="' . esc_url( get_the_permalink($product_id) ) . '" method="post" class="cart">';
    echo '<button type="submit" name="add-to-cart" value="' . esc_attr( $product_id ) . '" class="single_add_to_cart_button button alt">Add to cart - '.$product->get_price_html().'</button>';
    echo '</form>';
?>
<?php
	$output = ob_get_contents();
    ob_end_clean();
    return $output;
}

add_shortcode('smo_add_to_cart', 'smo_add_to_cart_func');
// Tạo field trong variation
add_action( 'woocommerce_variation_options', 'add_custom_variation_field', 10, 3 );
function add_custom_variation_field( $loop, $variation_data, $variation ) {
    woocommerce_wp_text_input( array(
        'id' => '_custom_variation_field[' . $loop . ']',
        'label' => 'Custom Save Percent(%)',
        'desc_tip' => true,
        'description' => '',
        'value' => get_post_meta( $variation->ID, '_custom_variation_field', true )
    ));
}

add_action( 'woocommerce_save_product_variation', 'save_custom_variation_field', 10, 2 );
function save_custom_variation_field( $variation_id, $i ) {
	$custom_field = $_POST['_custom_variation_field'][$i];
    if ( isset( $custom_field ) ) {
        update_post_meta( $variation_id, '_custom_variation_field', esc_attr( $custom_field ) );
    }
}
add_filter( 'woocommerce_available_variation', 'bbloomer_add_custom_field_variation_data' );
function bbloomer_add_custom_field_variation_data( $variations ) {
  $variations['save_percent'] = '<span class="discount-percentage">Save ' . get_post_meta( $variations[ 'variation_id' ], '_custom_variation_field', true ) . '%</span>';
  return $variations;
}

// Tạo Save percentage trong variations
function custom_variation_price_discount( $variations ) {
    if( isset( $variations['price_html'] ) && $variations['price_html'] != '' ) {
		$discount_message = '';
		$variation = wc_get_product( $variations['variation_id'] );
		
		if ( $variation->is_on_sale() ) {
			if($variations['save_percent'] && $variations['save_percent'] == ''){
				$regular_price = $variation->get_regular_price();
				$sale_price = $variation->get_sale_price();
				if ( $regular_price > 0 && $sale_price > 0 ) {
					$percentage = round( ( ( $regular_price - $sale_price ) / $regular_price ) * 100 );
					$discount_message = '<span class="discount-percentage">Save ' . $percentage . '%</span>';
				}
			}else{
				$discount_message = $variations['save_percent'];
			}
		}
		
        $variations['price_html'] = '<div class="price-wrap">'. $variations['price_html'] . $discount_message  . '</div>';
    }
    return $variations;
}

add_filter( 'woocommerce_available_variation', 'custom_variation_price_discount' );
add_action( 'wp', 'bbloomer_remove_zoom_lightbox_theme_support', 99 );
  
function bbloomer_remove_zoom_lightbox_theme_support() { 
    remove_theme_support( 'wc-product-gallery-zoom' );
    remove_theme_support( 'wc-product-gallery-lightbox' );
    remove_theme_support( 'wc-product-gallery-slider' );
}
remove_action('woocommerce_mini_cart_contents', 'commercekit_minicart_order_bump', 99);
add_action( 'custom_mini_cart_order_bump', 'commercekit_minicart_order_bump', 99 );


//pluign commercegurus-commercekit
https://drive.google.com/file/d/11QZEzZt8syH3elbPZFfp6Bbu8PTqUaac/view?usp=sharing
function custom_mini_cart() {
    if ( function_exists('WC') && WC()->cart ) {
        ?>
        <div class="custom-mini-cart">
            <a class="cart-contents" href="#" title="<?php _e( 'View your shopping cart', 'text-domain' ); ?>">
				<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 576 512" aria-hidden="true" class="icon icon-cart">
				 	 <title>Your cart</title><path d="M16 0H0V32H16 67.2l77.2 339.5 2.8 12.5H160 496h16V352H496 172.8l-14.5-64H496L566 64l10-32H542.5 100L95.6 12.5 92.8 0H80 16zm91.3 64H532.5l-60 192H151L107.3 64zM184 432a24 24 0 1 1 0 48 24 24 0 1 1 0-48zm0 80a56 56 0 1 0 0-112 56 56 0 1 0 0 112zm248-56a24 24 0 1 1 48 0 24 24 0 1 1 -48 0zm80 0a56 56 0 1 0 -112 0 56 56 0 1 0 112 0z"></path>
				</svg>
                <span class="cart-contents-count"><?php echo WC()->cart->get_cart_contents_count(); ?></span>
            </a>
        </div>
        <?php
    } else {
        echo '<p>' . __( 'Cart is empty.', 'text-domain' ) . '</p>';
    }
}
add_shortcode('custom_mini_cart', 'custom_mini_cart');
function custom_mini_cart_content() {
    if ( function_exists('WC') && WC()->cart ) {
        ?>
			<div class="bg_minicart_show"></div>
			<div class="minicart-wrap">
				<div class="widget_shopping_cart_heading">
					<h3>
						Your Cart
					</h3>
					<button type="button" aria-label="Close Cart" class="mni-cart-close"><img src="<?php echo get_stylesheet_directory_uri(); ?>/close.png" alt="" /></button>
				</div>
				<div class="widget_shopping_cart_content">
					<?php woocommerce_mini_cart(); ?>
				</div>
			</div>
            
        
        <?php
    } else {
        echo '<p>' . __( 'Cart is empty.', 'text-domain' ) . '</p>';
    }
}
add_shortcode('custom_mini_cart_content', 'custom_mini_cart_content');
function add_to_cart_fragment( $fragments ) {
    if ( function_exists('WC') && WC()->cart ) {
        ob_start();
        ?>
        <span class="cart-contents-count"><?php echo WC()->cart->get_cart_contents_count(); ?></span>
        <?php
        $fragments['.cart-contents-count'] = ob_get_clean();
    }
    return $fragments;
}
add_filter( 'woocommerce_add_to_cart_fragments', 'add_to_cart_fragment' );
<?php
		$product = wc_get_product(get_the_ID());
		$post_date = get_the_date('Y-m-d', get_the_ID());
		$post_date_time = strtotime($post_date);
		$current_date_time = strtotime(current_time('Y-m-d'));
		$date_diff = ($current_date_time - $post_date_time) / (60 * 60 * 24);
		if ($date_diff <= 10){
			echo '<span class="badge new-label">NEW</span>';
		}
	?>
	<?php
		$max_discount = 0;
		$output = '';

		if ($product->is_type('variable')) {
			foreach ($product->get_available_variations() as $variation) {
				$regular_price_variation = $variation['display_regular_price'];
				$sale_price_variation = $variation['display_price'];
				if ($sale_price_variation < $regular_price_variation) {
					$percentage_off = round((($regular_price_variation - $sale_price_variation) / $regular_price_variation) * 100);
					if ($percentage_off > $max_discount) {
						$max_discount = $percentage_off;
					}
				}
			}
			if ($max_discount > 0) {
				$output = '<span class="badge sale">ON SALE</span>';
			}
		} else {
			$regular_price = (float) $product->get_regular_price();
			$sale_price = (float) $product->get_sale_price();
			if ($sale_price && $sale_price < $regular_price) {
				$output = '<span class="badge sale">ON SALE</span>';
			}
		}
		if($output){
			echo $output;
		}
	?>
$('form.variations_form').on('found_variation', function(event, variation) {
				
				var imageSrc = variation.image.src;

				if(jQuery('.rst-image-product-thumb').length){
					if (imageSrc) {
						if (swiper2.activeIndex !== 0)
							swiper2.slideTo(0);
						setTimeout(function(){
							$('.product-single-image .swiper-slide-active img').attr('src',imageSrc);
						},100)
					}
				}
			});
function enable_ajax_add_to_cart_single_product() {
    if (is_product()) {
        ?>
        <script type="text/javascript">
           
			jQuery(function($){
				
				/* global wc_add_to_cart_params */
				if ( typeof wc_add_to_cart_params === 'undefined' ) {
					return false;
				}
				// Ajax add to cart on the product page
				var $warp_fragment_refresh = {
					url: woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_refreshed_fragments' ),
					type: 'POST',
					success: function( data ) {
						if ( data && data.fragments ) {

							$.each( data.fragments, function( key, value ) {
								$( key ).replaceWith( value );
							});

							$( document.body ).trigger( 'wc_fragments_refreshed' );
							$('body').addClass('is-visible');
						}
					}
				};

				$('form.cart').on('submit', function (e)
				{
					e.preventDefault();
					var form = $(this),
					button = form.find('.single_add_to_cart_button');
					button.block({ 
						message: null, 
						overlayCSS: {
							
							opacity: 0 
						}
					});

					var product_url = window.location;

					$.post(product_url, form.serialize() + '&_wp_http_referer=' + product_url, function (result)
					{
						

						// update fragments
						$.ajax($warp_fragment_refresh);

						button.unblock();

					});
				});
			});
        </script>
        <?php
   }
}
add_action('wp_footer', 'enable_ajax_add_to_cart_single_product');
function enqueue_woocommerce_ajax_add_to_cart() {
    if (is_product()) {
        wp_enqueue_script('wc-add-to-cart'); // WooCommerce Add to Cart Script
        wp_enqueue_script('woocommerce');
    }
}

add_action('wp_enqueue_scripts', 'enqueue_woocommerce_ajax_add_to_cart');
function display_product_variations_in_cart($cart_item, $cart_item_key) { 
    if (!empty($cart_item['variation'])) {
        echo '<div class="cart-item-variations">';
		
        foreach ($cart_item['variation'] as $key => $value) {
			
            $taxonomy = str_replace('attribute_', '', $key);
            $term = get_term_by('slug', $value, $taxonomy);
			
            if ($term) {
                echo '<p>' . $term->name . '</p>';
            }
        }
        echo '</div>';
    }
}
add_action('woocommerce_after_cart_item_name', 'display_product_variations_in_cart', 10, 2);
function custom_variation_price_discount( $variations ) {
    if( isset( $variations['price_html'] ) && $variations['price_html'] != '' ) {
		$discount_message = '';
		$variation = wc_get_product( $variations['variation_id'] );
		
		if ( $variation->is_on_sale() ) {
			if($variations['save_percent'] && $variations['save_percent'] == ''){
				$regular_price = $variation->get_regular_price();
				$sale_price = $variation->get_sale_price();
				if ( $regular_price > 0 && $sale_price > 0 ) {
					$percentage = round( ( ( $regular_price - $sale_price ) / $regular_price ) * 100 );
					$discount_message = '<span class="discount-percentage">Save ' . $percentage . '%</span>';
				}
			}else{
				$discount_message = $variations['save_percent'];
			}
		}
		
        $variations['price_html'] = '<div class="price-wrap">'. $variations['price_html'] . $discount_message  . '</div>';
    }
    return $variations;
}

add_filter( 'woocommerce_available_variation', 'custom_variation_price_discount' );
function smo_product_images_func2($atts) {
    ob_start();
	$atts = shortcode_atts(
        array(
            'product_id' => '',
        ), 
        $atts, 
        'smo_product_images2'
    );
	if(isset($atts['product_id']) && $atts['product_id'] != '') {
		$id = $atts['product_id'];
	}else{
		$id = get_the_ID();
	}
	$product = wc_get_product($id);
	//global $product;
	$thumbnail_size = 'woocommerce_single';
    $thumbnail_size_full = 'full';
	if ($product) {
	$post_thumbnail_id = $product->get_image_id();
	$attachment_ids = $product->get_gallery_image_ids();
	$thumbnail_src     = wp_get_attachment_image_src( $post_thumbnail_id, $thumbnail_size_full );
	$thumbnail_src2     = wp_get_attachment_image_src( $post_thumbnail_id, $thumbnail_size );
	}
?>
<div class="product--thumbnail_slider">
<div class="swiper rst-image-product-big2">
    <div class="swiper-wrapper">
		<div class="swiper-slide rst-item-image-product-big">
			<img src="<?php echo esc_url( $thumbnail_src[0] ); ?>" alt="" />
		</div>
		<?php
		if ( is_array($attachment_ids) && !empty($attachment_ids) ) {
		foreach ( $attachment_ids as $attachment_id ) {
		$gallery_src = wp_get_attachment_image_src( $attachment_id, $thumbnail_size_full );
		?>
		<div class="swiper-slide rst-item-image-product-big">
			<img src="<?php echo esc_url( $gallery_src[0] ); ?>" alt="" />
		</div>
		<?php
		}
		}
		?>
	</div> 
	<div class="swiper-pagination"></div>
</div> 
<?php
	if ( is_array($attachment_ids) && !empty($attachment_ids) ) {
?>
<div class="rst-image-product-thumb-container2">
<div class="swiper rst-image-product-thumb2">
    <div class="swiper-wrapper">
		<div class="swiper-slide rst-item-image-product-thumb">
			<div class="rst-item-image-product-thumb-img"><img src="<?php echo esc_url( $thumbnail_src2[0] ); ?>" alt="" /></div>
		</div>
		<?php
		
		foreach ( $attachment_ids as $attachment_id ) {
		$gallery_src = wp_get_attachment_image_src( $attachment_id, $thumbnail_size );
		?>
		<div class="swiper-slide rst-item-image-product-thumb">
			<div class="rst-item-image-product-thumb-img"><img src="<?php echo esc_url( $gallery_src[0] ); ?>" alt="" /></div>
		</div>
		<?php
		}
		?>
	</div>
	
</div>
	</div>
<?php
	}
?>
</div>
<?php	
	$output = ob_get_contents();
    ob_end_clean();
    return $output;
}

add_shortcode('smo_product_images2', 'smo_product_images_func2');
$(document).on('found_variation', 'form.cart', function(event, variation) {
	console.log(variation);
    if (variation.price_html) {
      $('.custom-price-box .elementor-widget-container').html(variation.price_html + variation.variation_description);
    }
});
function addCouponToMiniCart(){
?>
<div class="mini-cart-nm-coupon" style="margin-bottom: 10px;">
    <div class="nm-coupon" style="display: flex;">
       <input type="text" id="nm-coupon-code" class="input-text nm-coupon-code" name="nm_coupon_code" value="" placeholder="Discount code">
       <button type="button" id="nm-apply-coupon-btn" class="button" name="nm_apply_coupon" value="" onclick="applyCoupon(this)" style="white-space: nowrap;">Apply</button>
    </div>
    <div class="nm-coupon-notify" style="display: none; color: #FF0000;"></div>
</div>
<script type="text/javascript">
function applyCoupon(button) {
    let form = button.closest('.nm-coupon');
    let couponCode = form.querySelector(".nm-coupon-code").value;
    let ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
    
    jQuery.ajax({
        type: "GET",
        url: ajaxurl,
        dataType: 'json',
        data: 'coupon_code=' + couponCode + '&action=custom_apply_coupon',
        success: function (data) {
            if (data.status === 'success') {
                jQuery(document.body).trigger('wc_fragment_refresh');
                if (jQuery('body').hasClass('woocommerce-checkout'))
                    jQuery(document.body).trigger('update_checkout');
            } else if (data.status === 'already_used') {
                jQuery('.nm-coupon-notify').html('Coupon already used!');
                jQuery('.nm-coupon-notify').show();
            } else {
                jQuery('.nm-coupon-notify').html('Coupon is not valid!');
                jQuery('.nm-coupon-notify').show();
            }
        },
    });
}

(function($) {
    $('body').on('click', '.woocommerce-remove-coupon', function(e) {
        e.preventDefault();
        let ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
        var coupon = $(this).data('coupon');
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'remove_coupon',
                coupon: coupon,
            },
            success: function(response) {
                jQuery(document.body).trigger('wc_fragment_refresh');
            },
            error: function(error) {
                console.log('Error:', error);
            }
        });
    });
})(jQuery);
</script>
<?php    
}
//add_action('woocommerce_widget_shopping_cart_before_buttons', 'addCouponToMiniCart', 20);
add_action('woocommerce_custom_checkout_counpon', 'addCouponToMiniCart', 10);

add_action('wp_ajax_custom_apply_coupon', 'custom_apply_coupon');
add_action('wp_ajax_nopriv_custom_apply_coupon', 'custom_apply_coupon');

function custom_apply_coupon() {
    $coupon_code = isset($_GET['coupon_code']) ? $_GET['coupon_code'] : '';
    $coupon_code = sanitize_text_field($coupon_code);

    // Check if the coupon is already applied
    if (WC()->cart->has_discount($coupon_code)) {
        echo json_encode(array('status' => 'already_used'));
    } else {
        // Apply coupon
        $applied = WC()->cart->apply_coupon($coupon_code);
        if ($applied) {
            echo json_encode(array('status' => 'success'));
        } else {
            echo json_encode(array('status' => 'invalid'));
        }
    }
    wp_die();
}

add_action('wp_ajax_remove_coupon', 'remove_coupon_from_cart');
add_action('wp_ajax_nopriv_remove_coupon', 'remove_coupon_from_cart');

function remove_coupon_from_cart() {
    if (isset($_POST['coupon'])) {
        $coupon_code = sanitize_text_field($_POST['coupon']);
        WC()->cart->remove_coupon($coupon_code);
        wc_clear_notices(); 
        
        wp_send_json_success();
    } else {
        wp_send_json_error('Coupon code not provided.');
    }
}
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 );
add_filter('woocommerce_checkout_fields', 'remove_postal_code_field');
function remove_postal_code_field($fields) {
    //unset($fields['billing']['kl_newsletter_checkbox']);
		//unset($fields['billing']['billing_email']);
    return $fields;
}

add_action( 'woocommerce_checkout_after_customer_details', 'woocommerce_checkout_payment', 10 );
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10 );
function custom_woocommerce_place_order_button_text( $button_text ) {
    return 'Pay now';
}
add_filter( 'woocommerce_order_button_text', 'custom_woocommerce_place_order_button_text' );
function custom_checkout_privacy_policy_text( $text ) {
    return 'One or more items in your cart is a deferred or recurring purchase. By continuing with your payment, you agree that your payment method will automatically be charged at the price and frequency listed on this page until it ends or you cancel. All cancellations are subject to the <a href="" class="click-cancellation">cancellation policy</a>.';
}
add_filter( 'woocommerce_get_privacy_policy_text', 'custom_checkout_privacy_policy_text' );

function addCouponToMiniCart(){
?>
<div class="mini-cart-nm-coupon" style="margin-bottom: 10px;">
    <div class="nm-coupon" style="display: flex;">
       <input type="text" id="nm-coupon-code" class="input-text nm-coupon-code" name="nm_coupon_code" value="" placeholder="Discount code">
       <button type="button" id="nm-apply-coupon-btn" class="button" name="nm_apply_coupon" value="" onclick="applyCoupon(this)" style="white-space: nowrap;">Apply</button>
    </div>
    <div class="nm-coupon-notify" style="display: none; color: #FF0000;"></div>
</div>
<script type="text/javascript">
function applyCoupon(button) {
    let form = button.closest('.nm-coupon');
    let couponCode = form.querySelector(".nm-coupon-code").value;
    let ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
    
    jQuery.ajax({
        type: "GET",
        url: ajaxurl,
        dataType: 'json',
        data: 'coupon_code=' + couponCode + '&action=custom_apply_coupon',
        success: function (data) {
            if (data.status === 'success') {
                jQuery(document.body).trigger('wc_fragment_refresh');
                if (jQuery('body').hasClass('woocommerce-checkout'))
                    jQuery(document.body).trigger('update_checkout');
            } else if (data.status === 'already_used') {
                jQuery('.nm-coupon-notify').html('Coupon already used!');
                jQuery('.nm-coupon-notify').show();
            } else {
                jQuery('.nm-coupon-notify').html('Coupon is not valid!');
                jQuery('.nm-coupon-notify').show();
            }
        },
    });
}

(function($) {
    $('body').on('click', '.woocommerce-remove-coupon', function(e) {
        e.preventDefault();
        let ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
        var coupon = $(this).data('coupon');
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'remove_coupon',
                coupon: coupon,
            },
            success: function(response) {
                jQuery(document.body).trigger('wc_fragment_refresh');
            },
            error: function(error) {
                console.log('Error:', error);
            }
        });
    });
})(jQuery);
</script>
<?php    
}
//add_action('woocommerce_widget_shopping_cart_before_buttons', 'addCouponToMiniCart', 20);
add_action('woocommerce_custom_checkout_counpon', 'addCouponToMiniCart', 10);

add_action('wp_ajax_custom_apply_coupon', 'custom_apply_coupon');
add_action('wp_ajax_nopriv_custom_apply_coupon', 'custom_apply_coupon');

function custom_apply_coupon() {
    $coupon_code = isset($_GET['coupon_code']) ? $_GET['coupon_code'] : '';
    $coupon_code = sanitize_text_field($coupon_code);

    // Check if the coupon is already applied
    if (WC()->cart->has_discount($coupon_code)) {
        echo json_encode(array('status' => 'already_used'));
    } else {
        // Apply coupon
        $applied = WC()->cart->apply_coupon($coupon_code);
        if ($applied) {
            echo json_encode(array('status' => 'success'));
        } else {
            echo json_encode(array('status' => 'invalid'));
        }
    }
    wp_die();
}

add_action('wp_ajax_remove_coupon', 'remove_coupon_from_cart');
add_action('wp_ajax_nopriv_remove_coupon', 'remove_coupon_from_cart');

function remove_coupon_from_cart() {
    if (isset($_POST['coupon'])) {
        $coupon_code = sanitize_text_field($_POST['coupon']);
        WC()->cart->remove_coupon($coupon_code);
        wc_clear_notices(); 
        
        wp_send_json_success();
    } else {
        wp_send_json_error('Coupon code not provided.');
    }
}
	
sudo alternatives --config java
{% if product.metafields.custom.file2.value != blank %}
  <ul>
    {% for file in product.metafields.custom.file2.value %}
      <li>
        <a href="{{ file.url.value }}" target="new">{{ file.title }}</a>
      </li>
    {% endfor %}
  </ul>
{% else %}
  <p>No files available.</p>
{% endif %}
docker-compose down --rmi all --volumes --remove-orphans

--rmi all: elimina todas las imágenes creadas por docker-compose.
--volumes: elimina los volúmenes asociados.
--remove-orphans: elimina contenedores no definidos en el .yml actual.
# Eliminar volúmenes sin uso
docker volume prune -f

# Eliminar redes sin uso
docker network prune -f
Este comando elimina todas las imágenes de Docker del sistema (solo si no hay contenedores activos que las usen).

docker rmi $(docker images -a -q)
Estos comandos buscan todos los contenedores (activos y detenidos) y los detienen/eliminan automáticamente.

# Detener todos los contenedores
docker stop $(docker ps -a -q)

# Eliminar todos los contenedores
docker rm $(docker ps -a -q)
2. Archivo docker-compose.yml
¿Qué es un docker-compose.yml?
Es un archivo de configuración en formato YAML que permite definir y ejecutar múltiples contenedores Docker como un solo servicio, facilitando la orquestación de aplicaciones complejas.

Estructura básica de un docker-compose.yml
version: Define la versión de la sintaxis de Docker Compose.

services: Define los diferentes servicios o contenedores a levantar.

build: Ruta para construir la imagen Docker (opcional cuando se usa imagen pública).

image: Nombre de la imagen a usar.

ports: Puertos que se exponen y mapean al host.

volumes: Para montar volúmenes o carpetas locales dentro del contenedor.

environment: Variables de entorno para los contenedores.

Ejemplo básico:
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    environment:
      - NODE_ENV=development
  db:
    image: postgres:13
    environment:
      POSTGRES_USER: usuario
      POSTGRES_PASSWORD: contraseña
      POSTGRES_DB: mibase
    ports:
      - "5432:5432"
¿Cómo ejecutar un archivo docker-compose.yml?
Abrir una terminal.
Navegar a la carpeta donde está el archivo docker-compose.yml.

Ejecutar el comando:
docker-compose up
Esto creará y arrancará todos los servicios definidos en el archivo.

Para detener los servicios:
docker-compose down


Dockerfile
Qué es: Un archivo de texto que contiene una serie de instrucciones para construir una imagen Docker. Funciona como una "receta" para crear una imagen personalizada.

Para qué sirve: Define cómo se debe construir una imagen de contenedor, especificando la base del sistema operativo, las aplicaciones que se deben instalar, variables de entorno, archivos que se copian, comandos que se deben ejecutar para preparar la imagen, entre otros.

Cómo se arma: Se escribe paso a paso con comandos Docker (por ejemplo, FROM, COPY, RUN, CMD) que instruyen cómo se debe crear la imagen.

1. Dockerfile
¿Qué es un Dockerfile?
Un Dockerfile es un archivo de texto que contiene instrucciones para construir una imagen de Docker personalizada. Esta imagen luego se puede usar para crear contenedores.

Estructura básica de un Dockerfile
FROM: Define la imagen base desde la cual se construirá la nueva imagen.

WORKDIR: Define el directorio de trabajo dentro del contenedor.

COPY: Copia archivos o directorios desde tu sistema local hacia la imagen.

RUN: Ejecuta comandos en la imagen mientras se construye.

CMD: Define el comando que se ejecutará cuando se inicie un contenedor a partir de esta imagen.

Ejemplo básico:

# Imagen base
FROM node:14

# Directorio de trabajo
WORKDIR /app

# Copiar archivos al contenedor
COPY package*.json ./

# Instalar dependencias
RUN npm install

# Copiar el resto del código
COPY . .

# Puerto que se expondrá
EXPOSE 3000

# Comando para iniciar la aplicación
CMD ["npm", "start"]

¿Cómo ejecutar un Dockerfile?
Abrir una terminal.

Navegar a la carpeta donde está el Dockerfile.

Construir la imagen con el comando:
docker build -t nombre_de_la_imagen .

Ejecutar el contenedor con:
docker run -p 3000:3000 nombre_de_la_imagen
Las diferencias entre imágenes y contenedores en Docker son las siguientes:

Una imagen de Docker es una plantilla de solo lectura que contiene las bibliotecas, dependencias, archivos y el entorno necesario para ejecutar una aplicación. Es un archivo reutilizable e inmutable que sirve para crear contenedores. Las imágenes se crean generalmente a partir de un archivo Dockerfile que contiene todas las instrucciones para construir la imagen.

Un contenedor de Docker es una instancia en ejecución creada a partir de una imagen de Docker. Es un entorno aislado que incluye todo lo necesario para ejecutar la aplicación. Los contenedores tienen una capa adicional que permite escritura y cambios durante su ejecución, pero estos cambios no afectan la imagen original.

En resumen:

| Aspecto      | Imagen de Docker                             | Contenedor de Docker                       |
|--------------|---------------------------------------------|-------------------------------------------|
| Qué es       | Archivo de solo lectura que contiene la plantilla | Instancia en ejecución de una imagen      |
| Mutabilidad  | Inmutable, no se modifica después de creada | Mutable, permite cambios durante la ejecución |
| Función      | Plantilla para crear contenedores            | Ejecutar la aplicación de forma aislada   |
| Creación    | Creada a partir de un Dockerfile              | Creado a partir de una imagen              |
| Uso          | Almacenar y compartir la configuración y software | Ejecutar la aplicación en runtime          |

**Comandos específicos para imágenes:**


docker build -t nombre_imagen . — crea una imagen a partir de un Dockerfile.

docker images — lista las imágenes disponibles.

docker rmi nombre_imagen — elimina una imagen.

Comandos específicos para contenedores:

docker run nombre_imagen — crea y ejecuta un contenedor a partir de una imagen.

docker ps — lista los contenedores en ejecución.

docker ps -a — lista todos los contenedores (incluyendo los detenidos).

docker stop nombre_contenedor — detiene un contenedor en ejecución.

docker start nombre_contenedor — inicia un contenedor detenido.

docker rm nombre_contenedor — elimina un contenedor.

Por ejemplo, para crear y ejecutar un contenedor con un terminal bash usando una imagen llamada "MyImage":

text
docker run -it MyImage bash
En conclusión, las imágenes son las plantillas estáticas usadas para crear y ejecutar contenedores, mientras que los contenedores son las instancias activas que ejecutan realmente las aplicaciones, y se manejan con comandos diferentes conforme a su función. Esto permite portar software de forma consistente y escalable en diferentes entornos.
EXECUTE sp_set_database_firewall_rule N'Allow Azure', '0.0.0.0', '0.0.0.0';

SELECT * FROM sys.database_firewall_rules ORDER BY name;
function blog_list_shortcode($atts) {
	ob_start();
    $atts = shortcode_atts(array(), $atts);
	$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    $posts_per_page = get_option('posts_per_page');
	$cat = isset($_GET['cat'])?$_GET['cat']:'';
	
	$args = array(
		'post_type'      => 'post',
		'post_status'    => 'publish',
		'posts_per_page' => $posts_per_page,
		'paged'          => $paged,
	);
	$tax_query = [];
	if (!empty($cat)) {
		$tax_query[] = [
			'taxonomy' => 'category',
			'field'    => 'slug',
			'terms'    => [$cat],
		];
	}
	if (!empty($tax_query)) {
		$args['tax_query'] = $tax_query;
	}
    $query = new WP_Query($args);

    

    if ($query->have_posts()) {
		?>
		<form method="GET" action="" class="frmFilterPost">
			<input type="hidden" value="" name="cat" class="category_val" />
			<?php  
				$category = get_terms([
					'taxonomy'   => 'category',
					'hide_empty' => true,
			
				]);
				if(!empty($category)):
				$column_item = ceil(count($category) / 4);
				$total = count($category);
			?>	
			<div class="rst-box-filter">
				<div class="rst-box-filter-list deskop">
						<div class="rst-box-filter-list-all">
							<a class="rst-box-filter-item <?php echo $cat ? '' : 'active' ?>" data-slug="" >All<span class="count">(<?php echo $query->found_posts; ?>)</span></a>
						</div>	
						<div>
						<?php
							$i = 0;
							foreach ($category as $key => $value){
								$i++;
								$class="";
								if(!empty($cat) && $cat == $value->slug){
									$class="active";
								}
						?>
						
							<a class="rst-box-filter-item <?php echo $class; ?>" data-slug="<?php echo $value->slug ?>" ><?php echo $value->name ?><span class="count">(<?php echo $value->count ?>)</span></a>
						
						<?php
							if($i%$column_item == 0 && $i != $total ){
								echo '</div><div>';
							}
							}
						?>
							</div>
					
				</div>
				<div class="rst-box-filter-list mobile">
						<div class="rst-box-filter-list-all">
							<a class="rst-box-filter-item <?php echo $cat ? '' : 'active' ?>" data-slug="" >All<span class="count">(<?php echo $query->found_posts; ?>)</span></a>
						</div>	
						
						<?php
							foreach ($category as $key => $value){
								$class="";
								if(!empty($cat) && $cat == $value->slug){
									$class="active";
								}
						?>
						<div>
							<a class="rst-box-filter-item <?php echo $class; ?>" data-slug="<?php echo $value->slug ?>" ><?php echo $value->name ?><span class="count">(<?php echo $value->count ?>)</span></a>
						</div>
						<?php
							
							}
						?>
							
					
				</div>
			</div>
			<?php endif; ?>
		</form>
	<div class="rst-blog-lists-container-ajax">
		<div class="rst-blog-lists-container">
		<div class="rst-blog-lists">
		<?php
        

        while ($query->have_posts()) {
            $query->the_post();
			
            $post_id = get_the_ID();
            $permalink = get_permalink();
            $title = get_the_title();
			$excerpt = wp_trim_words(get_the_excerpt(), 22, '...');
            $thumbnail = get_the_post_thumbnail_url($post_id, 'full');
            $post_date = get_the_date();
            ?>
            <div class="blog-item">
				<a href="<?php echo esc_url($permalink); ?>"></a>
				<span class="icon-more">
				<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.25 7.25C15.6562 7.25 16 7.59375 16 8C16 8.4375 15.6562 8.75 15.25 8.75H8.75V15.25C8.75 15.6875 8.40625 16 8 16C7.5625 16 7.25 15.6875 7.25 15.25V8.75H0.75C0.3125 8.75 0 8.4375 0 8C0 7.59375 0.3125 7.25 0.75 7.25H7.25V0.75C7.25 0.34375 7.5625 0 8 0C8.40625 0 8.75 0.34375 8.75 0.75V7.25H15.25Z" fill="#0A5660"/>
</svg>

				</span>
				<?php if($thumbnail):?>
					<div class="rst-blog-post-image"> 
						<img src="<?php echo esc_url($thumbnail); ?>" alt="<?php echo esc_attr($title); ?>">
					</div>
				<?php endif;?>
				<div class="rst-blog-post-content">
					<div class="rst-blog-post-content-top">
						<h3><?php echo esc_html($title); ?></h3>
						<p><?php echo get_the_excerpt(); ?></p>
					</div>
					<div class="rst-blog-post-meta">
						<span class="rst-post-date"><?php echo get_the_date(); ?></span><span class="rst-space"></span><span class="rst-post-author">by <a href="<?php echo get_author_posts_url( get_post_field('post_author', $post_id) ); ?>" class="meta-author"><?php the_author()?></a></span>
					</div>	
				</div>
            </div>
            <?php
        }
		
		?>
        </div>
			<?php
			echo rst_the_posts_navigation($query);
		?>
			</div>
</div>
		<?php
        

    } else {
        echo '<p>No posts found.</p>';
    }

    wp_reset_postdata();
	?>
	<script type="text/javascript">
		(function($){
			$('.rst-box-filter-item').click(function(){
				var value = $(this).attr('data-slug');
				$('.rst-box-filter-item').removeClass('active');
				$(this).addClass('active');
				$('.category_val').val(value);
				$('.frmFilterPost').submit();
				return false;
			});
			
			
			function customAjaxSend(form,fullUrl){
				$.ajax({
					url: fullUrl,
					method: form.attr('method'),
					data: form.serialize(),
					dataType: 'html',
					beforeSend: function () {
						$('.rst-blog-lists-container').addClass('loading')
					},
					success: function(response) {
						const html = $(response);
						const items = html.find('.rst-blog-lists-container');
						$('.rst-blog-lists-container-ajax').html(items);
						$('.rst-blog-lists-container').removeClass('loading')
					},
					error: function(jqXHR, textStatus, errorThrown) {
						console.log('Error submitting form');
						console.log(textStatus, errorThrown);
					}
				});
			}
			
			$('.frmFilterPost').on('submit', function(e) {
				e.preventDefault(); 
				var form = $(this); 
				var url = form.attr('action'); 
				var fullUrl = url + '?' + form.serialize();
				var link_page = $('.link_page').val();
				//history.pushState({}, '', link_page);
				let currentUrl = window.location.href;
				let newUrl = currentUrl.replace(/page\/\d+\//, '');
				customAjaxSend(form, newUrl);
			});
			$('body').on('click','#tf-pagination a',function(e){
				e.preventDefault();
				var form = $('.frmFilterPost'); 
				var fullUrl = $(this).attr('href');
				$('html, body').animate({
					scrollTop: $(".rst-blog-lists").offset().top - 300
				}, 1000);
				customAjaxSend(form, fullUrl);
				
			})
			
		})(jQuery);
	</script>
	<?php
    return ob_get_clean();
}
add_shortcode('blog_list', 'blog_list_shortcode');
https://richplugins.com/business-reviews-bundle-wordpress-plugin

Grativi form:
82c574d3fc7f2da8c1239bc384e29e01
KEY MAP Api:
sk_9+Kn7QUZfX*0obV?i4J39?*FSKw:V
AIzaSyDNsicAsP6-VuGtAb1O9riI3oc_NOb7IOU
Key ticket
b9c9c200b7074f730ae5be8a6e894403b7e55699
Key ACF Pro:
b3JkZXJfaWQ9ODA4NjF8dHlwZT1kZXZlbG9wZXJ8ZGF0ZT0yMDE2LTA1LTAzIDE4OjM4OjIy
key wpform:
ff7340730b5c8079ff161a5158ef05c0

https://wpml.org
info@f-mediendesign.de
0711nb

 
// PHP Action
function highlight_text($text, $keyword) {
    return preg_replace('/(' . preg_quote($keyword, '/') . ')/i', '<strong>$1</strong>', $text);
}
add_action('wp_ajax_rst_ajax_search', 'rst_ajax_search_action');
add_action('wp_ajax_nopriv_rst_ajax_search', 'rst_ajax_search_action');

function rst_ajax_search_action() {
	global $wp_query;
	$s = isset($_POST['s']) ? sanitize_text_field($_POST['s']) : '';
	if ($s) {
		$args = array(
			'post_type'      => 'product',
			'post_status'    => 'publish',
			'posts_per_page' => 10,
			's'              => $s,
		);
		$the_query = new WP_Query($args);
		$wp_query = $the_query;
		$i = 0;
		if ($the_query->have_posts()) :
			?>
			<div class="rst-search-result-product">
				<span class="result-head">PRODUCTS<span>(<?php echo esc_html($the_query->found_posts); ?>)</span></span>
				<div class="rst-list-result-product">
					<div class="rst-list-result-product-column">
					<?php
						while ($the_query->have_posts()) : $the_query->the_post();
						$product_id = get_the_ID();
						$i++;
						$product = wc_get_product($product_id);
						$sku = $product->get_sku();
						if($i == 6){
							echo '</div><div class="rst-list-result-product-column">';
						}
					?>
					<div class="rst-item-result-product">
						<div class="rst-item-result-product-thumb">
							<?php echo get_the_post_thumbnail($product_id, 'woocommerce_thumbnail'); ?>
						</div>
						<div class="rst-item-result-product-meta">
							<h4><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h4>
							<?php 
								if($sku){
							?>
							<span>SKU: <?php echo esc_html($sku); ?></span>
							<?php
								}
							?>
						</div>
					</div>
					<?php
						endwhile;
					?>
					</div>
				</div>
				<?php
					if ($the_query->found_posts > 10) {
				?>
					<div class="wiew_all_product_wrap">
						<a href="<?php echo esc_url(home_url('/?s=' . $s . '&post_type=product')); ?>" class="wiew_all_product">View all products </a>
				</div>
				<?php
					}
				?>
			</div>
			<div class="rst-search-result-meta">
				<?php
					$args = array(
						'taxonomy'   => 'product_cat',
						'number' => 2,
						'orderby' => 'name',
						'name__like' => $s,
						'hide_empty' => false,
					);
					$tags = get_terms($args);
					$total = count($tags);
					//var_dump($tags);
					 if (!empty($tags) && !is_wp_error($tags)) {
						$y = 0;
				?>
				
				<div class="rst-search-result-meta-box rst-search-result-meta-box-product-cat">
					<span class="result-head">CATEGORIES<span>(<?php echo $total; ?>)</span></span>
					<ul>
					<?php
						foreach ($tags as $tag) {
							$y++;
							$tag_link = get_tag_link($tag->term_id);
							$term = get_term($tag->term_id);
							$thumbnail_id = get_term_meta( $tag->term_id, 'thumbnail_id', true );
							$thumbnail_url = wp_get_attachment_url( $thumbnail_id );
							$parent_terms = [];
							while ($term->parent != 0) {
								$term = get_term($term->parent);
								if (!is_wp_error($term) && $term) {
									$parent_terms[] = $term;
								}
							}
							$in = '';
							if (!empty($parent_terms)) {
								$in = 'in ';
								$reversed_array = array_reverse($parent_terms);
								$z = 0;
								foreach ($reversed_array as $item) {
									$z++;
									if($z == 1){
										$in = $in . esc_html($item->name);
									}else{
										$in = $in . ' > ' . esc_html($item->name);
									}
									
								}
							}
							
							$title_tag = highlight_text($tag->name,$s);
					?>
					<li><a href="<?php echo esc_url($tag_link); ?>" class="taxonomy-link-meta">
					<?php
						if ( $thumbnail_url ) {
					?>
					<img src="<?php echo esc_url( $thumbnail_url ); ?>" alt="" />
					<?php
						}
					?>
					<div>
					<h4><?php echo $title_tag; ?></h4>
					<?php
						if($in){
					?>
					<span><?php echo $in; ?></span>
					<?php
						}
					?>
					</div>
					</a></li>
					<?php
						//if($y == 2) break;
						}
					?>
					</ul>
				</div>
				<?php
					 }
				?>
				<?php
					$args = array(
						'taxonomy'   => 'post_tag',
						'number' => 1,
						'name__like' => $s,
						'hide_empty' => true,
					);
					$tags = get_terms($args);
					 if (!empty($tags) && !is_wp_error($tags)) {
				?>
				<div class="rst-search-result-meta-box">
					<span class="result-head">TAGS</span>
					<ul>
						<?php
							foreach ($tags as $tag) {
								
								$tag_link = get_tag_link($tag->term_id);
								 $title_tag = highlight_text($tag->name,$s);
						?>
						<li><a href="<?php echo esc_url($tag_link); ?>"><?php echo $title_tag; ?></a></li>
						<?php
							
							}
						?>
					</ul>
				
				</div>
				<?php
					 }
				?>
				<?php
				$args_post = array(
					'post_type'      => 'post',
					'post_status'    => 'publish',
					'posts_per_page' => 1,
					's'              => $s,
				);
				
				$the_query_post = new WP_Query($args_post);
				if ($the_query_post->have_posts()) :
					?>
				<div class="rst-search-result-meta-box">				
					<span class="result-head">POSTS</span>
					<ul>
						<?php
							while ($the_query_post->have_posts()) : $the_query_post->the_post();
								$tag_link = get_the_permalink();
								$title_tag = highlight_text(get_the_title(),$s);
						?>
						<li><a href="<?php echo esc_url($tag_link); ?>"><?php echo $title_tag; ?></a></li>
						<?php
							endwhile;
						?>
					</ul>
				</div>
				<?php
					endif; 
					wp_reset_query();
				?>
			</div>
		<?php
		else :
			echo '<p class="no-result">No results</p>';
		endif;
		wp_reset_query();
	}
	exit;
}



//Js Call
jQuery('.rst-search .rst-wcas-search-input').on("input", function(e) {
	e.preventDefault();
	var dInput = this.value;
	if (dInput.length >= 2) {
		jQuery('.rst-search-result').addClass('show');
		jQuery('.rst-wcas-proccesing').addClass('show');
		jQuery('.rst-wcas-close').removeClass('show');
		var ajax_url = jQuery('.ajax_url').val();
		jQuery.ajax({
			type: "POST",
			url: ajax_url,
			data: {
				'action' 	: 'rst_ajax_search',
				's' 		: dInput,
			}
		}).done(function(data){
			var items = jQuery(data);
			jQuery('.rst-wcas-proccesing').removeClass('show');
			jQuery('.rst-wcas-close').addClass('show');
			jQuery('.rst-search-result-inner').html(items);
		});
	}
});
 $('.et_pb_toggle').removeClass('et_pb_toggle_open');
	  $('.et_pb_toggle_content').hide();
	  $('.et_pb_toggle_title').on('click', function() {
		let parent = $(this).closest('.et_pb_toggle');
		let content = parent.find('.et_pb_toggle_content');

		if (parent.hasClass('et_pb_toggle_open')) {
		  content.slideUp();
		  parent.removeClass('et_pb_toggle_open');
		} else {
		  content.slideDown();
		  parent.addClass('et_pb_toggle_open');
		}
	  });
class Rst_Custom_Navigation extends Walker_Nav_Menu {
	 function display_element($element, &$children_elements, $max_depth, $depth = 0, $args = [], &$output = '') {
        // Check if current element has children
        $element->has_children = !empty($children_elements[$element->ID]);

        // Continue the normal walker process
        parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
    }
	function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
		$classes = array_diff($classes, ['menu-item-has-children']);
		/*
		$classes1 = array();
		$classes1[] = 'menu-item';
        $classes1[] = 'menu-item-' . $item->ID;
		*/
		if (!empty($item->has_children)) {
            $classes[] = 'rst-menu-item-has-children';
        }
        $mega_menu = get_field('mega_menu',$item);
        if($mega_menu){
            $classes[] = 'has-submenu-mega-menu';
        }
        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
			
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
        $id = 'menu-item-'. $item->ID;
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
		
		$promotion = get_field('promotion',$item) ? get_field('promotion',$item) : 'current';
        $href = !empty($item->url) ? $item->url : '#';
		$atts = array();
		$atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
		$atts['target'] = ! empty( $item->target )     ? $item->target     : '';
		$atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
		$atts['href']   = ! empty( $item->url )        ? $item->url        : '';
		$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

		$attributes = '';
		foreach ( $atts as $attr => $value ) {
			if ( ! empty( $value ) ) {
				$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
				$attributes .= ' ' . $attr . '="' . $value . '"';
			}
		}
        $output .= '<li' . $id . $class_names .'>';
        $output .= '<a' . $attributes . '>';
        $output .= esc_html( $item->title );
         $output .= '<svg class="icon_link" width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
		<path d="M8.96875 0.375C9.32422 0.375 9.625 0.675781 9.625 1.03125V7.59375C9.625 7.97656 9.32422 8.25 8.96875 8.25C8.58594 8.25 8.3125 7.97656 8.3125 7.59375V2.61719L1.99609 8.93359C1.72266 9.20703 1.3125 9.20703 1.06641 8.93359C0.792969 8.6875 0.792969 8.27734 1.06641 8.03125L7.38281 1.71484L2.40625 1.6875C2.02344 1.6875 1.75 1.41406 1.75 1.03125C1.75 0.675781 2.02344 0.375 2.40625 0.375H8.96875Z" fill="#E32838"/></svg>';
        if ( in_array( 'rst-menu-item-has-children', $classes ) ) {
            $output .= ' <span class="submenu-icon"><svg width="13" height="9" viewBox="0 0 13 9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.5625 8.03516L5.88867 7.36133L1.20117 2.67383L0.527344 2L1.875 0.681641L2.51953 1.35547L6.5625 5.36914L10.5762 1.35547L11.25 0.681641L12.5684 2L11.8945 2.67383L7.20703 7.36133L6.5625 8.03516Z" fill="#C7202F"/></svg></span>';
        }
        $output .= '</a>';
		ob_start();
		if($mega_menu){
			?>
			<div class="rst-mega-menu-container">
				<div class="rst-mega-menu-container-inner">
					<div class="rst-mega-menu-left">
						<div class="rst-mega-menu-left-inner">
							<div class="rst-mega-menu-left-inner-heading">
								Emergency Services
							</div>
							<?php
								$emergency_services = get_field('emergency_services','option');
								if(is_array($emergency_services) && !empty($emergency_services)){
							?>
							<div class="rst-mega-menu-left-inner-content">
								<h3><?php echo $emergency_services['title']; ?></h3>
								<p><?php echo do_shortcode($emergency_services['description']); ?></p>
								<?php
									if(get_field('phone','option')){
								?>
								<a href="tel:<?php echo get_field('phone','option'); ?>">Call Now</a>
								<?php	
								}
								?>
							</div>
							<?php
							}
							?>
						</div>
					</div>
					<div class="rst-mega-menu-center">
						<div class="rst-back-menu">
							<span>BACK</span>
							<svg width="13" height="9" viewBox="0 0 13 9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.5625 8.03516L5.88867 7.36133L1.20117 2.67383L0.527344 2L1.875 0.681641L2.51953 1.35547L6.5625 5.36914L10.5762 1.35547L11.25 0.681641L12.5684 2L11.8945 2.67383L7.20703 7.36133L6.5625 8.03516Z" fill="#C7202F"/></svg>
						</div>
			<?php
		}
		$output .=  ob_get_clean();
    }

    function end_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
		ob_start();
		$mega_menu = get_field('mega_menu',$item);
		$promotion = get_field('promotion',$item) ? get_field('promotion',$item) : 'current';
		if($mega_menu){
			?>
			</div>
			<div class="rst-mega-menu-right <?php echo $promotion == 'current' ? 'promotion-current' : 'promotion-featured'; ?>">
				<div class="rst-mega-menu-right-inner">
					<?php
						if($promotion == 'featured'){
					
						$featured_promotion = get_field('featured_promotion','option');
						if(is_array($featured_promotion) && !empty($featured_promotion)){
					
					?>
					<span>Featured Promotion</span>
					<h3><?php echo $featured_promotion['title']; ?></h3><p><?php echo $featured_promotion['description']; ?></p>
					<?php
						if($featured_promotion['promo_code']){
					?>
					<a href="#footer" data-promo="<?php echo $featured_promotion['promo_code']; ?>" class="use-promo-code">
						<svg width="13" height="15" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
						<path d="M10.5 10.375C10.9648 10.375 11.375 9.99219 11.375 9.5V3.92188C11.375 3.8125 11.3203 3.70312 11.2383 3.62109L9.37891 1.76172C9.29688 1.67969 9.1875 1.625 9.07812 1.625H6.125C5.63281 1.625 5.25 2.03516 5.25 2.5V9.5C5.25 9.99219 5.63281 10.375 6.125 10.375H10.5ZM11.8398 2.99219C12.0859 3.23828 12.25 3.59375 12.25 3.92188V9.5C12.25 10.4844 11.457 11.25 10.5 11.25H6.125C5.14062 11.25 4.375 10.4844 4.375 9.5V2.5C4.375 1.54297 5.14062 0.75 6.125 0.75H9.07812C9.40625 0.75 9.76172 0.914062 10.0078 1.16016L11.8398 2.99219ZM1.75 4.25H3.5V5.125H1.75C1.25781 5.125 0.875 5.53516 0.875 6V13C0.875 13.4922 1.25781 13.875 1.75 13.875H6.125C6.58984 13.875 7 13.4922 7 13V12.125H7.875V13C7.875 13.9844 7.08203 14.75 6.125 14.75H1.75C0.765625 14.75 0 13.9844 0 13V6C0 5.04297 0.765625 4.25 1.75 4.25Z" fill="#1B459B"/>
						</svg>
						<span>Use Promo Code: </span>
						<?php echo $featured_promotion['promo_code']; ?>
					</a>
					<?php
						}
						}
					?>
					<a href="#footer" data-code="<?php echo $featured_promotion['title']; ?>" class="get_this_deal">Get this deal</a>
					<?php
						}else{
							$current_promotion = get_field('current_promotion','option');
						if(is_array($current_promotion) && !empty($current_promotion)){
					?>
					<span>Current promotion</span>
					<h3><?php echo $current_promotion['title']; ?></h3>
					<p><?php echo $current_promotion['description']; ?></p>
					<?php
						if($current_promotion['image']){
					?>
					<img src="<?php echo $current_promotion['image']; ?>" alt="" />
					<?php
						}
					?>
					<?php
						}
						}
					?>
					
					
				</div>
			</div>
			</div></div>
			<?php
		}
		$output .=  ob_get_clean();
        $output .= '</li>';
    }

    function start_lvl( &$output, $depth = 0, $args = null ) {
        $output .= '<ul class="sub-menu">';
    }

    function end_lvl( &$output, $depth = 0, $args = null ) {
        $output .= '</ul>';
    }
}
function custom_wp_nav_menu_shortcode($atts) {
    $atts = shortcode_atts(
        array(
            'menu' => '',
            'container' => 'div',
            'container_class' => 'rst-main-menu-container',
            'menu_class' => 'menu',
        ),
        $atts,
        'smo_nav_menu'
    );
    if (!empty($atts['menu'])) {
        return wp_nav_menu(array(
            'menu' => $atts['menu'],
            'container' => $atts['container'],
            'container_class' => $atts['container_class'],
            'menu_class' => $atts['menu_class'],
			'walker'  => new Rst_Custom_Navigation(),
            'echo' => false
        ));
    }
}

add_shortcode('smo_nav_menu', 'custom_wp_nav_menu_shortcode');
<?php
//Pluign 
<?php

/**

 * Plugin Name: Smo Elementor Addon

 * Description: Simple widgets for Elementor.

 * Version:     1.0.0

 * Author:      Elementor Developer

 * Author URI:  https://developers.elementor.com/

 * Text Domain: elementor-addon

 */



function smo_register_widget( $widgets_manager ) {
	require_once( __DIR__ . '/widgets/smo_timeline.php' );
    $widgets_manager->register( new \Elementor_Timeline() );
}

add_action( 'elementor/widgets/register', 'smo_register_widget' );


//File shortcode 
class Elementor_Client_Logos extends \Elementor\Widget_Base {

	public function get_name() {
		return 'smo_client_logos';
	}

	public function get_title() {
		return esc_html__( 'Smo Client Logos', 'elementor-addon' );
	}

	public function get_icon() {
		return 'eicon-featured-image';
	}

	public function get_categories() {
		return [ 'basic' ];
	}

	public function get_keywords() {
		return [ 'Client Logos' ];
	}
	protected function register_controls() {
	
		$this->start_controls_section(
			'content_section',
			[
				'label' => esc_html__( 'Content', 'smo' ),
				'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
			]
		);
		$this->add_control(
			'list_top',
			[
				'label' => esc_html__( 'List Top', 'smo' ),
				'type' => \Elementor\Controls_Manager::REPEATER,
				'fields' => [
					[
						'name' => 'list1_image',
						'label' => esc_html__( 'Choose Image', 'smo' ),
						'type' => \Elementor\Controls_Manager::MEDIA,
						'default' => '',
					],
					[
						'name' => 'bg_color',
						'label' => esc_html__( 'Background Color', 'smo' ),
						'type' => \Elementor\Controls_Manager::COLOR,
						'default' => '#DDF780',
						'label_block' => true,
					],
					
				],
				'default' => [
					
				],
				'title_field' => '',
			]
		);
		$this->add_control(
			'list_bottom',
			[
				'label' => esc_html__( 'List Bottom', 'smo' ),
				'type' => \Elementor\Controls_Manager::REPEATER,
				'fields' => [
					[
						'name' => 'list2_image',
						'label' => esc_html__( 'Choose Image', 'smo' ),
						'type' => \Elementor\Controls_Manager::MEDIA,
						'default' => '',
					],
					[
						'name' => 'bg2_color',
						'label' => esc_html__( 'Background Color', 'smo' ),
						'type' => \Elementor\Controls_Manager::COLOR,
						'default' => '#DDF780',
						'label_block' => true,
					],
					
				],
				'default' => [
					
				],
				'title_field' => '',
			]
		);
		$this->end_controls_section();
		// Content Tab End
	}

	protected function render() {
		$settings = $this->get_settings_for_display();
		if ( is_array($settings['list_top']) && !empty($settings['list_top']) ) {
		?>
		
			<div class="rst-client-logos">
				<div class="rst-client-logos-container rst-client-logos-top">
					<div class="rst-client-logos-wrapper-container">
						<?php
							foreach (  $settings['list_top'] as $item ) {
								$bg = $item['bg_color'] ? $item['bg_color'] : '#DDF780';
						?>
						<?php
							if($item['list1_image']['url']){
						?>
						<div class="rst-client-logos-item">
							<div class="rst-client-logos-item-radius" style="background-color: <?php echo $bg; ?>">
								<img src="<?php echo $item['list1_image']['url']; ?>" alt="" />
							</div>
						</div>
						<?php
							}
							}
						?>
					</div>
					<div class="rst-client-logos-wrapper-container">
						<?php
							foreach (  $settings['list_top'] as $item ) {
								$bg = $item['bg_color'] ? $item['bg_color'] : '#DDF780';
						?>
						<?php
							if($item['list1_image']['url']){
						?>
						<div class="rst-client-logos-item">
							<div class="rst-client-logos-item-radius" style="background-color: <?php echo $bg; ?>">
								<img src="<?php echo $item['list1_image']['url']; ?>" alt="" />
							</div>
						</div>
						<?php
							}
							}
						?>
					</div>
				</div>
				<?php
					if ( is_array($settings['list_bottom']) && !empty($settings['list_bottom']) ) {
				?>
				<div class="rst-client-logos-container rst-client-logos-top">
					<div class="rst-client-logos-wrapper-container">
						<?php
							foreach (  $settings['list_bottom'] as $item ) {
								$bg2 = $item['bg2_color'] ? $item['bg2_color'] : '#DDF780';
						?>
						<?php
							if($item['list2_image']['url']){
						?>
						<div class="rst-client-logos-item">
							<div class="rst-client-logos-item-radius" style="background-color: <?php echo $bg2; ?>">
								<img src="<?php echo $item['list2_image']['url']; ?>" alt="" />
							</div>
						</div>
						<?php
							}
							}
						?>
					</div>
					<div class="rst-client-logos-wrapper-container">
						<?php
							foreach (  $settings['list_bottom'] as $item ) {
								$bg2 = $item['bg2_color'] ? $item['bg2_color'] : '#DDF780';
						?>
						<?php
							if($item['list2_image']['url']){
						?>
						<div class="rst-client-logos-item">
							<div class="rst-client-logos-item-radius" style="background-color: <?php echo $bg2; ?>">
								<img src="<?php echo $item['list2_image']['url']; ?>" alt="" />
							</div>
						</div>
						<?php
							}
							}
						?>
					</div>
				</div>
				<?php
					}
				?>
			</div>
		
		<?php
		}
	}
}
function smo_custom_slider_service_shortcode($atts = []){
	$atts = shortcode_atts([
		'list_service' => [],
	],$atts);
	ob_start();
	$list_service = vc_param_group_parse_atts($atts['list_service']);
	
	if(is_array($list_service) && !empty($list_service)):
	?>
	<div class="smo-list-service-wrapper-container">
		<div class="list-service-deskop">
			<div class="list-service-row">
				<?php
					foreach ($list_service as $key => $value) {
				?>
				<div>
					<a class="rst-item-service" href="<?php echo $value['link']; ?>">
						<?php echo $value['title']; ?>
					</a>
				</div>	
				<?php
					}
				?>
			</div>
		</div>
		<div class="list-service-mobile">
			<div class="swiper list_service_slider"> 
				<div class="swiper-wrapper">
				<?php
					foreach ($list_service as $key => $value) {
				?>
				<div class="swiper-slide">
					<a class="rst-item-service" href="<?php echo $value['link']; ?>">
						<?php echo $value['title']; ?>
					</a>
				</div>
				<?php
					}
				?>
				</div>
			</div>
		</div>
	</div>
	<?php	
	endif;
	return ob_get_clean();
}
add_shortcode('smo_custom_slider_service','smo_custom_slider_service_shortcode');

add_action( 'vc_before_init', 'smo_custom_slider_service_map' );
function smo_custom_slider_service_map(){
	vc_map( array(
	  "name" => __( "Custom Service"),
	  "base" => "smo_custom_slider_service",
	  "class" => "",
	  "category" => __( "SMO"),
	  "params" => array(
		 array(
		  "type" => "param_group", 
		  'param_name' => 'list_service', 
		  "heading" => __( "List Service"),
		  'params' => array(
		  	 
			 array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Title',
				  'param_name' => 'title',
		     ), 
			  array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Link',
				  'param_name' => 'link',
		     ), 
		  ),
		 )
	  )
 ) );
}
function smo_custom_slider_key_figures_shortcode($atts = []){
	$atts = shortcode_atts([
		'list_key_figures' => [],
	],$atts);
	ob_start();
	$key_figures = vc_param_group_parse_atts($atts['list_key_figures']);
	shuffle($key_figures);
	if(is_array($key_figures) && !empty($key_figures)):
	?>
	<div class="smo-list-key-figures-wrapper-container">
		<div class="swiper list_key_figures_slider"> 
			<div class="swiper-wrapper">
			<?php
				foreach ($key_figures as $key => $item) {
			?>
				
				<div class="swiper-slide">
			<div class=" rst-item-key-figures">
				<div class="rst-item-key-figures-value counter">
					<?php echo $item['value']; ?>
				</div>
				<p class="rst-item-key-figures-label"><?php echo $item['label']; ?></p>
			</div>
					</div>
			<?php
				}
			?>
			</div>
		</div>
	</div>
	<?php	
	endif;
	return ob_get_clean();
}
add_shortcode('smo_custom_slider_key_figures','smo_custom_slider_key_figures_shortcode');

add_action( 'vc_before_init', 'smo_custom_slider_key_figures_map' );
function smo_custom_slider_key_figures_map(){
	vc_map( array(
	  "name" => __( "Key Figures"),
	  "base" => "smo_custom_slider_key_figures",
	  "class" => "",
	  "category" => __( "SMO"),
	  "params" => array(
		 array(
		  "type" => "param_group", 
		  'param_name' => 'list_key_figures', 
		  "heading" => __( "List Key Figures"),
		  'params' => array(
		  	 
			 array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Value',
				  'param_name' => 'value',
		     ), 
			  array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Label',
				  'param_name' => 'label',
		     ), 
		  ),
		 )
	  )
 ) );
}

function smo_custom_slider_teams_shortcode($atts = []){
	$atts = shortcode_atts([
		'list_teams' => [],
	],$atts);
	ob_start();
	$list_teams = vc_param_group_parse_atts($atts['list_teams']);
	
	if(is_array($list_teams) && !empty($list_teams)):
	?>
	<div class="smo-list-team-wrapper-container">
		<div class="swiper list_teams_slider"> 
			<div class="swiper-wrapper">
			<?php
				foreach ($list_teams as $key => $item) {
			?>
			<div class="swiper-slide rst-item-team">
				<div class="rst-team-avatar">
					<img src="<?php echo wp_get_attachment_url($item['avatar']) ?>" alt="" />
					<div class="rst-team-avatar-description">
						<?php echo $item['description']; ?>
					</div>
				</div>
				<div class="rst-team-info">
					<h4>
						<?php
							if($item['fname']){
						?>
						<span><?php echo $item['fname']; ?></span>
						<?php
							}
						?>
						<?php echo $item['lname']; ?>
					</h4>
					<div class="rst-team-info-social">
					<?php
						if($item['email']){
					?>
						<div class="rst-team-info-email">
							<a href="mailto:<?php echo $item['email']; ?>"><span class="rst-team-info-icon"><svg width="25" height="21" viewBox="0 0 25 21" fill="none" xmlns="http://www.w3.org/2000/svg">
							<g clip-path="url(#clip0_512_950)">
							<path opacity="0.986" fill-rule="evenodd" clip-rule="evenodd" d="M1.87755 1.73525C8.95951 1.7264 16.0415 1.73525 23.1234 1.76181C23.2665 1.7984 23.3976 1.86037 23.5169 1.94771C20.2798 5.47028 17.0339 8.98467 13.7792 12.491C12.9267 13.2346 12.0743 13.2346 11.2218 12.491C7.98412 8.99429 4.7464 5.49753 1.5087 2.00083C1.47488 1.95665 1.48308 1.92124 1.53329 1.8946C1.65705 1.85052 1.7718 1.7974 1.87755 1.73525Z" fill="white"/>
							<path opacity="0.974" fill-rule="evenodd" clip-rule="evenodd" d="M0.647542 2.79724C0.69928 2.78933 0.74846 2.79814 0.795083 2.8238C3.31215 5.53339 5.82033 8.25106 8.31967 10.9769C5.82033 13.7028 3.31215 16.4204 0.795083 19.13C0.74846 19.1557 0.69928 19.1645 0.647542 19.1566C0.601839 18.9639 0.560852 18.7692 0.524591 18.5723C0.491803 13.5087 0.491803 8.44509 0.524591 3.3815C0.560852 3.18461 0.601839 2.98989 0.647542 2.79724Z" fill="white"/>
							<path opacity="0.974" fill-rule="evenodd" clip-rule="evenodd" d="M24.2053 2.79736C24.2544 2.79736 24.3036 2.79736 24.3528 2.79736C24.3985 2.99001 24.4395 3.18473 24.4757 3.38163C24.5085 8.44521 24.5085 13.5089 24.4757 18.5724C24.4395 18.7693 24.3985 18.9641 24.3528 19.1567C24.3011 19.1646 24.2519 19.1558 24.2053 19.1301C21.6882 16.4205 19.18 13.7029 16.6807 10.977C19.1899 8.24938 21.6981 5.52279 24.2053 2.79736Z" fill="white"/>
							<path opacity="0.984" fill-rule="evenodd" clip-rule="evenodd" d="M9.00869 11.827C9.06043 11.8191 9.10961 11.8279 9.15624 11.8536C9.76583 12.5475 10.4052 13.2025 11.0743 13.8188C12.1644 14.4065 13.2136 14.3357 14.2218 13.6064C14.7628 13.0221 15.3038 12.4378 15.8448 11.8536C15.8939 11.8182 15.9431 11.8182 15.9923 11.8536C18.5093 14.5632 21.0175 17.2808 23.5169 20.0067C23.3976 20.0941 23.2665 20.156 23.1234 20.1926C16.0415 20.228 8.95951 20.228 1.87755 20.1926C1.76093 20.1536 1.64618 20.1093 1.53329 20.0598C1.48308 20.0331 1.47488 19.9978 1.5087 19.9536C4.0186 17.2517 6.5186 14.5429 9.00869 11.827Z" fill="white"/>
							</g>
							<defs>
							<clipPath id="clip0_512_950">
							<rect width="25" height="20" fill="white" transform="translate(0 0.975586)"/>
							</clipPath>
							</defs>
							</svg></span>
							<span class="rst-team-info-text"><?php echo $item['email']; ?></span></a>
						</div>
						<?php
							}
						?>
						<?php
							if($item['phone']){
						?>
						<div class="rst-team-info-phone">
							<a href="tell:<?php echo $item['phone']; ?>">
							<span class="rst-team-info-icon"><svg width="25" height="21" viewBox="0 0 25 21" fill="none" xmlns="http://www.w3.org/2000/svg">
							<path opacity="0.989" fill-rule="evenodd" clip-rule="evenodd" d="M6.13618 0.983333C6.72752 0.933604 7.20612 1.12328 7.57201 1.55236C8.58955 2.82768 9.47314 4.18251 10.2228 5.61687C10.3446 5.89212 10.4256 6.17663 10.4658 6.47041C10.4487 6.68685 10.3824 6.89007 10.267 7.08009C9.75677 7.5901 9.20453 8.05752 8.61023 8.48234C9.69006 11.2032 11.7076 13.0661 14.6628 14.071C15.0011 13.7258 15.3325 13.3736 15.6568 13.0143C15.9678 12.6444 16.3727 12.4277 16.8718 12.3639C17.5921 12.4923 18.2695 12.7294 18.904 13.0752C20.0589 13.691 21.1781 14.3549 22.2617 15.0668C22.8562 15.5282 22.9813 16.0769 22.6372 16.713C22.0146 17.4755 21.3004 18.1596 20.4945 18.7655C19.6539 19.43 18.7409 19.999 17.7554 20.4726C17.0173 20.494 16.2957 20.3992 15.5906 20.1881C13.8497 19.6718 12.2298 18.9402 10.7308 17.9933C7.20254 15.7501 4.50025 12.8575 2.62392 9.31557C2.16625 8.36398 1.84227 7.37493 1.65197 6.34848C1.62252 6.11814 1.62252 5.88785 1.65197 5.65751C2.62991 3.99854 3.90375 2.55564 5.47349 1.32882C5.68423 1.1914 5.90512 1.07624 6.13618 0.983333Z" fill="white"/>
							</svg></span>
							<span class="rst-team-info-text"><?php echo $item['phone']; ?></span></a>
						</div>
						<?php
							}
						?>
					</div>
				</div>
			</div>
			<?php
				}
			?>
			</div>
		</div>
	</div>
	<?php	
	endif;
	return ob_get_clean();
}
add_shortcode('smo_custom_slider_teams','smo_custom_slider_teams_shortcode');

add_action( 'vc_before_init', 'smo_custom_slider_teams_map' );
function smo_custom_slider_teams_map(){
	vc_map( array(
	  "name" => __( "List Teams"),
	  "base" => "smo_custom_slider_teams",
	  "class" => "",
	  "category" => __( "SMO"),
	  "params" => array(
		 array(
		  "type" => "param_group", 
		  'param_name' => 'list_teams', 
		  "heading" => __( "List Teams"),
		  'params' => array(
		  	 array(
				  'type' => 'attach_image',
				  'value' => '',
				  'heading' => 'Avatar',
				  'param_name' => 'avatar',
		     ),
			 array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'First Name',
				  'param_name' => 'fname',
		     ), 
			 array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Last Name',
				  'param_name' => 'lname',
		     ), 
			  array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Email',
				  'param_name' => 'email',
		     ), 
			  array(
				  'type' => 'textfield',
				  'value' => '',
				  'heading' => 'Phone',
				  'param_name' => 'phone',
		     ),
			 array(
				  'type' => 'textarea',
				  'value' => '',
				  'heading' => 'Description',
				  'param_name' => 'description',
		     ),
		  ),
		 )
	  )
 ) );
}
<a href="https://twitter.com/intent/tweet?text=<?php the_title(); ?>&amp;url=<?php echo get_the_permalink(); ?>" class="social-link" target="_blank" rel="noopener noreferrer follow" data-wpel-link="internal">
        <svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
            <rect width="28" height="28" rx="4" fill="#43414F"></rect>
            <path d="M19.9222 4.66675H23.0741L16.1883 12.5742L24.2888 23.3334H17.9457L12.9779 16.8085L7.2928 23.3334H4.13916L11.504 14.8763L3.7334 4.66675H10.237L14.7275 10.6315L19.9222 4.66675ZM18.8157 21.4381H20.5627L9.28848 6.46302H7.41409L18.8157 21.4381Z" fill="white"></path>
        </svg>
    </a>
<a href="https://www.facebook.com/sharer/sharer.php?u=<?php echo get_the_permalink(); ?>" class="social-link" target="_blank" rel="noopener noreferrer follow" data-wpel-link="internal">
      <svg width="28" height="28" class="facebook" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg">
        <g clip-path="url(#clip0_3307_57195)">
          <path d="M24.889 1.60787e-07H3.11C2.7015 1.39669e-07 2.29701 0.0804758 1.91962 0.23683C1.54224 0.393185 1.19935 0.622355 0.910544 0.911252C0.621741 1.20015 0.392681 1.54311 0.236448 1.92055C0.0802144 2.29799 -0.000131188 2.70251 1.60787e-07 3.111V24.89C1.39669e-07 25.2985 0.0804758 25.703 0.23683 26.0804C0.393185 26.4578 0.622355 26.8007 0.911252 27.0895C1.20015 27.3783 1.54311 27.6073 1.92055 27.7636C2.29799 27.9198 2.70251 28.0001 3.111 28H14.966V17.172H11.321V12.932H14.966V9.815C14.966 6.2 17.176 4.229 20.403 4.229C21.4898 4.22651 22.5759 4.28092 23.657 4.392V8.172H21.436C19.678 8.172 19.336 9.003 19.336 10.229V12.928H23.536L22.99 17.167H19.31V28H24.889C25.2976 28.0001 25.7022 27.9198 26.0797 27.7635C26.4572 27.6072 26.8002 27.378 27.0891 27.0891C27.378 26.8002 27.6072 26.4572 27.7635 26.0797C27.9198 25.7022 28.0001 25.2976 28 24.889V3.11C28 2.7015 27.9195 2.29701 27.7632 1.91962C27.6068 1.54224 27.3776 1.19935 27.0887 0.910544C26.7999 0.621741 26.4569 0.392681 26.0795 0.236448C25.702 0.0802144 25.2975 -0.000131188 24.889 1.60787e-07Z"></path>
        </g>
        <defs>
          <clipPath id="clip0_3307_57195">
            <rect width="28" height="28" fill="white"></rect>
          </clipPath>
        </defs>
      </svg>
    </a>
<a href="https://www.linkedin.com/sharing/share-offsite/?url=<?php echo get_the_permalink(); ?>" class="social-link" target="_blank" rel="noopener noreferrer follow" data-wpel-link="internal">
      <svg width="28" height="28" class="linkedin h-p-0-lg h-mb-3-lg" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg">
        <g clip-path="url(#clip0_3302_57044)">
          <path d="M24.889 1.60787e-07H3.11C2.7015 1.39669e-07 2.29701 0.0804758 1.91962 0.23683C1.54224 0.393185 1.19935 0.622355 0.910544 0.911252C0.621741 1.20015 0.392681 1.54311 0.236448 1.92055C0.0802144 2.29799 -0.000131188 2.70251 1.60787e-07 3.111V24.89C1.39669e-07 25.2985 0.0804758 25.703 0.23683 26.0804C0.393185 26.4578 0.622355 26.8007 0.911252 27.0895C1.20015 27.3783 1.54311 27.6073 1.92055 27.7636C2.29799 27.9198 2.70251 28.0001 3.111 28H24.89C25.2985 28 25.703 27.9195 26.0804 27.7632C26.4578 27.6068 26.8007 27.3776 27.0895 27.0887C27.3783 26.7999 27.6073 26.4569 27.7636 26.0795C27.9198 25.702 28.0001 25.2975 28 24.889V3.11C28 2.7015 27.9195 2.29701 27.7632 1.91962C27.6068 1.54224 27.3776 1.19935 27.0887 0.910544C26.7999 0.621741 26.4569 0.392681 26.0795 0.236448C25.702 0.0802144 25.2975 -0.000131188 24.889 1.60787e-07ZM9.333 21.778H5.41V10.888H9.334V21.778H9.333ZM7.302 8.893C6.102 8.893 5.302 8.093 5.302 7.026C5.302 5.959 6.1 5.16 7.433 5.16C8.633 5.16 9.433 5.96 9.433 7.026C9.433 8.094 8.633 8.893 7.301 8.893H7.302ZM23.333 21.778H19.535V15.826C19.535 14.18 18.522 13.801 18.142 13.801C17.762 13.801 16.497 14.054 16.497 15.826V21.778H12.572V10.888H16.497V12.408C17.002 11.522 18.015 10.888 19.914 10.888C21.814 10.888 23.334 12.408 23.334 15.826V21.778H23.333Z"></path>
        </g>
        <defs>
          <clipPath id="clip0_3302_57044">
            <rect width="28" height="28" fill="white"></rect>
          </clipPath>
        </defs>
      </svg>
    </a>
<a href="mailto:?subject=<?php the_title(); ?>&amp;body=Article:<?php echo get_the_permalink(); ?>" class="social-link" target="_blank" rel="nofollow noopener noreferrer">
      <svg width="28" height="28" class="mail h-p-0-lg h-mb-3-lg" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg">
        <path d="M2.8 3.00001C2.12163 2.99621 1.4654 3.24121 0.955496 3.68864C0.445591 4.13608 0.117389 4.7549 0.033 5.42801L14 14L27.967 5.42801C27.8826 4.7549 27.5544 4.13608 27.0445 3.68864C26.5346 3.24121 25.8784 2.99621 25.2 3.00001H2.8ZM0 8.15901V22.25C0 23.77 1.253 25 2.8 25H25.2C26.747 25 28 23.77 28 22.25V8.15901L14.741 16.296C14.5178 16.4323 14.2615 16.5043 14 16.5043C13.7385 16.5043 13.4822 16.4323 13.259 16.296L0 8.16001V8.15901Z"></path>
      </svg>
    </a>
if ( ! function_exists( 'rst_the_posts_navigation' ) ) :
/**
 * Display navigation to next/previous set of posts when applicable.
 *
 * @todo Remove this function when WordPress 4.3 is released.
 */
function rst_the_posts_navigation($query) {
	// Don't print empty markup if there's only one page.
	if ( $query->max_num_pages < 2 ) {
		return;
	}
	$big = 999999999;
	$my_page = max( get_query_var('paged'), get_query_var('page') );
	$paginate_links = paginate_links( array(
		'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
		'format' => '?paged=%#%',
		'current' => max( 1, $my_page ),
		'total' => $query->max_num_pages,
		'prev_text'    => '<svg width="6" height="11" viewBox="0 0 6 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.64844 5.10156C5.85938 5.33594 5.85938 5.6875 5.64844 5.89844L1.14844 10.3984C0.914062 10.6328 0.5625 10.6328 0.351562 10.3984C0.117188 10.1875 0.117188 9.83594 0.351562 9.625L4.45312 5.52344L0.351562 1.39844C0.117188 1.1875 0.117188 0.835938 0.351562 0.625C0.5625 0.390625 0.914062 0.390625 1.125 0.625L5.64844 5.10156Z" fill="#0A5660"/>
</svg>

',
		'next_text'    => '<svg width="6" height="11" viewBox="0 0 6 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.64844 5.10156C5.85938 5.33594 5.85938 5.6875 5.64844 5.89844L1.14844 10.3984C0.914062 10.6328 0.5625 10.6328 0.351562 10.3984C0.117188 10.1875 0.117188 9.83594 0.351562 9.625L4.45312 5.52344L0.351562 1.39844C0.117188 1.1875 0.117188 0.835938 0.351562 0.625C0.5625 0.390625 0.914062 0.390625 1.125 0.625L5.64844 5.10156Z" fill="#0A5660"/>
</svg>

',
		'type'			=> 'array'
	 ));
	
	if( is_array( $paginate_links ) ) {
		$paged = ( $my_page == 0 ) ? 1 : $my_page;
		echo '<div id="tf-pagination">';
			echo '<nav class="wp-pagenavi">';
				
				foreach ( $paginate_links as $page ) {
					echo force_balance_tags($page);
				}
			
			echo '</nav>';
		echo '</div>';
	}
}
endif;
function smo_post_navigation_shortcode() {
	ob_start();
	?>
	<nav class="navigation post-navigation" role="navigation">
		<div class="nav-links">
			<?php
			$prev_post = get_previous_post(true);
			if (!empty($prev_post)) {
					?>
					<div class="prev-post">
						<a href="<?php echo get_permalink($prev_post->ID); ?>" class="click-icon"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.28125 7.46875C0.046875 7.23438 0.046875 6.80469 0.28125 6.57031L6.53125 0.320312C6.76562 0.0859375 7.19531 0.0859375 7.42969 0.320312C7.66406 0.554688 7.66406 0.984375 7.42969 1.21875L1.60938 7L7.42969 12.8203C7.66406 13.0547 7.66406 13.4844 7.42969 13.7188C7.19531 13.9531 6.76562 13.9531 6.53125 13.7188L0.28125 7.46875Z" fill="#027DC0"/>
</svg>
</a>
						<div class="infor-post-navigation">
							<h6>Previous NEWS</h6>
							<p><?php echo esc_html($prev_post->post_title); ?></p>
						</div>
					</div>
					<?php
						}else{
				echo '<div></div>';
			}
					?>
					<?php
			$next_post = get_next_post(true);
			if (!empty($next_post)) {
					?>
					<div class="next-post">
						<div class="infor-post-navigation">
							<h6>NEXT NEWS</h6>
							<p><?php echo esc_html($next_post->post_title); ?></p>
						</div>
						<a href="<?php echo get_permalink($next_post->ID); ?>" class="click-icon"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.67969 6.57031C7.91406 6.80469 7.91406 7.23438 7.67969 7.46875L1.42969 13.7188C1.19531 13.9531 0.765625 13.9531 0.53125 13.7188C0.296875 13.4844 0.296875 13.0547 0.53125 12.8203L6.35156 7L0.53125 1.21875C0.296875 0.984375 0.296875 0.554688 0.53125 0.320312C0.765625 0.0859375 1.19531 0.0859375 1.42969 0.320312L7.67969 6.57031Z" fill="#027DC0"/>
</svg>

						</a>
					</div>
					<?php
						}else{
				echo '<div></div>';
			}
	?>
		</div><!-- .nav-links -->
	</nav><!-- .navigation -->
	<?php
	return ob_get_clean();
}
add_shortcode('smo_post_navigation', 'smo_post_navigation_shortcode');
star

Wed Aug 20 2025 15:13:51 GMT+0000 (Coordinated Universal Time) https://codepen.io/rustcode/pen/YPPbxYX

@CallTheCops #undefined

star

Wed Aug 20 2025 15:05:47 GMT+0000 (Coordinated Universal Time) https://codepen.io/rustcode/pen/YPPbxYX

@CallTheCops #undefined

star

Wed Aug 20 2025 14:18:20 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Tue Aug 19 2025 18:40:28 GMT+0000 (Coordinated Universal Time)

@reiddd #javascript

star

Tue Aug 19 2025 16:12:49 GMT+0000 (Coordinated Universal Time) https://soulvacation.in/resort-in-south-goa/

@dagapam705

star

Tue Aug 19 2025 05:58:33 GMT+0000 (Coordinated Universal Time)

@FOHWellington

star

Mon Aug 18 2025 11:43:20 GMT+0000 (Coordinated Universal Time) https://maticz.com/rummy-game-development

@austinparker #rummy #rummygame #rummygamedevelopment #rummygameapp

star

Mon Aug 18 2025 05:58:16 GMT+0000 (Coordinated Universal Time)

@Diyorbek21

star

Mon Aug 18 2025 03:31:25 GMT+0000 (Coordinated Universal Time)

@quanganh141220 #wordpress #divi #menumobile

star

Mon Aug 18 2025 03:30:31 GMT+0000 (Coordinated Universal Time)

@quanganh141220 #wordpress #divi #menumobile

star

Mon Aug 18 2025 03:29:48 GMT+0000 (Coordinated Universal Time)

@quanganh141220 #wordpress #divi #menumobile

star

Sun Aug 17 2025 15:00:07 GMT+0000 (Coordinated Universal Time)

@E23CSEU1151

star

Sun Aug 17 2025 09:13:15 GMT+0000 (Coordinated Universal Time)

@E23CSEU1151

star

Sun Aug 17 2025 06:06:20 GMT+0000 (Coordinated Universal Time)

@MinaTimo

star

Sat Aug 16 2025 09:09:55 GMT+0000 (Coordinated Universal Time) https://www.allassignmenthelp.com/pay-someone-to-take-my-online-class.html

@payforonline

star

Sat Aug 16 2025 02:21:12 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:20:16 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:19:57 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:18:00 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:15:26 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:12:54 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:12:09 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:11:35 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:10:56 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:09:46 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:08:41 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:07:54 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:06:00 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:05:34 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Sat Aug 16 2025 02:04:32 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 23:54:54 GMT+0000 (Coordinated Universal Time)

@wizyOsva #bash

star

Fri Aug 15 2025 21:33:20 GMT+0000 (Coordinated Universal Time)

@procodefinder

star

Fri Aug 15 2025 17:50:19 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 17:31:01 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 17:29:03 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 17:28:09 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 17:27:35 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 17:15:05 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 16:38:54 GMT+0000 (Coordinated Universal Time)

@jrg_300i #docker

star

Fri Aug 15 2025 08:02:43 GMT+0000 (Coordinated Universal Time)

@merol007

star

Fri Aug 15 2025 03:05:30 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 03:04:08 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 03:02:04 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 02:59:31 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 02:57:53 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 02:55:26 GMT+0000 (Coordinated Universal Time)

@vanthien

star

Fri Aug 15 2025 02:54:11 GMT+0000 (Coordinated Universal Time)

@vanthien #jq

star

Fri Aug 15 2025 02:53:24 GMT+0000 (Coordinated Universal Time)

@vanthien #jq

star

Fri Aug 15 2025 02:52:24 GMT+0000 (Coordinated Universal Time)

@vanthien #jq

star

Fri Aug 15 2025 02:51:03 GMT+0000 (Coordinated Universal Time)

@vanthien #jq

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension