import torch
import torch.distributed as dist
import numpy as np
import math
from .misc import reduce_tensor, gather_tensors_to_list
from typing import Tuple
import copy
from typing import List, Dict, Union

class Metrics:
    """Compute metrics (batch-wise average).

    Available metrics: `Precision`, `Recall`, `F1`, `Mean`, `Std`, `MAE`, `MAPE`, `R2`
    """

    _epsilon = 1e-6
    _avl_regr_keys = ("sum_res", "sum_squ_res", "sum_abs_res", "sum_abs_per_res")
    _avl_cmat_keys = ("tp", "predp", "possp")
    _avl_metrics = ("precision", "recall", "f1", "mean", "std", "mae", "mape", "r2")

    def __init__(
        self,
        task: str,
        metric_names: Union[list, tuple],
        sampling_rate: int,
        time_threshold: int,
        num_samples: int,
        device: torch.device,
    ) -> None:
        """
        Args:
            task: str
                Task name. See :class:`SeisT.config.Config` for more details.
            metric_names:Union[list,tuple]
                Names of metrics.
            sampling_rate:int
                Sampling rate of waveform.
            time_threshold:int
                Threshold for phase-picking.
            num_samples:int
                Number of samples of waveform.
            device: torch.device
                Device.
        """

        self.device = device

        self._t_thres = int(time_threshold * sampling_rate)

        self._task = task.lower()
        self._metric_names = tuple(n.lower() for n in metric_names)

        self._num_samples = num_samples

        unexpected_keys = set(self._metric_names) - set(self._avl_metrics)
        assert set(self._metric_names).issubset(
            self._avl_metrics
        ), f"Unexpected metrics:{unexpected_keys}"

        data_keys = self._metric_names
        if set(self._metric_names) & set(("precision", "recall", "f1")):
            data_keys += self._avl_cmat_keys
        if set(self._metric_names) & set(("mean", "std", "mae", "mape")):
            data_keys += self._avl_regr_keys

        self._data={
            k: torch.tensor(0, dtype=torch.float32, device=self.device)
            for k in data_keys
        }
        self._data["data_size"] = torch.tensor(0, dtype=torch.long, device=self.device)

        self._tgts: torch.Tensor = None

        self._results: Dict[str,float] = {}

        self._modified = True

    def synchronize_between_processes(self):
        """
        Synchronize metrics between processes
        """
        dist.barrier()

        for k in self._data:
            self._data[k] = reduce_tensor(self._data[k])

        if isinstance(self._tgts, torch.Tensor):
            tgts_list = gather_tensors_to_list(self._tgts)
            self._tgts = torch.cat(tgts_list, dim=0)

        dist.barrier()

        self._modified = True

    def _order_phases(
        self, targets: torch.Tensor, preds: torch.Tensor
    ) -> Tuple[torch.Tensor, torch.Tensor]:
        """Match the order of predictions and labels"""

        num_phases = targets.size(-1)
        _targets = targets.clone().detach().cpu().numpy()
        _preds = preds.clone().detach().cpu().numpy()

        for i, (target_i, pred_i) in enumerate(zip(_targets, _preds)):
            orderd = np.zeros_like(pred_i)
            dmat = np.abs(
                target_i[:, np.newaxis].repeat(num_phases, axis=1)
                - pred_i[np.newaxis, :].repeat(num_phases, axis=0)
            )
            for _ in range(num_phases):
                ind = dmat.argmin()
                ito, ifr = ind // num_phases, ind % num_phases
                orderd[ito] = pred_i[ifr]
                dmat[ito, :] = int(1 / self._epsilon)
                dmat[:, ifr] = int(1 / self._epsilon)
            _preds[i] = orderd

        preds.copy_(torch.from_numpy(_preds))
        return targets, preds

    @torch.no_grad()
    def compute(
        self, targets: torch.Tensor, preds: torch.Tensor, reduce: bool = False
    ) -> None:
        """
        Args:
            targets: torch.Tensor
                Labels. Shape: (N, L), (N, Classes), (N, 2 * D) or (N, 1)
            preds: torch.Tensor
                Predictions. Shape: (N, L), (N, Classes), (N, 2 * D) or (N, 1)
            reduce: bool
                For distributed training.
        """
        assert targets.size(0) == preds.size(0), f"`{targets.size()}` != `{preds.size()}`"
        assert targets.dim() == 2, f"dim:{targets.dim()}, shape:{targets.size()}"

        self._data["data_size"] += targets.size(0)

        targets = targets.clone().detach().to(self.device)
        preds = preds.clone().detach().to(self.device)
        mask = 1.0

        if set(self._metric_names) & set(("precision", "recall", "f1")):
            if self._task in ["ppk", "spk"]:
                targets = targets.type(torch.long)
                preds = preds.type(torch.long)
                if targets.size(-1) > 1:
                    targets, preds = self._order_phases(targets, preds)

                preds_bin = (preds >= 0) & (preds < self._num_samples)
                targets_bin = (targets >= 0) & (targets < self._num_samples)

                ae = torch.abs(targets - preds)
                mask = tp_bin = preds_bin & targets_bin & (ae <= self._t_thres)

                self._data["tp"] = torch.sum(tp_bin)
                self._data["predp"] = torch.sum(preds_bin)
                self._data["possp"] = torch.sum(targets_bin)

            elif self._task in ["det"]:
                targets = targets.type(torch.long)
                preds = preds.type(torch.long)

                bs = targets.size(0)

                targets = targets.reshape(bs,-1,2)
                preds = preds.reshape(bs,-1,2)

                indices = torch.arange(self._num_samples,device=self.device).unsqueeze(0).unsqueeze(0)

                targets_bin = torch.sum((targets[:,:,:1] <= indices) & (indices <=targets[:,:,1:]),dim=-2)
                preds_bin = torch.sum((preds[:,:,:1] <= indices) & (indices <=preds[:,:,1:]),dim=-2)

                self._data["tp"] = torch.sum(
                    torch.round(torch.clip(targets_bin * preds_bin, 0, 1))
                )
                self._data["predp"] = torch.sum(
                    torch.round(torch.clip(preds_bin, 0, 1))
                )
                self._data["possp"] = torch.sum(
                    torch.round(torch.clip(targets_bin, 0, 1))
                )

            else:
                assert (
                    targets.size() == preds.size()
                ), f"`{targets.size()}` != `{preds.size()}`"
                assert targets.size(-1) > 1, f"The input must be one-hot."

                # Scatter is faster than fancy indexing.
                preds_indices = preds.topk(1).indices
                preds = preds.zero_().scatter_(dim=1,index=preds_indices,value=1)

                targets_indices = targets.topk(1).indices
                targets = targets.zero_().scatter_(dim=1,index=targets_indices,value=1)

                self._data["tp"] = torch.sum(targets * preds, dim=0)
                self._data["predp"] = torch.sum(preds, dim=0)
                self._data["possp"] = torch.sum(targets, dim=0)

        if set(self._metric_names) & set(("mean", "std", "mae", "mape", "r2")):
            res = targets - preds
            # BAZ
            if self._task in ["baz"]:
                res = torch.where(
                    res.abs() > 180, -torch.sign(res) * (360 - res.abs()), res
                )

            if "mean" in self._metric_names:
                self._data["sum_res"] = (res * mask).type(torch.float32).mean(-1).sum()

            if "std" in self._metric_names:
                self._data["sum_squ_res"] = (
                    torch.pow(res * mask, 2).type(torch.float32).mean(-1).sum()
                )

            if "mae" in self._metric_names:
                self._data["sum_abs_res"] = (
                    (res * mask).abs().type(torch.float32).mean(-1).sum()
                )

            if "mape" in self._metric_names:
                self._data["sum_abs_per_res"] = (
                    (res * mask / (targets + self._epsilon))
                    .abs()
                    .type(torch.float32)
                    .mean(-1)
                    .sum()
                )

            if "r2" in self._metric_names:
                self._tgts = targets
                if "sum_squ_res" not in self._data:
                    self._data["sum_squ_res"] = (
                        torch.pow(res * mask, 2).type(torch.float32).mean(-1).sum()
                    )

        if reduce:
            self.synchronize_between_processes()

        self._modified = True

    def add(self, b) -> None:
        if not type(self) == type(b):
            raise TypeError(f"Type of `b` must be `Metrics`, got `{type(b)}`")

        if (set(self._data) | set(b._data)) - (set(self._data) & set(b._data)):
            raise TypeError(
                f"Mismatched data fields: `{set(self._data)}` and `{set(b._data)}`"
            )

        for k in self._data:
            self._data[k] = self._data[k] + b._data[k]

        tgts_to_cat = list(
            filter(lambda x: isinstance(x, torch.Tensor), [self._tgts, b._tgts])
        )
        if tgts_to_cat:
            self._tgts = torch.cat(tgts_to_cat, dim=0)

        self._modified = True

    def __add__(a, b):
        if not type(a) == type(b):
            raise TypeError(
                f"Unsupported operand type(s) for `+`: `{type(a)}` and `{type(b)}`"
            )

        if (set(a._data) | set(b._data)) - (set(a._data) & set(b._data)):
            raise TypeError(
                f"Mismatched data fields: `{set(a._data)}` and `{set(b._data)}`"
            )

        c = copy.deepcopy(a)
        for k in c._data:
            c._data[k] = a._data[k] + b._data[k]

        tgts_to_cat = list(
            filter(lambda x: isinstance(x, torch.Tensor), [a._tgts, b._tgts])
        )
        if tgts_to_cat:
            c._tgts = torch.cat(tgts_to_cat, dim=0)
        c._modified = True

        return c

    def _update_metric(self, key: str) -> torch.Tensor:
        """Update value of metric."""

        if key == "precision":
            v = self._data["precision"] = (
                self._data["tp"] / (self._data["predp"] + self._epsilon)
            ).mean()
        elif key == "recall":
            v = self._data["recall"] = (
                self._data["tp"] / (self._data["possp"] + self._epsilon)
            ).mean()
        elif key == "f1":
            pr = self._data["tp"] / (self._data["predp"] + self._epsilon)
            re = self._data["tp"] / (self._data["possp"] + self._epsilon)
            v = self._data["f1"] = (2 * pr * re / (pr + re + self._epsilon)).mean()
        elif key == "mean":
            v = self._data["mean"] = self._data["sum_res"] / self._data["data_size"]
        elif key == "std":
            v = self._data["std"] = torch.sqrt(
                self._data["sum_squ_res"] / self._data["data_size"]
            )
        elif key == "mae":
            v = self._data["mae"] = self._data["sum_abs_res"] / self._data["data_size"]
        elif key == "mape":
            v = self._data["mape"] = (
                self._data["sum_abs_per_res"] / self._data["data_size"]
            )
        elif key == "r2":
            t = self._tgts - self._tgts.mean()
            # BAZ
            if self._task in ["baz"]:
                t = torch.where(t.abs() > 180, -torch.sign(t) * (360 - t.abs()), t)
            v = 1 - (
                self._data["sum_squ_res"]
                / (torch.pow(t, 2).mean(-1).sum() + self._epsilon)
            )
        else:
            raise ValueError(f"Unexpected key name: '{key}'")

        return v

    def _update_all_metrics(self) -> dict:
        if self._modified or len(self._results)==0:
            self._results = {
                k: self._update_metric(k).item() for k in self._metric_names
            }
            self._modified = False
        return self._results

    def get_metric(self, name: str) -> float:
        self._update_all_metrics()
        return self._results[name]

    def get_metrics(self, names: List[str]) -> Dict[str, float]:
        self._update_all_metrics()
        metrics_dict = {}
        for name in names:
            name_lower = name.lower()
            if name_lower in self._avl_metrics:
                metrics_dict[name] = self.get_metric(name_lower)
        return metrics_dict

    def metric_names(self) -> List[str]:
        return list(self._metric_names)

    def get_all_metrics(self) -> Dict[str, float]:
        return self._update_all_metrics()

    def __repr__(self) -> str:
        entries = [
            f"{k.upper()} {v:6.4f}" for k, v in self._update_all_metrics().items()
        ]
        string = "  ".join(entries)
        return string

    def to_dict(self) -> dict:
        self._update_all_metrics()
        metrics_dict = {}
        for k, v in self._data.items():
            if isinstance(v, torch.Tensor):
                v = v.item() if v.dim() == 0 else v.tolist()

            if isinstance(v, (list, tuple, np.ndarray)):
                for i, vi in enumerate(v):
                    if isinstance(vi, torch.Tensor):
                        vi = vi.item()
                    metrics_dict[f"{k}.{i}"] = vi
            else:
                metrics_dict[k] = v
        return metrics_dict


def tipo_pizza(tipo_pizza_var):

    if tipo_pizza_var == 1:
        pizza = "Vegetariana"
        print("Esta pizza puede contener: \n1- Pimiento \n2- Tofu")
        cual_pizza = int(input("El ingrediente que desea: "))

        ingrediente = el_ingrediente(cual_pizza)

    elif tipo_pizza_var == 2:
        pizza = "No vegetariana"
        print("Esta pizza puede contener: \n3- Peperoni \n4- Jamon \n5- Salmon")
        cual_pizza = int(input("El ingrediente que desea: "))

        ingrediente = el_ingrediente(cual_pizza)

    output(pizza, ingrediente)

def el_ingrediente(cual_pizza):

    if cual_pizza == 1:
        ingrediente = "Pimiento"
    elif cual_pizza == 2:
        ingrediente = "Tofu"
    elif cual_pizza == 3:
        ingrediente = "Peperoni"
    elif cual_pizza == 4:
        ingrediente = "Jamon"
    elif cual_pizza == 5:
        ingrediente = "Salmon"

    return ingrediente

def output(pizza, ingrediente):
    print("\nTipo de pizza: ", pizza)
    print("Ingrediente agregado: ", ingrediente)

print("Hoy tenemos pizzas")
print("1. Pizza vegetariana")
print("2. Pizza no vegetariana")
tipo_pizza_var = int(input("Digite el tipo de pizza que desea adquirir: "))

tipo_pizza(tipo_pizza_var)


import numpy as np

def compute_mandlebrot_iters(num: complex,
                             attempts: int) -> int:
    """
    Computes how long a number takes to diverge in when
    passed into the function which generates the Mandlebrot
    Set. If the magnitude of the complex number exceeds 2
    then the function will diverge.

    Args:
        num (complex): Point in the complex plain to
                        analyze in the Mandlebrot Set

    Returns:
        int: Number of iterations until divergence
    """
    f0 = complex(0, 0)
    for att in range(attempts):
        f0 = f0*f0 + num
        if f0.real + f0.imag > 2:
            # return number of attempts at
            # point of divergence
            return att
    # point does not diverge
    return att

if __name__ == "__main__":

    import matplotlib.pyplot as plt
    import matplotlib.cm as colors
    plt.style.use('dark_background')

    STEP = 0.0001
    TRIES = 101

    x = np.arange(-3, 1, STEP)
    y = np.arange(-2, 2, STEP)

    mandle = np.zeros(shape=(len(x), len(y)), dtype=np.int8)

    for i, x_val in enumerate(x):
        for j, y_val in enumerate(y):
            num = complex(x_val, y_val)
            result = compute_mandlebrot_iters(num, TRIES)
            mandle[j, i] = result

    fig, ax = plt.subplots(figsize=(25, 14))
    cmap = colors.get_cmap('Greys_r')
    ax.tick_params(axis='both', colors='black')
    ax.imshow(mandle, cmap=cmap)
    plt.show()


"""This code follows the tutorial on # https://keras.io/examples/vision/image_classification_with_vision_transformer."""
from __future__ import absolute_import, print_function

import argparse
import os
from typing import List, Tuple

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow_addons as tfa
from tensorflow import keras
from tensorflow.keras import Sequential, layers
from tensorflow.keras.callbacks import History

def main(args: argparse.Namespace):
    """Run VIT Image Classification.

    Args:
        args (argparse.Namespace): input arguments.
    """
    (x_train, y_train), (x_test, y_test) = keras.datasets.cifar100.load_data()

    print(f"x_train shape: {x_train.shape}  - y_train shape: {y_train.shape}")
    print(f"x_test shape: {x_test.shape}  - y_test shape: {y_test.shape}")

    # Hyperparameters
    num_classes = 100
    input_shape = (32, 32, 3)
    learning_rate = 0.001
    weight_decay = 0.0001
    batch_size = 256
    num_epochs = 100
    image_size = 72
    patch_size = 6
    num_patches = (image_size // patch_size) ** 2
    projection_dim = 64
    num_heads = 4
    transformer_units = [projection_dim * 2, projection_dim]
    transformer_layers = 8
    mlp_head_units = [2048, 1024]

    # Data Augmentation
    data_augmentation = Sequential(
        [
            layers.Normalization(),
            layers.Resizing(image_size, image_size),
            layers.RandomFlip("horizontal"),
            layers.RandomRotation(factor=0.02),
            layers.RandomZoom(height_factor=0.2, width_factor=0.2),
        ],
        name="data_augmentation",
    )

    data_augmentation.layers[0].adapt(x_train)

    plot_patches(x_train, image_size, patch_size, args.image_dir)

    vit_classifier = create_vit_classifier(
        input_shape,
        patch_size,
        num_patches,
        projection_dim,
        transformer_layers,
        num_heads,
        transformer_units,
        mlp_head_units,
        num_classes,
        data_augmentation,
    )

    model_plot = os.path.join(args.image_dir, "./vit_classifier.png")

    keras.utils.plot_model(
        vit_classifier,
        to_file=model_plot,
        show_shapes=False,
        show_dtype=False,
        show_layer_names=True,
        rankdir="TB",
        expand_nested=False,
        dpi=96,
        layer_range=None,
        show_layer_activations=False,
    )

    _ = run_experiment(
        vit_classifier,
        learning_rate,
        weight_decay,
        x_train,
        y_train,
        batch_size,
        num_epochs,
        x_test,
        y_test,
        args.model_dir,
    )

def create_vit_classifier(
    input_shape: Tuple,
    patch_size: int,
    num_patches: int,
    projection_dim: int,
    transformer_layers: int,
    num_heads: int,
    transformer_units: List,
    mlp_head_units: List,
    num_classes: int,
    data_augmentation: keras.Model,
) -> keras.Model:
    """Create VIT Classifier.

    Args:
        input_shape (Tuple): inpute image shape.
        patch_size (int): patch size.
        num_patches (int): number of patches.
        projection_dim (int): projection dimension.
        transformer_layers (int): transformer layers.
        num_heads (int): number of attention heads.
        transformer_units (List): transformer units.
        mlp_head_units (List): MLP head units.
        num_classes (int): number of classes.
        data_augmentation (keras.Model): data augmentation.

    Returns:
        keras.Model: VIT model.
    """
    inputs = layers.Input(shape=input_shape)
    augmented = data_augmentation(inputs)
    patches = Patches(patch_size)(augmented)
    encoded_patches = PatchEncoder(num_patches, projection_dim)(patches)

    for _ in range(transformer_layers):
        x1 = layers.LayerNormalization(epsilon=1e-6)(encoded_patches)
        attention_output = layers.MultiHeadAttention(
            num_heads=num_heads, key_dim=projection_dim, dropout=0.1
        )(x1, x1)
        x2 = layers.Add()([attention_output, encoded_patches])
        x3 = layers.LayerNormalization(epsilon=1e-6)(x2)
        x3 = mlp(x3, hidden_units=transformer_units, dropout_rate=0.1)
        encoded_patches = layers.Add()([x3, x2])

    representation = layers.LayerNormalization(epsilon=1e-6)(encoded_patches)
    representation = layers.Flatten()(representation)
    representation = layers.Dropout(0.5)(representation)

    features = mlp(representation, hidden_units=mlp_head_units, dropout_rate=0.5)

    logits = layers.Dense(num_classes)(features)
    model = keras.Model(inputs=inputs, outputs=logits)
    return model

def run_experiment(
    model: keras.Model,
    learning_rate: float,
    weight_decay: float,
    x_train: np.array,
    y_train: np.array,
    batch_size: int,
    num_epochs: int,
    x_test: np.array,
    y_test: np.array,
    output_dir: str,
) -> History:
    """Run Training and Validation.

    Args:
        model (keras.Model): classifier model.
        learning_rate (float): learning rate.
        weight_decay (float): weight decay.
        x_train (np.array): training input.
        y_train (np.array): training output.
        batch_size (int): batch size.
        num_epochs (int): number of epochs.
        x_test (np.array): test input.
        y_test (np.array): test output.
        output_dir (str): directory to write model.

    Returns:
        History: training history.
    """
    optimizer = tfa.optimizers.AdamW(
        learning_rate=learning_rate, weight_decay=weight_decay
    )

    model.compile(
        optimizer=optimizer,
        loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
        metrics=[
            keras.metrics.SparseCategoricalAccuracy(name="accuracy"),
            keras.metrics.SparseTopKCategoricalAccuracy(5, name="top-5-accuracy"),
        ],
    )

    os.makedirs(output_dir, exist_ok=True)

    checkpoint_filepath = os.path.join(output_dir, "checkpoint")
    _ = keras.callbacks.ModelCheckpoint(
        checkpoint_filepath,
        monitor="val_accuracy",
        save_best_only=True,
        save_weights_only=True,
    )

    history = model.fit(
        x=x_train,
        y=y_train,
        batch_size=batch_size,
        epochs=num_epochs,
        validation_split=0.1,
        callbacks=[],
    )

    # model.load_weights(checkpoint_filepath)
    _, accuracy, top_5_accuracy = model.evaluate(x_test, y_test)
    print(f"Test accuracy: {round(accuracy * 100, 2)}%")
    print(f"Test top 5 accuracy: {round(top_5_accuracy * 100, 2)}%")

    return history

def plot_patches(x_train: np.array, image_size: int, patch_size: int, output_dir: str):
    """Plot Image Patches.

    Args:
        x_train (np.array): Training set as numpy array.
        image_size (int): image size.
        patch_size (int): patch size.
        output_dir (str): directory to write images.
    """
    fig = plt.figure(figsize=(4, 4))
    image = x_train[np.random.choice(range(x_train.shape[0]))]
    plt.imshow(image.astype("uint8"))
    plt.axis("off")

    os.makedirs(output_dir, exist_ok=True)
    fig.savefig(os.path.join(output_dir, "./vit_classification_image.jpeg"))

    resized_image = tf.image.resize(
        tf.convert_to_tensor([image]), size=(image_size, image_size)
    )
    patches = Patches(patch_size)(resized_image)
    print(f"Image size: {image_size} X {image_size}")
    print(f"Patch size: {patch_size} X {patch_size}")
    print(f"Patches per image: {patches.shape[1]}")
    print(f"Elements per patch: {patches.shape[-1]}")

    n = int(np.sqrt(patches.shape[1]))
    fig = plt.figure(figsize=(4, 4))
    for i, patch in enumerate(patches[0]):
        _ = plt.subplot(n, n, i + 1)
        patch_img = tf.reshape(patch, (patch_size, patch_size, 3))
        plt.imshow(patch_img.numpy().astype("uint8"))
        plt.axis("off")

    fig.savefig(os.path.join(output_dir, "./vit_classification_patches.jpeg"))

def mlp(x: layers, hidden_units: int, dropout_rate: float) -> layers:
    """Multi Layer Perceptron.

    Args:
        x (layers): input layer.
        hidden_units (int): number of hidden units.
        dropout_rate (float): dropout rate.

    Returns:
        layers: output layer.
    """
    for units in hidden_units:
        x = layers.Dense(units, activation=tf.nn.gelu)(x)
        x = layers.Dropout(dropout_rate)(x)
    return x

class Patches(layers.Layer):
    """Image Patches."""

    def __init__(self, patch_size: int):
        """Initialize Class.

        Args:
            patch_size (int): patch size.
        """
        super(Patches, self).__init__()
        self.patch_size = patch_size

    def call(self, images: np.array) -> tf.Tensor:
        """Extrach Patches.

        Args:
            images (np.array): input images.

        Returns:
            tf.Tensor: image patches.
        """
        batch_size = tf.shape(images)[0]
        patches = tf.image.extract_patches(
            images=images,
            sizes=[1, self.patch_size, self.patch_size, 1],
            strides=[1, self.patch_size, self.patch_size, 1],
            rates=[1, 1, 1, 1],
            padding="VALID",
        )
        patch_dims = patches.shape[-1]
        # Flatten patches
        patches = tf.reshape(patches, [batch_size, -1, patch_dims])
        return patches

class PatchEncoder(layers.Layer):
    """Encode Patches."""

    def __init__(self, num_patches: int, projection_dim: int):
        """Initialize Class.

        Args:
            num_patches (int): number of patches.
            projection_dim (int): projection dimension.
        """
        super(PatchEncoder, self).__init__()
        self.num_patches = num_patches
        # Trainable Linear Projection, (Eq.1)
        self.projection = layers.Dense(units=projection_dim)

        # Position Embeddings
        self.position_embedding = layers.Embedding(
            input_dim=num_patches, output_dim=projection_dim
        )

    def call(self, patch: tf.Tensor) -> layers:
        """Encode Patches.

        Args:
            patch (tf.Tensor): input image tensor.

        Returns:
            layers: encoded tensor.
        """
        positions = tf.range(start=0, limit=self.num_patches, delta=1)
        encoded = self.projection(patch) + self.position_embedding(positions)
        return encoded

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--image_dir", default="./images")
    parser.add_argument("--model_dir", default="./models")
    main(parser.parse_args())


# 실패 코드
# import sys

# input = sys.stdin.readline

# N = int(input())

# result = 0

# def Find(depth, bit, b_num):
#     global result
#     if depth == N:
#         for i in range(10):
#             if not bit & (1 << i):
#                 return
#         result += 1
#         return
#     cnt = 0
#     for i in range(10):
#         if not bit & (1 << i):
#             cnt += 1
#     if N-depth < cnt:
#         return
#     if b_num == 0:
#         Find(depth+1, bit | 1, 1)
#     elif b_num == 9:
#         Find(depth+1, bit | (1 << 8), 8)
#     else:
#         Find(depth+1, bit | (1 << b_num-1), b_num-1)
#         Find(depth+1, bit | (1 << b_num+1), b_num+1)

# for i in range(1, 10):
#     Find(1, 1 << i, i)

# print(result % 1000000000)

# https://rccode.tistory.com/entry/Python-%EB%B0%B1%EC%A4%80-1562%EB%B2%88-%EA%B3%84%EB%8B%A8-%EC%88%98
import sys

input = sys.stdin.readline

Max = (1 << 10) - 1

N = int(input())

def Find():
    dp = [[0]*(Max+1) for _ in range(10)]

    for i in range(1, 10):
        dp[i][1 << i] = 1

    for _ in range(2, N+1):
        next_dp = [[0]*(Max+1) for _ in range(10)]

        for i in range(10):
            for j in range(Max+1):
                if i > 0:
                    next_dp[i][j | (1 << i)] = (
                        next_dp[i][j | (1 << i)] + dp[i-1][j]) % 1000000000
                if i < 9:
                    next_dp[i][j | (1 << i)] = (
                        next_dp[i][j | (1 << i)] + dp[i+1][j]) % 1000000000
        dp = next_dp

    return sum(dp[i][Max] for i in range(10)) % 1000000000

print(Find())


# -------------------------------------------------------------------------------------------------------------
## Import Statements
# -------------------------------------------------------------------------------------------------------------
from __future__ import print_function

import os
import shutil
import subprocess as sp
import sys

from .utils import conda_root, get_ggd_channels

# -------------------------------------------------------------------------------------------------------------
## Argument Parser
# -------------------------------------------------------------------------------------------------------------
def add_uninstall(p):
    c = p.add_parser(
        "uninstall",
        help="Uninstall a ggd data package",
        description="Use ggd to uninstall a ggd data package installed in the current conda environment",
    )
    c.add_argument(
        "-c",
        "--channel",
        default="genomics",
        choices=get_ggd_channels(),
        help="The ggd channel of the recipe to uninstall. (Default = genomics)",
    )
    c.add_argument(
        "names", nargs="+", help="the name(s) of the ggd package(s) to uninstall"
    )

    c.set_defaults(func=uninstall)

# -------------------------------------------------------------------------------------------------------------
## Functions/Methods
# -------------------------------------------------------------------------------------------------------------

def get_channeldata(ggd_recipes, ggd_channel):
    """Method to get the conda channel data for the specific ggd/conda channel for the designated ggd recipe

    get_channeldata
    ===============
    Method to get the channel data and check if the recipe is within that channel.
     This method is to identify the files installed during installation, but that
     won't be removed by normal uninstalling. These files will be removed by the
     check_for_installation() method if it is found within the channeldata.json file

    """

    from .list_files import in_ggd_channel

    ## Check if recipe is in the ggd channel
    package_list = []
    try:
        package_list, jdict = in_ggd_channel(
            ggd_recipes,
            ggd_channel,
            conda_root(),
            reporting=False,
            return_pkg_list=True,
        )
    except SystemExit:
        pass

    uninstall_recipes = True
    for recipe in ggd_recipes:
        if recipe not in package_list:
            uninstall_recipes = False
            if ggd_channel in get_ggd_channels():
                print(
                    "\n:ggd:uninstall: %s is not in the ggd-%s channel"
                    % (recipe, ggd_channel)
                )
            else:
                print(
                    "\n:ggd:uninstall: The '{}' channel is not a ggd conda channel".format(
                        ggd_channel
                    )
                )

            similar_pkgs = get_similar_pkg_installed_by_conda(recipe)
            if len(similar_pkgs) > 0:
                print(
                    "\n:ggd:uninstall: Packages installed on your system that are similar include:\n\t\t Package\tChannel\n\t\t-%s"
                    % "\n\t\t-".join([x for x in similar_pkgs.split("\n")])
                )
                print(
                    "\n:ggd:uninstall: If one of these packages is the desired package to uninstall please re-run ggd uninstall with the desired package name and correct ggd channel name"
                )
                print(
                    "\n:ggd:uninstall: Note: If the the package is not a part of a ggd channel run 'conda uninstall <pkg>' to uninstall"
                )
                print(
                    "\n:ggd:uninstall:\t GGD channels include: %s"
                    % ",".join(get_ggd_channels())
                )
            else:
                print(
                    "\n:ggd:uninstall: Unable to find any package similar to the package entered. Use 'ggd search' or 'conda find' to identify the right package"
                )
                print(
                    "\n:ggd:uninstall: This package may not be installed on your system"
                )

    if uninstall_recipes:
        return jdict
    else:
        return False

def get_similar_pkg_installed_by_conda(ggd_recipe):
    """Method to get a list of similarly installed package names, referring to package installed by conda

    get_similar_pkg_installed_by_conda
    ==================================
    Method to identify if there are similar packages to the one provided installed by conda that could be
     uninstalled. Provides a list of potential pkg names

    Parameters:
    ----------
    1) ggd_recipe: (str) The ggd_recipe name. (May not be an actually ggd_recipe)

    Returns:
    +++++++
    A string of pkgs and channels, with each pkg-channel separated from another by a new line
    """

    conda_package_list = sp.check_output(["conda", "list"]).decode("utf8").split("\n")
    ## Index 0 = name, index -1 = channel name
    return "\n".join(
        [
            pkg.split(" ")[0] + "\t" + pkg.split(" ")[-1]
            for pkg in conda_package_list
            if ggd_recipe in pkg
        ]
    )

def check_conda_installation(ggd_recipes, installed_ggd_packages):
    """Method to check if the ggd package was installed with conda

    check_conda_installation
    ========================
    Method used to check if the recipe has been installed with conda. If so, it uses conda to uninstall the recipe
    """

    ## Filter ggd recipe list to those installed by conda
    conda_installed_recipes = [x for x in ggd_recipes if x in installed_ggd_packages]

    ## Uninstall any conda installed recipes
    if len(conda_installed_recipes) > 0:
        print(
            "\n:ggd:uninstall: %s are installed by conda on your system"
            % ", ".join(conda_installed_recipes)
        )
        return conda_uninstall(conda_installed_recipes)
    else:
        print(
            "\n:ggd:uninstall: %s is NOT installed on your system"
            % ", ".join(ggd_recipes)
        )

def conda_uninstall(ggd_recipes):
    """Method use to uninstall the ggd recipe using conda

    conda_uninstall
    ===============
    Method used to uninstall ggd recipe using conda
    """

    print("\n:ggd:uninstall: Uninstalling %s" % ", ".join(ggd_recipes))
    try:
        return sp.check_call(
            ["conda", "remove", "-y"] + ggd_recipes,
            stderr=sys.stderr,
            stdout=sys.stdout,
        )
    except sp.CalledProcessError as e:
        sys.stderr.write("ERROR in uninstall %s" % ", ".join(ggd_recipes))
        sys.stderr.write(str(e))
        sys.exit(e.returncode)

def check_for_installation(ggd_recipes, ggd_jdict, prefix=conda_root()):
    """Method to check for and processes ggd package if it is installed

    check_for_installation
    =================
    Method used to remove extra files created during recipe installation, but that are not
     removed during normal uninstallation.
    This method depends on the get_channeldata method. If the recipe is not found in the
     channeldata.json file the extra files will not be removed.

    Parameters:
    -----------
    1) ggd_recipes: (list) A list of ggd recipe names to check for installation. (Recipes being uninstalled)
    2) ggd_jdict:   (dict) The json dictionary describing the ggd recipe
    3) prefix:      (str)  The conda prefix/environment to uninstall from (Default = conda_root())

    Returns:
    +++++++
    1) True for False: Whether or not to update the ggd package list
    """

    import glob

    from .show_env import remove_env_variable
    from .utils import conda_root, get_conda_prefix_path

    recipes_removed_from_conda = False
    for ggd_recipe in ggd_recipes:
        species = ggd_jdict["packages"][ggd_recipe]["identifiers"]["species"]
        build = ggd_jdict["packages"][ggd_recipe]["identifiers"]["genome-build"]
        version = ggd_jdict["packages"][ggd_recipe]["version"]

        prefix = get_conda_prefix_path(prefix) if prefix != conda_root() else prefix
        path = os.path.join(prefix, "share", "ggd", species, build, ggd_recipe, version)
        recipe_exists = glob.glob(path)
        if recipe_exists:
            print(
                "\n:ggd:uninstall: Removing %s version %s file(s) from ggd recipe storage"
                % (ggd_recipe, str(version))
            )
            shutil.rmtree(path)
            remove_from_condaroot(ggd_recipe, version, prefix)
            dir_env_var = "ggd_" + ggd_recipe + "_dir"
            remove_env_variable(dir_env_var, prefix)
            file_env_var = "ggd_" + ggd_recipe + "_file"
            remove_env_variable(file_env_var, prefix)
            recipes_removed_from_conda = True
        else:
            print("\n:ggd:uninstall: %s is not in the ggd recipe storage" % ggd_recipe)
    return recipes_removed_from_conda

def remove_from_condaroot(ggd_recipe, version, prefix):
    """Method to use conda to remove an installed ggd package from the conda root. This is a method for ggd package file handling

    remove_from_condaroot
    ====================
    Method used to remove the recipe's extra files created during installation, but that are not removed
     when conda uninstalled.
    """
    from .utils import update_installed_pkg_metadata

    ## Get a list of files for the package starting at the prefix path
    find_list = (
        sp.check_output(
            ["find", prefix, "-name", ggd_recipe + "-" + str(version) + "*"]
        )
        .decode("utf8")
        .strip()
        .split("\n")
    )
    ## Filter the list by conda env
    filtered_list = []
    for path in find_list:
        if prefix in path:
            if (
                str(prefix) + "/envs/" not in path
            ):  ## If the conda env root is in the path, and conda env root/env/ is not in the path, then add it to the filtered list
                filtered_list.append(path)
    print(
        "\n:ggd:uninstall: Deleting %d items of %s version %s from your conda root"
        % (len(filtered_list), ggd_recipe, version)
    )
    ## Remove files
    for path in filtered_list:
        if str(prefix) + "/env/" not in path:
            if os.path.isdir(path):
                shutil.rmtree(path)
            else:
                os.remove(path)

    ## Update installed package list
    print("\n:ggd:uninstall: Updating installed package list")
    update_installed_pkg_metadata(prefix=prefix, exclude_pkg=ggd_recipe)

def uninstall(parser, args):
    """Main method for uninstall command

    uninstall
    =========
    Main method used to check if the recipe is installed, uninstall the recipe, and remove extra recipe files
    """
    from .utils import get_conda_package_list, get_run_deps_from_tar

    ## List of packages to uninstall
    ggd_recipes = args.names

    ## Get the channeldata.json file in dictionary form
    print("\n:ggd:uninstall: Checking for installation of: %s" % ", ".join(ggd_recipes))
    ggd_jsonDict = get_channeldata(ggd_recipes, args.channel)
    if ggd_jsonDict == False:
        sys.exit()

    ## Get the installed ggd data package names
    installed_ggd_packages = get_conda_package_list(conda_root(), include_local=True)

    ## Check for GGD package as run deps
    ### Add them to the uninstall list
    ggd_info_dir = os.path.join(conda_root(), "share", "ggd_info", "noarch")
    tars_in_info_dir = set(os.listdir(ggd_info_dir))
    for recipe in args.names:
        tarballfile = (
            "{}-{}-{}.tar.bz2".format(
                recipe,
                installed_ggd_packages[recipe]["version"],
                installed_ggd_packages[recipe]["build"],
            )
            if recipe in installed_ggd_packages
            else ""
        )
        if tarballfile in tars_in_info_dir:
            tarfile_path = os.path.join(ggd_info_dir, tarballfile)
            ggd_recipes.extend(get_run_deps_from_tar(tarfile_path, args.channel))

    ## Check if installed through conda
    check_conda_installation(ggd_recipes, installed_ggd_packages.keys())

    ## Check if the recipe is in file system
    if len(ggd_jsonDict) > 0:
        check_for_installation(ggd_recipes, ggd_jsonDict)

    else:
        print("\n:ggd:uninstall: Skipping steps for package removal from system")

    print("\n:ggd:uninstall: DONE")

    return True


from django.db import models
from django.utils import timezone
from django.template.defaultfilters import slugify
from modules.models import Module, Component, ModuleBomListItem
from django.contrib.auth.models import User
import ast

def StringToJSON(input_to_test):
    try:
        return ast.literal_eval(input_to_test)
    except:
        return ast.literal_eval("{}")

class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True, on_delete=models.CASCADE)
    built_modules = models.ManyToManyField(Module, blank=True, related_name='built')
    want_to_build_modules = models.ManyToManyField(Module, blank=True, related_name='want_to_build')
    component_inventory = models.ManyToManyField(Component, blank=True, related_name='user_component_inventory',
                                                 through='UserProfileComponentInventoryData')
    shopping_list = models.ManyToManyField(Component, blank=True, related_name='user_shopping_list',
                                                 through='UserProfileShoppingListData')
    component_inventory_json = models.JSONField(null=True, blank=True)
    shopping_list_json = models.JSONField(null=True, blank=True)
    slug = models.SlugField(blank=True)

    def save(self, *args, **kwargs):
        if type(self.component_inventory_json) is str:
            self.component_inventory_json = StringToJSON(self.component_inventory_json)
        if type(self.shopping_list_json) is str:
            self.shopping_list_json = StringToJSON(self.shopping_list_json)
        if not self.slug:
            self.slug = slugify(f"{self.user}")
            super(UserProfile, self).save(*args, **kwargs)
        else:
            super(UserProfile, self).save(*args, **kwargs)

    def __str__(self):
        return f"{self.user}"

    class Meta:
        verbose_name_plural = "User Extended Properties"

class UserProfileComponentInventoryData(models.Model):
    component = models.ForeignKey(Component, null=True, on_delete=models.SET_NULL)
    profile = models.ForeignKey(UserProfile, null=True, on_delete=models.SET_NULL)
    quantity = models.PositiveIntegerField(default=0, blank=False)
    location = models.JSONField(null=True, blank=True)

    class Meta:
        # unique_together = ('component', 'profile', 'location')
        verbose_name_plural = "User Component Inventory"

    def __str__(self):
        return f'[ {self.profile} ] - [ {self.location} ] - {self.component}'

# Allows users to add modules to a named list
# All modules are also in a default "all" list which is just
class UserShoppingLists(models.Model):
    name = models.CharField(max_length=255, blank=False)
    user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "User-Defined, Named Shopping Lists"

    def __str__(self):
        return f'[ {self.user} ] - {self.name}'

class UserProfileShoppingListData(models.Model):
    module = models.ForeignKey(Module, on_delete=models.CASCADE)
    bom_item = models.ForeignKey(ModuleBomListItem, on_delete=models.CASCADE)
    component = models.ForeignKey(Component, on_delete=models.CASCADE)
    profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
    number = models.PositiveIntegerField(default=0, blank=False)
    tags = models.JSONField(blank=True, null=True)

    class Meta:
        verbose_name_plural = "User Shopping List"

    def __str__(self):
        return f'[ {self.profile} ] - {self.component}'


# -*- coding: utf-8 -*-
"""
Created on Sun Feb  9 00:18:31 2020

@author: smondal
"""

import pandas as pd
from sklearn.model_selection import train_test_split
import tensorflow as tf
import numpy as np
from nltk.corpus import stopwords #provides list of english stopwords
stop = stopwords.words('english')

#PRINT VERSION!!!
tf.__version__

#Load a file content
def LoadFile(filename):
    train = pd.read_csv(filename)
    return train
#some refined task on train data
def RefineTrain(train):
    train = train[['Summary','Text']]
    train['text_length'] = train['Text'].str.count(' ')
    train['text_length'].describe()
    train['summary_length'] = train['Summary'].str.count(' ')
    train['summary_length'].describe()
    train = train.loc[train['summary_length']<8]
    train = train.loc[train['text_length']<30]
    return train
#put everything to lowercase and then replace undesired characters
def ToLowercase(train, key1, key2, key3, key4, start, end):
    train[key2] = train[key1].str.lower()
    if start.strip():
        #print("it's not an empty or blank string")
        train[key4] =  start + ' ' +train[key3].str.replace('[^\w\s]','')+ ' ' + end
    else:
        train[key4] = train[key3].str.replace('[^\w\s]','')
        #print("it's an empty or blank string")
    return train

# generate tokens
def GetTokens(max_features, filters):
    if filters.strip():
        print("it's not an empty or blank filters")
        tok = tf.keras.preprocessing.text.Tokenizer(num_words=max_features, filters = '*') #tokenizer step
    else:
        tok = tf.keras.preprocessing.text.Tokenizer(num_words=max_features) #tokenizer step
    return tok

# fit tokens to cleaned text and create sequences
def FitTokens(tok, tf_train, key1, key2):
    tok.fit_on_texts(list(tf_train[key1].astype(str))) #fit to cleaned text
    tf_train=tok.texts_to_sequences(list(tf_train[key2].astype(str))) #this is how we create sequences
    return tf_train

#####################Driver Code################################################################
train = LoadFile('reviews.csv')
train.head()
train = RefineTrain(train)
print(train.shape)
print(train.head())
train = ToLowercase(train, 'Text', 'text_lower', 'text_lower', 'text_no_punctuation','','')
train = ToLowercase(train, 'Summary', 'summary_lower', 'summary_lower', 'summary_no_punctuation','_start_','_end_')
# NOTICE THAT WE ADD "_start_" and "_end_" EXACTLY AT THE BEGINNING AND THE END OF EACH SENTENCE TO HAVE SOME KIND OF'DELIMITERS'
#THAT WILL TELL OUR DECODER TO START AND FINISH. BECAUSE WE DON'T HAVE GENERAL SIGNALS OF START AND FINISH IN NATURAL LANGUAGE. BASICALLY '_end_' REFLECTS THE POINT IN WHICH OUR OUTPUT SENTENCE IS MORE LIKELY TO END.
#train['text_lower'] = train['Text'].str.lower()
#train['text_no_punctuation'] = train['text_lower'].str.replace('[^\w\s]','')
#train['english_no_stopwords'] = train['english_no_punctuation'].apply(lambda x: ' '.join([word for word in x.split() if word not in (stop)]))
#train["english_no_stopwords"] = train["english_no_stopwords"].fillna("fillna")
#train["english_no_stopwords"] = train["english_no_stopwords"]
#train['summary_lower'] = train["Summary"].str.lower()
#train['summary_no_punctuation'] =  '_start_' + ' ' +train['summary_lower'].str.replace('[^\w\s]','')+ ' ' +'_end_'

max_features1 = 5000
maxlen1 = 30

max_features2 = 5000
maxlen2 = 8

#tok1 = tf.keras.preprocessing.text.Tokenizer(num_words=max_features1)
tok1 = GetTokens(max_features1, '')
#tok1.fit_on_texts(list(train['text_no_punctuation'].astype(str))) #fit to cleaned text
#tf_train_text =tok1.texts_to_sequences(list(train['text_no_punctuation'].astype(str)))
tf_train_text = FitTokens(tok1, train, 'text_no_punctuation', 'text_no_punctuation')
tf_train_text =tf.keras.preprocessing.sequence.pad_sequences(tf_train_text, maxlen=maxlen1) #let's execute pad step
#the processing has to be done for both
#two different tokenizers
#tok2 = tf.keras.preprocessing.text.Tokenizer(num_words=max_features2, filters = '*')
tok2 = GetTokens(max_features2, '*')
#tok2.fit_on_texts(list(train['summary_no_punctuation'].astype(str))) #fit to cleaned text
#tf_train_summary = tok2.texts_to_sequences(list(train['summary_no_punctuation'].astype(str)))
tf_train_summary = FitTokens(tok2, train, 'summary_no_punctuation', 'summary_no_punctuation')
tf_train_summary = tf.keras.preprocessing.sequence.pad_sequences(tf_train_summary, maxlen=maxlen2, padding ='post')

vectorized_summary = tf_train_summary
# For Decoder Input, you don't need the last word as that is only for prediction
# when we are training using Teacher Forcing.
decoder_input_data = vectorized_summary[:, :-1]

# Decoder Target Data Is Ahead By 1 Time Step From Decoder Input Data (Teacher Forcing)
decoder_target_data = vectorized_summary[:, 1:]

print(f'Shape of decoder input: {decoder_input_data.shape}')
print(f'Shape of decoder target: {decoder_target_data.shape}')

vectorized_text = tf_train_text
# Encoder input is simply the body of the issue text
encoder_input_data = vectorized_text
doc_length = encoder_input_data.shape[1]
print(f'Shape of encoder input: {encoder_input_data.shape}')

vocab_size_encoder = len(tok1.word_index) + 1 #remember vocab size?
vocab_size_decoder = len(tok2.word_index) + 1

#arbitrarly set latent dimension for embedding and hidden units
latent_dim = 50

encoder_inputs = tf.keras.Input(shape=(doc_length,), name='Encoder-Input')

# Word embeding for encoder (English text)
x = tf.keras.layers.Embedding(vocab_size_encoder, latent_dim, name='Body-Word-Embedding', mask_zero=False)(encoder_inputs)

#Batch normalization is used so that the distribution of the inputs
#to a specific layer doesn't change over time
x = tf.keras.layers.BatchNormalization(name='Encoder-Batchnorm-1')(x)

# We do not need the `encoder_output` just the hidden state.
_, state_h = tf.keras.layers.GRU(latent_dim, return_state=True, name='Encoder-Last-GRU')(x)

# Encapsulate the encoder as a separate entity so we can just
#  encode without decoding if we want to.
encoder_model = tf.keras.Model(inputs=encoder_inputs, outputs=state_h, name='Encoder-Model')

seq2seq_encoder_out = encoder_model(encoder_inputs)

########################
#### Decoder Model ####
decoder_inputs = tf.keras.Input(shape=(None,), name='Decoder-Input')  # for teacher forcing

# Word Embedding For Decoder (Italian text)
dec_emb = tf.keras.layers.Embedding(vocab_size_decoder, latent_dim, name='Decoder-Word-Embedding', mask_zero=False)(decoder_inputs)
#again batch normalization
dec_bn = tf.keras.layers.BatchNormalization(name='Decoder-Batchnorm-1')(dec_emb)

# Set up the decoder, using `decoder_state_input` as initial state.
decoder_gru = tf.keras.layers.GRU(latent_dim, return_state=True, return_sequences=True, name='Decoder-GRU')
decoder_gru_output, _ = decoder_gru(dec_bn, initial_state=seq2seq_encoder_out) #the decoder "decodes" the encoder output.
x = tf.keras.layers.BatchNormalization(name='Decoder-Batchnorm-2')(decoder_gru_output)

# Dense layer for prediction
decoder_dense = tf.keras.layers.Dense(vocab_size_decoder, activation='softmax', name='Final-Output-Dense')
decoder_outputs = decoder_dense(x)

########################
#### Seq2Seq Model ####
seq2seq_Model = tf.keras.Model([encoder_inputs, decoder_inputs], decoder_outputs)

seq2seq_Model.compile(optimizer=tf.keras.optimizers.Nadam(lr=0.001), loss='sparse_categorical_crossentropy')

#from seq2seq_utils import viz_model_architecture
seq2seq_Model.summary()
#viz_model_architecture(seq2seq_Model)

#Train Model

batch_size = 64
epochs = 2

history = seq2seq_Model.fit([encoder_input_data, decoder_input_data], np.expand_dims(decoder_target_data, -1),
          batch_size=batch_size,  epochs=epochs ,  validation_split=0.12)
seq2seq_Model.save("seq2seq_subsample_1_epochs.h5")

#---------------------------------Code should run on saved model file ----------------------------------------------------------------------------------
seq2seq_Model = tf.keras.models.load_model('seq2seq_subsample_1_epochs.h5')

#test_text = ['apparently they used too much synthetic flavors that it just burns your tongue also theres too much oil  almost made me chok']
test_text = ['this stuff is awesome  for best flavor boil it in water drain the water add spice packet and then add hot water']
#test_text = ['This dataset consists of reviews of fine foods from amazon. The data span a period of more than 10 years, including all ~500,000 reviews up to October 2012. Reviews include product and user information, ratings, and a plain text review. It also includes reviews from all other Amazon categories.']
#seq2seq_Model = tf.keras.models.load_model('seq2seq_subsample_1_epochs.h5')
#seq2seq_Model = tf.keras.models.load_model('seq2seq_full_data_3_epochs.h5')
#max_len_title = 30
# get the encoder's features for the decoder
tok1.fit_on_texts(test_text)
raw_tokenized = tok1.texts_to_sequences(test_text)
raw_tokenized = tf.keras.preprocessing.sequence.pad_sequences(raw_tokenized, maxlen=maxlen1)
body_encoding = encoder_model.predict(raw_tokenized) #predict the encoder state of the new sentence
latent_dim = seq2seq_Model.get_layer('Decoder-Word-Embedding').output_shape[-1]

#remember the get layer methodo for getting the embedding (word clusters)
decoder_inputs = seq2seq_Model.get_layer('Decoder-Input').input
dec_emb = seq2seq_Model.get_layer('Decoder-Word-Embedding')(decoder_inputs)
dec_bn = seq2seq_Model.get_layer('Decoder-Batchnorm-1')(dec_emb)

gru_inference_state_input = tf.keras.Input(shape=(latent_dim,), name='hidden_state_input')
gru_out, gru_state_out = seq2seq_Model.get_layer('Decoder-GRU')([dec_bn, gru_inference_state_input])

# Reconstruct dense layers
dec_bn2 = seq2seq_Model.get_layer('Decoder-Batchnorm-2')(gru_out)
dense_out = seq2seq_Model.get_layer('Final-Output-Dense')(dec_bn2)

decoder_model = tf.keras.Model([decoder_inputs, gru_inference_state_input],
                          [dense_out, gru_state_out])

# we want to save the encoder's embedding before its updated by decoder
#   because we can use that as an embedding for other tasks.
original_body_encoding = body_encoding

state_value = np.array(tok2.word_index['_start_']).reshape(1, 1)

state_value

decoded_sentence = []
stop_condition = False

vocabulary_inv = dict((v, k) for k, v in tok2.word_index.items())
#vocabulary_inv[0] = "<PAD/>"
#vocabulary_inv[1] = "unknown"

vocabulary_inv

while not stop_condition:
    #print(1)
    preds, st = decoder_model.predict([state_value, body_encoding])

    pred_idx = np.argmax(preds[:, :, 2:]) + 2
    pred_word_str = vocabulary_inv[pred_idx]
    print(pred_word_str)
    if pred_word_str == '_end_' or len(decoded_sentence) >= maxlen2:
        stop_condition = True
        break
    decoded_sentence.append(pred_word_str)

    # update the decoder for the next word
    body_encoding = st
    state_value = np.array(pred_idx).reshape(1, 1)
    #print(state_value)

    train.tail()


#upgradeAlerts.py
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2013 NV Access Limited
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.

"""Dialogs displayed when NVDA starts containing important information about changes to NVDA.
"""

import os
import wx
import gui
import config

class NewLaptopKeyboardLayout(wx.Dialog):
	MESSAGE = _(
		# Translators: Information about NVDA's new laptop keyboard layout.
		"In NVDA 2013.1, the laptop keyboard layout has been completely redesigned in order to make it more intuitive and consistent.\n"
		"If you use the laptop layout, please see the What's New document for more information."
	)

	def __init__(self, parent):
		# Translators: The title of a dialog providing information about NVDA's new laptop keyboard layout.
		super(NewLaptopKeyboardLayout, self).__init__(parent, title=_("New Laptop Keyboard layout"))
		mainSizer = wx.BoxSizer(wx.VERTICAL)
		item = wx.StaticText(self, label=self.MESSAGE)
		mainSizer.Add(item, border=20, flag=wx.LEFT | wx.RIGHT | wx.TOP)
		# Translators: The label of a button in the New Laptop Keyboard Layout dialog
		# to open the What's New document.
		whatsNewButton = wx.Button(self, label=_("Read What's New"))
		whatsNewButton.Bind(wx.EVT_BUTTON, self.onWhatsNew)
		mainSizer.Add(whatsNewButton)

		mainSizer.Add(self.CreateButtonSizer(wx.OK),flag=wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL,border=20)
		self.Bind(wx.EVT_BUTTON, lambda evt: self.Close(), id=wx.ID_OK)

		self.Bind(wx.EVT_CLOSE, self.onClose)

		whatsNewButton.SetFocus()
		self.Sizer = mainSizer
		mainSizer.Fit(self)

	def onClose(self, evt):
		config.conf["upgrade"]["newLaptopKeyboardLayout"] = True
		try:
			config.save()
		except:
			pass
		self.EndModal(0)

	def onWhatsNew(self, evt):
		os.startfile(gui.getDocFilePath("changes.html"))
		self.Close()

	@classmethod
	def run(cls):
		"""Prepare and display an instance of this dialog.
		This does not require the dialog to be instantiated.
		"""
		gui.mainFrame.prePopup()
		d = cls(gui.mainFrame)
		d.ShowModal()
		d.Destroy()
		gui.mainFrame.postPopup()


#The approach is to calculate a prefix and postfix array
#Multiply the values of the prefix and postfix array and append to an output array
def productArray(nums):
    pre = 1
    post = 1
    answer = []
    prefix = [pre]
    postfix = [post]
    for i in range(1,len(nums)):
        pre = nums[i-1] * pre
        prefix.append(pre)
    for i in range(len(nums)-2,-1,-1):
        post = nums[i+1]* post
        postfix.insert(0,post)
    for i in range(len(prefix)):
        answer.append(prefix[i]* postfix[i])
    return answer
print(productArray([1,2,3,4]))    #24, 12, 8, 8


import tkinter
from tkinter import filedialog
from tkinter import messagebox
import bif
import time
from PIL import Image
from PIL import ImageTk

def original_algorithm_check():
    if mode.get()==4 or mode.get()==5:
        original_algorithm.set(0)
    if original_algorithm.get()==0:
        threshold_slider_label.set("Prebright:")
    else:
        threshold_slider_label.set("Threshold:")

def mode_button_check():
    if mode.get()==4 or mode.get()==5:
        original_algorithm.set(0)
        threshold_slider_label.set("Prebright:")
    else:
        if original_algorithm.get()==0:
            threshold_slider_label.set("Prebright:")
        else:
            threshold_slider_label.set("Threshold:")

def open_file():
    global image
    filename=filedialog.askopenfilename(title="Select a file for conversion...",filetypes=[("Image files","*.jpg *.jpeg *.png *.webp"),("BIF files","*.bif")])
    if filename!=None:
        filename_string.set(filename)
        filename_label_text.set(filename)
        filename_extension=".".join(filename_string.get().split(".")[-1:]).lower()
        if filename_extension=="bif":
            with open(filename_string.get()) as file:
                image=bif.decompress_bif(file.readline(),False)
            image_tk=ImageTk.PhotoImage(image["image"])
            image_label.configure(image=image_tk)
            image_label.image=image_tk
            preview_window.geometry(str(image["image"].size[0]) + "x" + str(image["image"].size[1]))
            converted.set(0)

            mode_string=""
            mode_string=bif.get_mode_description(image["mode"])
            compressed_string=""
            if image["compressed"]:
                compressed_string="Compression ratio: " + str(image["ratio"]) + "%"
            else:
                compressed_string="Uncompressed"

            status_label_text.set("BIF opened successfully! "+mode_string+", "+compressed_string)
            bif_opened.set(1)

def save_file():
    global image
    if bif_opened.get()==0:
        if converted.get()==1:
            if preview_compressed.get()!=compressed.get():
                image=bif.convert_to_bif(filename_string.get(),mode.get(),bool(original_algorithm.get()),threshold_actual.get(),bool(compressed.get()),prebright_actual.get(),float(scale.get()),False)
            filename=filedialog.asksaveasfile(title="Save the converted file...",filetypes=[("BIF files","*.bif")],defaultextension=".bif")
            if filename!=None:
                filename_actual=filename.name
                with open(filename_actual, "w") as file:
                    file.write(image["file"])
        else:
            messagebox.showerror("Error","Image not converted yet!")
    else:
        filename=filedialog.asksaveasfile(title="Save the converted file...",filetypes=[("PNG files","*.png")],defaultextension=".png")
        if filename!=None:
            image["image"].save(filename.name)

def preview():
    global image
    if filename_string.get()=="":
        messagebox.showerror("Error","File not specified!")
    else:
        filename_extension=".".join(filename_string.get().split(".")[-1:]).lower()
        if filename_extension!="bif":
            start_time=time.time()
            bif_opened.set(0)
            threshold_actual.set(0)
            prebright_actual.set(0)
            if original_algorithm.get()==0:
                prebright_actual.set(threshold.get())
            else:
                threshold_actual.set(threshold.get())
            image=bif.convert_to_bif(filename_string.get(),mode.get(),bool(original_algorithm.get()),threshold_actual.get(),bool(compressed.get()),prebright_actual.get(),float(scale.get()),False)
            image_tk=ImageTk.PhotoImage(image["image"])
            image_label.configure(image=image_tk)
            image_label.image=image_tk

            end_time=time.time()
            preview_window.geometry(str(image["image"].size[0]) + "x" + str(image["image"].size[1]))
            if image["file"].endswith("D:"):
                status_label_text.set("Conversion error!")
                messagebox.showerror("Error","For whatever reason, BIF was unable to convert this image. It likely has the incorrect file extension, or is in a format that isn't supported by the converter.")
                converted.set(0)
            else:
                status_label_text.set("Conversion completed in " + str(round(end_time-start_time,2)) + " seconds!")
                converted.set(1)
            preview_compressed.set(int(compressed.get()))
            preview_window.lift()

def about_show():
    def destroy():
        about.grab_release()
        about.destroy()
    about=tkinter.Toplevel(window)
    about.title("About!")
    about.geometry("360x560")
    about.configure(bg="black")
    about.resizable(width=False,height=False)

    logo2_image=tkinter.PhotoImage(file="gui/bifpy_small.gif")
    logo2_label=tkinter.Label(about,image=logo2_image,border=0)
    logo2_label.pack()

    tkinter.Label(about,text="BIF.py",fg="white",bg="black",font="Courier 20 bold").pack()
    tkinter.Label(about,text="A complete Python rewrite of the Best Image Format, complete with the BCA and original colour reduction algorithm, alongside some bonus new features!\n\nBest Image Format is an attempt at creating an image format, complete with lossless compression (via the Bloated Compression Algorithm) and various colour modes for extremely vibrant results! It's objectively better than PNG and JPG.\n\nBy Presley Peters, 2021-2022.",fg="white",bg="black",wraplength=360).pack(pady=10)
    tkinter.Button(about,text="okay cool thx",command=destroy).pack()
    about.wait_visibility()
    about.grab_set()
    about.mainloop()

image=None

window=tkinter.Tk(className="\Best Image Format")
window.resizable(width=False,height=False)
window.geometry("600x420")

tkinter.Button(text="?",command=about_show).pack(side="right",anchor="n",padx=(0,10),pady=10)

preview_window=tkinter.Toplevel(window)
preview_window.resizable(width=False,height=False)
preview_window.geometry("400x400+" + str(window.winfo_rootx()+600) + "+" + str(window.winfo_rooty()-20))
preview_window.title("Preview")
image_label=tkinter.Label(preview_window)
image_label.place(x=-2,y=-2)

logo_image=tkinter.PhotoImage(file="gui/logo.gif")
logo_label=tkinter.Label(window,image=logo_image)
logo_label.pack(pady=10)

mode_frame=tkinter.LabelFrame(text="Conversion properties")
mode_frame.pack(fill="x",expand=True,padx=20)

mode=tkinter.IntVar(value=1)
mode_buttons=[]
mode_buttons.append(tkinter.Radiobutton(mode_frame,text=bif.get_mode_description(1),variable=mode,value=1,command=mode_button_check))
mode_buttons.append(tkinter.Radiobutton(mode_frame,text=bif.get_mode_description(2),variable=mode,value=2,command=mode_button_check))
mode_buttons.append(tkinter.Radiobutton(mode_frame,text=bif.get_mode_description(3),variable=mode,value=3,command=mode_button_check))
mode_buttons.append(tkinter.Radiobutton(mode_frame,text=bif.get_mode_description(4),variable=mode,value=4,command=mode_button_check))
mode_buttons.append(tkinter.Radiobutton(mode_frame,text=bif.get_mode_description(5),variable=mode,value=5,command=mode_button_check))
for button in mode_buttons:
    button.pack(anchor="w")

original_algorithm=tkinter.IntVar(value=0)
original_algorithm_box=tkinter.Checkbutton(mode_frame,text="Original algorithm",variable=original_algorithm,command=original_algorithm_check)
original_algorithm_box.pack(side="right",anchor="e")

tkinter.Label(mode_frame,text="Scale:").pack(side="left",anchor="e",expand=True)
scale=tkinter.StringVar(value="1.00")
scale_slider_value=tkinter.Label(mode_frame,width=3,textvariable=scale).pack(side="left",anchor="w",expand=True)
scale_slider=tkinter.Scale(mode_frame,resolution=0.01,from_=0.25,to=1,variable=scale,orient="horizontal",showvalue=0)
scale_slider.pack(side="left")

threshold_slider_label=tkinter.StringVar(value="Prebright:")
tkinter.Label(mode_frame,textvariable=threshold_slider_label,width=8).pack(side="left",anchor="e",expand=True)
threshold=tkinter.IntVar(value=0)
threshold_slider_value=tkinter.Label(mode_frame,width=2,textvariable=threshold).pack(side="right",anchor="w",expand=True)
threshold_slider=tkinter.Scale(mode_frame,from_=-100,to=100,variable=threshold,orient="horizontal",showvalue=0)
threshold_slider.pack(side="right",anchor="w",expand=True)

compressed=tkinter.IntVar(value=0)
compressed_box=tkinter.Checkbutton(text="Enable BCA",variable=compressed)
compressed_box.pack()

status_label_text=tkinter.StringVar(value="Idle!")
status_label=tkinter.Label(textvariable=status_label_text).pack()
filename_string=tkinter.StringVar(value="")
filename_label_text=tkinter.StringVar(value="File not selected yet...")
filename_label=tkinter.Label(textvariable=filename_label_text).pack()
open_file_button=tkinter.Button(text="Open file",command=open_file)
open_file_button.pack(side="left",anchor="e",expand=True,padx=4,pady=(0,10))
save_file_button=tkinter.Button(text="Save file",command=save_file)
save_file_button.pack(side="right",anchor="w",expand=True,padx=4,pady=(0,10))
preview_button=tkinter.Button(text="Preview",command=preview)
preview_button.pack(pady=(0,10))

converted=tkinter.IntVar(value=0)
preview_compressed=tkinter.IntVar(value=0)
prebright_actual=tkinter.IntVar(value=0)
threshold_actual=tkinter.IntVar(value=0)
bif_opened=tkinter.IntVar(value=0)

window.focus_set()
window.mainloop()


import torch.nn as nn
from transformers import BertModel

class BERTNewsClf(nn.Module):
    def __init__(self):
        super(BERTNewsClf, self).__init__()

        self.bert = BertModel.from_pretrained('../models/bert-base-uncased')

        self.feature_ext = nn.Sequential(
            nn.Linear(768, 64),
            nn.ReLU()
        )

        self.clf_head = nn.Sequential(
            nn.Linear(64, 3),
            nn.Softmax(dim=1)
        )

    def forward(self, input_ids, attention_mask):
        last_hidden_state, pooler_output = self.bert(input_ids=input_ids, attention_mask=attention_mask, return_dict=False)
        feature_vect = self.feature_ext(pooler_output)
        y = self.clf_head(feature_vect)

        return y, feature_vect

if __name__ == '__main__':
    model = BERTNewsClf()
    model_in = "Replace me by any text you'd like."
    model_out = model(model_in)
    print(model_out)
    print(model_out.shape)


import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

from GraphicsGenerators.gcodeParser import GCodeSegment, ParseResult
from typing import List

def colorLayer(parseResult : ParseResult, name = ''):
    for layerGenerator in parseResult.layerGeneratorGenerator():
        layerSegs : List[GCodeSegment] = list(layerGenerator)
        print(f"{len(layerSegs)} z={layerSegs[0].startPos[2]}")

        zLayer = layerSegs[0].startPos[2]

        lines = list(map(lambda x: ((x.startPos[0], x.endPos[0]), (x.startPos[1], x.endPos[1])), layerSegs))
        colorsAndLabels = list(map(lambda x: ('b','print segment') if x.isPrint() else ('g', 'travel segment'), layerSegs))

        plt.figure()
        legendSet = set()
        for ((x,y),(c,l)) in zip(lines, colorsAndLabels):
            # print(f"{x} {y} {c}")
            if(l in legendSet):
                plt.plot(x,y,color=c, label='_')
            else:
                plt.plot(x,y,color=c, label=l)
                legendSet.add(l)
        ax = plt.gcf().gca()
        ax.legend(loc=0)
        ax.set_aspect('equal', adjustable='box')

        # Shrink current axis by 20%
        box = ax.get_position()
        ax.set_position([box.x0, box.y0, box.width * 0.8, box.height * 0.8])

        # Put a legend to the right of the current axis
        ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

        plt.title(f"{name}    z = {zLayer}")
        plt.xlabel("X (mm)")
        plt.ylabel("Y (mm)")
        plt.show()

def colorChains(parseResult : ParseResult, name = ''):
    for layerGenerator in parseResult.layerGeneratorGenerator():
        layerSegs : List[GCodeSegment] = list(layerGenerator)
        print(f"{len(layerSegs)} z={layerSegs[0].startPos[2]}")

        printSegs = [seg for seg in layerSegs if seg.isPrint()]

        zLayer = layerSegs[0].startPos[2]

        lines = list(map(lambda x: ((x.startPos[0], x.endPos[0]), (x.startPos[1], x.endPos[1])), printSegs))

        colors = []
        inChain = False
        thisColor = None
        def colorGenerator():
            while(True):
                for e in mcolors.TABLEAU_COLORS:
                    yield e

        colorGen = colorGenerator()

        for seg in layerSegs:
            if seg.isPrint() is False:
                inChain = False
            else:
                if inChain is False:
                    thisColor = next(colorGen)
                    inChain = True
                colors.append(thisColor)

        assert(len(colors) == len(lines))

        plt.figure()
        for ((x,y),c) in zip(lines, colors):
            # print(f"{x} {y} {c}")
            plt.plot(x,y,color=c)
        ax = plt.gcf().gca()

        plt.title(f"{name}    z = {zLayer}")

        ax.set_aspect('equal', adjustable='box')

        plt.show()


#write a program to remove every consonant from a string

def ConsonantEraser(string):
    vowels = ["a","e","i","o","u", " "]
    splitString = [*string]
    resultString = []
    for letter in splitString:
        if letter.lower() in vowels:
            resultString.append(letter)
        else:
            continue

    print(resultString)
    print(''.join(resultString))

ConsonantEraser("Why you are worry")


from tkinter import *
from tkinter import ttk
from tkinter import messagebox as mb
import tkinter.scrolledtext as tkst
import turtle
import base64
import os
from time import time

dir = "./playerdata"
try:
    os.listdir(dir)
except:
    os.mkdir(dir)

vot = "Laseme kõik laevad õhku"

def encode(string):
    return str(base64.b64encode(bytes(string, "utf-8")), "utf-8")
def decode(string):
    return str(base64.b64decode(bytes(string, "utf-8")), "utf-8")

def logi():
    global playerdata
    global kasu
    global sobib
    kasu = str(kasutaja.get())
    paro = str(parool.get())
    #print(kasu,paro)
    if "" in [kasu,paro]:
        mb.showerror("ERROR", "Kasutajanimi või parool on ebasobiv.")
    else:
        try:
            playerfile = open(dir + "/" + kasu + ".txt", "r", encoding="utf-8")
            a = decode(playerfile.readline())
            playerfile.close()
            if paro == a:
                sobib = True
                mb.showinfo("INFO", "Sisselogimine õnnestus.")
                login.destroy()
            else:
                mb.showerror("ERROR", "Sisestatud parool on vale.")
        except:
            mb.showerror("ERROR", "Kasutajat ei eksisteeri.")

def polekas():
    global kasutaja1
    global parool1
    global lookas
    lookas = Tk()
    lookas.title("Loo kasutaja")
    lookas.geometry('300x210')
    kas = Label(lookas, text="Kasutajanimi:")
    kas.place(x=75, y=10)
    kasutaja1 = Entry(lookas)
    kasutaja1.place(x=75, y=30, width=150)
    par = Label(lookas, text="Parool:")
    par.place(x=75, y=60)
    parool1 = Entry(lookas, show="*")
    parool1.place(x=75, y=80, width=150)
    nupp = ttk.Button(lookas, text="Loo kasutaja", command=lokas)
    nupp.place(x=75, y=110, width=150)

def lokas():
    kasu = str(kasutaja1.get())
    paro = str(parool1.get())
    #print(kasu, paro)
    if "" in [kasu, paro]:
        mb.showerror("ERROR", "Kasutajanimi või parool on ebasobiv.")
    else:
        if kasu + ".txt" in os.listdir(dir):
            mb.showerror("ERROR", "Kasutajanimi on juba kasutuses, palun vali mõni teine.")
        else:
            playerfile = open(dir + "/" + kasu + ".txt", "w", encoding="utf-8")
            print(encode(paro) + "\n")
            playerfile.write(encode(paro) + "\n")
            playerfile.close()
            mb.showinfo("INFO", "Registreerimine õnnestus.")
            lookas.destroy()

def reeg():
    r = Toplevel(tervitus)
    r.title("Reeglid")
    reeglid = tkst.ScrolledText(master=r, wrap=WORD, width=50, height=10)
    reeglid.pack(padx=10, pady=10, fill=BOTH, expand=True)
    # Adding some text, to see if scroll is working as we expect it
    sis = open("Reeglid.txt","r")
    reeglid.insert(INSERT, sis.read())
    sis.close()

def mang():
    global sobib
    sobib = True
    tervitus.destroy()

def rt(n):
    global sobib
    global raskustase
    sobib = True
    raskustase = n
    rask.destroy()

login = Tk()
login.title("Login")
login.geometry('300x210')

loginmsg = Label(login, text="Mängimiseks pead sisse logima.")
loginmsg.place(x=65, y=5)
kas = Label(login, text="Kasutajanimi:")
kas.place(x=75, y=40)
kasutaja = Entry(login)
kasutaja.place(x=75, y=60, width=150)
par = Label(login, text="Parool:")
par.place(x=75, y=90)
parool = Entry(login, show="*")
parool.place(x=75, y=110, width=150)
nupp1 = ttk.Button(login, text="Logi sisse", command=logi)
nupp1.place(x=75, y=140, width=150)
nupp2 = ttk.Button(login, text="Mul pole veel kasutajat", command=polekas)
nupp2.place(x=75, y=170, width=150)

sobib = False
login.mainloop()
if not sobib:
    sys.exit()

playerfile = open(dir + "/" + kasu + ".txt", "r", encoding="utf-8")
tervitus = Tk()
tervitus.title("Tere tulemast, " + kasu)
tervitus.geometry('300x110')
msg = Label(tervitus, text="Mida soovid teha?")
msg.place(x=100, y=5)
nupp1 = ttk.Button(tervitus, text="Lugeda reegleid", command=reeg)
nupp1.place(x=75, y=40, width=150)
nupp2 = ttk.Button(tervitus, text="Mängida", command=mang)
nupp2.place(x=75, y=70, width=150)
sobib = False
tervitus.mainloop()
if not sobib:
    sys.exit()

rask = Tk()
rask.title("Raskustase")
rask.geometry('300x230')
msg = Label(rask, text="Vali endale sobiv raskustase.")
msg.place(x=73, y=5)
nupp1 = ttk.Button(rask, text="Väga lihtne", command=lambda: rt(1))
nupp1.place(x=75, y=40, width=150)
nupp2 = ttk.Button(rask, text="Lihtne", command=lambda: rt(2))
nupp2.place(x=75, y=70, width=150)
nupp3 = ttk.Button(rask, text="Keskmine", command=lambda: rt(3))
nupp3.place(x=75, y=100, width=150)
nupp4 = ttk.Button(rask, text="Raske", command=lambda: rt(4))
nupp4.place(x=75, y=130, width=150)
nupp5 = ttk.Button(rask, text="Ekstreemne", command=lambda: rt(5))
nupp5.place(x=75, y=160, width=150)
nupp6 = ttk.Button(rask, text="Võimatu", command=lambda: rt(6))
nupp6.place(x=75, y=190, width=150)
sobib = False
rask.mainloop()
if not sobib:
    sys.exit()
print(raskustase)

def ules():
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[1] < 9:
        asukoht[1] += 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(-248 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def alla():
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[1] > 0:
        asukoht[1] -= 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(-248 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def vasakule():
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[0] > 0:
        asukoht[0] -= 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(-248 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def paremale():
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[0] < 9:
        asukoht[0] += 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(-248 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def paiguta():
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time() + 0.3
    x = asukoht[0]
    y = asukoht[1]
    if valiklaud[y][x] == 0:
        valiklaud[y][x] = 1
        j.goto(-225 + 50 * x, -225 + 50 * y)
        j.pencolor("#0000FF")
        j.pendown()
        j.dot(23)
        j.penup()
        for i in [[x+1,y+1],[x+1,y-1],[x-1,y+1],[x-1,y-1]]:
            if not (i[0] < 0 or i[1] < 0 or i[0] > 9 or i[1] > 9):
                if valiklaud[i[1]][i[0]] == 0:
                    rist([i[0],i[1]])
                    valiklaud[i[1]][i[0]] = "x"
        suund = 0
        if (x > 0 and valiklaud[y][x-1] == 1) or (x < 9 and valiklaud[y][x+1] == 1):
            suund = "h"
        elif (x == 0 and valiklaud[y][x+1] == 1) or (x == 9 and valiklaud[y][x-1] == 1):
            suund = "h"
        elif (y > 0 and valiklaud[y-1][x] == 1) or (y < 9 and valiklaud[y+1][x] == 1):
            suund = "v"
        elif (y == 0 and valiklaud[y+1][x] == 1) or (y == 9 and valiklaud[y-1][x] == 1):
            suund = "v"
        print(suund)
        if suund == "h":
            ots1 = x
            ots2 = x
            while ots1 > 0 and valiklaud[y][ots1 - 1] == 1:
                ots1 -= 1
            while ots2 < 9 and valiklaud[y][ots2 + 1] == 1:
                ots2 += 1
            print(ots1,ots2)
            a = 2
            juures1 = 0
            juures2 = 0
            while ots1 - a >= 0:
                try:
                    if valiklaud[y][ots1 - a] == 1:
                        a += 1
                        juures1 += 1
                    else:
                        break
                except IndexError:
                    break
            a = 2
            while ots2 + a <= 9:
                try:
                    if valiklaud[y][ots2 + a] == 1:
                        a += 1
                        juures2 += 1
                    else:
                        break
                except IndexError:
                    break

            l = ots2 - ots1 + 1
            print(l, juures1, juures2)
            if l + juures1 >= 5:
                if ots1 > 0:
                    if valiklaud[y][ots1 - 1] == 0:
                        rist([ots1 - 1, y])
                        valiklaud[y][ots1 - 1] = "x"
            if l + juures2 >= 5:
                if ots2 < 9:
                    if valiklaud[y][ots2 + 1] == 0:
                        rist([ots2 + 1, y])
                        valiklaud[y][ots2 + 1] = "x"
        elif suund == "v":
            ots1 = y
            ots2 = y
            while ots1 > 0 and valiklaud[ots1 - 1][x] == 1:
                ots1 -= 1
            while ots2 < 9 and valiklaud[ots2 + 1][x] == 1:
                ots2 += 1
            print(ots1, ots2)
            a = 2
            juures1 = 0
            juures2 = 0
            while ots1 - a >= 0:
                try:
                    if valiklaud[ots1 - a][x] == 1:
                        a += 1
                        juures1 += 1
                    else:
                        break
                except IndexError:
                    break
            a = 2
            while ots2 + a <= 9:
                try:
                    if valiklaud[ots2 + a][x] == 1:
                        a += 1
                        juures2 += 1
                    else:
                        break
                except IndexError:
                    break

            l = ots2 - ots1 + 1
            print(l, juures1, juures2)
            if l + juures1 >= 5:
                if ots1 > 0:
                    if valiklaud[ots1 - 1][x] == 0:
                        rist([x, ots1 - 1])
                        valiklaud[ots1 - 1][x] = "x"
            if l + juures2 >= 5:
                if ots2 < 9:
                    if valiklaud[ots2 + 1][x] == 0:
                        rist([x, ots2 + 1])
                        valiklaud[ots2 + 1][x] = "x"
        else:
            a = 2
            juures1 = 0
            juures2 = 0
            while x - a >= 0:
                try:
                    if valiklaud[y][x - a] == 1:
                        a += 1
                        juures1 += 1
                    else:
                        break
                except IndexError:
                    break
            a = 2
            while x + a <= 9:
                try:
                    if valiklaud[y][x + a] == 1:
                        a += 1
                        juures2 += 1
                    else:
                        break
                except IndexError:
                    break

            print(juures1, juures2)
            if juures1 >= 4:
                if x > 0:
                    if valiklaud[y][x - 1] == 0:
                        rist([x - 1, y])
                        valiklaud[y][x - 1] = "x"
            if juures2 >= 4:
                if x < 9:
                    if valiklaud[y][x + 1] == 0:
                        rist([x + 1, y])
                        valiklaud[y][x + 1] = "x"

            a = 2
            juures1 = 0
            juures2 = 0
            while y - a >= 0:
                try:
                    if valiklaud[y - a][x] == 1:
                        a += 1
                        juures1 += 1
                    else:
                        break
                except IndexError:
                    break
            a = 2
            while y + a <= 9:
                try:
                    if valiklaud[y + a][x] == 1:
                        a += 1
                        juures2 += 1
                    else:
                        break
                except IndexError:
                    break

            print(juures1, juures2)
            if juures1 >= 4:
                if y > 0:
                    if valiklaud[y - 1][x] == 0:
                        rist([x, y - 1])
                        valiklaud[y - 1][x] = "x"
            if juures2 >= 4:
                if y < 9:
                    if valiklaud[y + 1][x] == 0:
                        rist([x, y + 1])
                        valiklaud[y + 1][x] = "x"

        j.goto(-248 + 50 * x, -247 + 50 * y)

def eemalda():
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time() + 0.3
    x = asukoht[0]
    y = asukoht[1]
    if valiklaud[y][x] == 1:
        valiklaud[y][x] = 0
        j.goto(-225 + 50 * x, -225 + 50 * y)
        j.pencolor("#FFFFFF")
        j.pendown()
        j.dot(23)
        j.penup()
        for i in [[x+1,y+1],[x+1,y-1],[x-1,y+1],[x-1,y-1]]:
            if not (i[0] < 0 or i[1] < 0 or i[0] > 9 or i[1] > 9):
                if valiklaud[i[1]][i[0]] == "x":
                    lsd = []
                    if i[1] < 9:
                        if i[0] < 9:
                            lsd.append(valiklaud[i[1]+1][i[0]+1])
                        if i[0] > 0:
                            lsd.append(valiklaud[i[1]+1][i[0]-1])
                    if i[1] > 0:
                        if i[0] < 9:
                            lsd.append(valiklaud[i[1]-1][i[0]+1])
                        if i[0] > 0:
                            lsd.append(valiklaud[i[1]-1][i[0]-1])
                    if 1 not in lsd:
                        unrist([i[0],i[1]])
                        valiklaud[i[1]][i[0]] = 0
                    del lsd

        ots1 = x
        while ots1 > 0 and valiklaud[y][ots1 - 1] == 1:
            ots1 -= 1
        ots2 = y
        while ots2 > 0 and valiklaud[ots2 - 1][x] == 1:
            ots2 -= 1
        ots3 = x
        while ots3 < 9 and valiklaud[y][ots3 + 1] == 1:
            ots3 += 1
        ots4 = y
        while ots4 < 9 and valiklaud[ots4 + 1][x] == 1:
            ots4 += 1
        print(ots1,ots2,ots3,ots4)

        if x - ots1 <= 4 and ots1 > 0:
            if valiklaud[y][ots1-1] == "x":
                lsd = []
                if y < 9:
                    if ots1-1 < 9:
                        lsd.append(valiklaud[y + 1][ots1])
                    if ots1-1 > 0:
                        lsd.append(valiklaud[y + 1][ots1-2])
                if y > 0:
                    if ots1-1 < 9:
                        lsd.append(valiklaud[y - 1][ots1])
                    if ots1-1 > 0:
                        lsd.append(valiklaud[y - 1][ots1-2])
                if 1 not in lsd:
                    unrist([ots1-1, y])
                    valiklaud[y][ots1-1] = 0
                del lsd
        if ots3 - x <= 4 and ots3 < 9:
            if valiklaud[y][ots3+1] == "x":
                lsd = []
                if y < 9:
                    if ots3+1 < 9:
                        lsd.append(valiklaud[y + 1][ots3+2])
                    if ots3+1 > 0:
                        lsd.append(valiklaud[y + 1][ots3])
                if y > 0:
                    if ots3+1 < 9:
                        lsd.append(valiklaud[y - 1][ots3+2])
                    if ots3+1 > 0:
                        lsd.append(valiklaud[y - 1][ots3])
                if 1 not in lsd:
                    unrist([ots3+1, y])
                    valiklaud[y][ots3+1] = 0
                del lsd
        if y - ots2 <= 4 and ots2 > 0:
            if valiklaud[ots2-1][x] == "x":
                lsd = []
                if ots2-1 < 9:
                    if x < 9:
                        lsd.append(valiklaud[ots2][x+1])
                    if x > 0:
                        lsd.append(valiklaud[ots2][x-1])
                if ots2-1 > 0:
                    if x < 9:
                        lsd.append(valiklaud[ots2-2][x+1])
                    if x > 0:
                        lsd.append(valiklaud[ots2-2][x-1])
                if 1 not in lsd:
                    unrist([x, ots2-1])
                    valiklaud[ots2-1][x] = 0
                del lsd
        if ots4 - y <= 4 and ots4 < 9:
            if valiklaud[ots4+1][x] == "x":
                lsd = []
                if ots4+1 < 9:
                    if x < 9:
                        lsd.append(valiklaud[ots4+2][x+1])
                    if x > 0:
                        lsd.append(valiklaud[ots4+2][x-1])
                if ots4+1 > 0:
                    if x < 9:
                        lsd.append(valiklaud[ots4][x+1])
                    if x > 0:
                        lsd.append(valiklaud[ots4][x-1])
                if 1 not in lsd:
                    unrist([x, ots4+1])
                    valiklaud[ots4+1][x] = 0
                del lsd

        j.goto(-248 + 50 * x, -247 + 50 * y)

def rist(asuk):
    global lastpress
    lastpress += 0.1
    j.pencolor("#FF0000")
    j.goto(-225 + 50 * asuk[0], -225 + 50 * asuk[1])
    j.pendown()
    j.left(45)
    j.forward(20)
    j.back(40)
    j.forward(20)
    j.right(90)
    j.forward(20)
    j.back(40)
    j.forward(20)
    j.left(45)
    j.penup()

def unrist(asuk):
    global lastpress
    lastpress += 0.1
    j.pencolor("#FFFFFF")
    j.goto(-225 + 50 * asuk[0], -225 + 50 * asuk[1])
    j.pendown()
    j.left(45)
    j.forward(20)
    j.back(40)
    j.forward(20)
    j.right(90)
    j.forward(20)
    j.back(40)
    j.forward(20)
    j.left(45)
    j.penup()

def valm1():
    if 1 in [i for e in valiklaud for i in e]:
        global valm
        valm = Toplevel(control)
        valm.title("Oled sa kindel?")
        valm.geometry('300x80')

        msg = Label(valm, text="Oled sa kindel?")
        msg.place(x=100, y=5)
        nupp2 = ttk.Button(valm, text="JAH", command=valm2)
        nupp2.place(x=75, y=40, width=75)
        nupp3 = ttk.Button(valm, text="EI", command=lambda: valm.destroy())
        nupp3.place(x=150, y=40, width=75)
    else:
        mb.showerror("ERROR","Laual ei ole ühtegi laeva.")

def valm2():
    global sobib
    global valm
    sobib = True
    valm.destroy()
    control.destroy()
    laevavalik.destroy()

laevavalik = Tk()
laevavalik.title("Laevade paigutamine")
canvas = Canvas(master = laevavalik, width = 700, height = 700)
canvas.pack()

j = turtle.RawTurtle(canvas)
j.speed(0)
j.hideturtle()
j.pensize(10)
j.penup()
for i in range(11):
    j.goto(-250, -250 + 50 * i)
    j.pendown()
    j.forward(500)
    j.penup()
j.left(90)
for i in range(11):
    j.goto(-250+50*i,-250)
    j.pendown()
    j.forward(500)
    j.penup()
j.pensize(5)
j.goto(-248,-247)
asukoht = [0,0]
j.pencolor("#00FF00")
j.pendown()
for i in range(4):
    j.forward(45)
    j.right(90)
j.penup()

control = Toplevel(laevavalik)
control.title("Paigutaja kontrollimine")
control.geometry('300x240')

lastpress = 0
nupp1 = ttk.Button(control, text="N", command=ules)
nupp1.place(x=75, y=20, width=150)
nupp2 = ttk.Button(control, text="W", command=vasakule)
nupp2.place(x=75, y=45, width=75)
nupp3 = ttk.Button(control, text="E", command=paremale)
nupp3.place(x=150, y=45, width=75)
nupp4 = ttk.Button(control, text="S", command=alla)
nupp4.place(x=75, y=70, width=150)
nupp5 = ttk.Button(control, text="Paiguta", command=paiguta)
nupp5.place(x=75, y=120, width=150)
nupp6 = ttk.Button(control, text="Eemalda", command=eemalda)
nupp6.place(x=75, y=145, width=150)
nupp7 = ttk.Button(control, text="Valmis", command=valm1)
nupp7.place(x=75, y=200, width=150)
valiklaud = [[0 for i in range(10)] for j in range(10)]
print(valiklaud)

sobib = False
laevavalik.mainloop()
if not sobib:
    sys.exit()
print(valiklaud)

kaidud = []
laevad = []
for y in range(10):
    for x in range(10):
        if valiklaud[y][x] == 1 and [x,y] not in kaidud:
            laev = [[x,y]]
            kaidud.append([x,y])
            a = 1
            while x + a <= 9:
                if valiklaud[y][x+a] == 1:
                    laev.append([x+a, y])
                    kaidud.append([x+a, y])
                    a += 1
                else:
                    break
            a = 1
            while y + a <= 9:
                if valiklaud[y+a][x] == 1:
                    laev.append([x, y+a])
                    kaidud.append([x, y+a])
                    a += 1
                else:
                    break
            laevad.append(laev)
print(laevad)
laevapikkused = [len(i) for i in laevad]
print(laevapikkused)

def ules():
    if not kaik:
        return None
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[1] < 9:
        asukoht[1] += 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(102 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def alla():
    if not kaik:
        return None
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[1] > 0:
        asukoht[1] -= 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(102 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def vasakule():
    if not kaik:
        return None
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[0] > 0:
        asukoht[0] -= 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(102 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def paremale():
    if not kaik:
        return None
    global lastpress
    if time() - lastpress < 0.6:
        return None
    lastpress = time()
    j.pendown()
    #print(asukoht)
    if asukoht[0] < 9:
        asukoht[0] += 1
    else:
        return None
    j.pencolor("#000000")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.goto(102 + 50 * asukoht[0], -247 + 50 * asukoht[1])
    j.pencolor("#00FF00")
    for i in range(4):
        j.forward(45)
        j.right(90)
    j.penup()

def mark():
    if not kaik:
        return None
    global lastpress
    lastpress += 0.1
    j.pencolor("#FF0000")
    j.goto(125 + 50 * asukoht[0], -225 + 50 * asukoht[1])
    j.pendown()
    j.left(45)
    j.forward(10)
    j.back(20)
    j.forward(10)
    j.right(90)
    j.forward(10)
    j.back(20)
    j.forward(10)
    j.left(45)
    j.penup()
    j.goto(102 + 50 * asukoht[0], -247 + 50 * asukoht[1])

def unmark():
    if not kaik:
        return None
    global lastpress
    lastpress += 0.1
    j.pencolor("#FFFFFF")
    j.goto(125 + 50 * asukoht[0], -225 + 50 * asukoht[1])
    j.pendown()
    j.left(45)
    j.forward(10)
    j.back(20)
    j.forward(10)
    j.right(90)
    j.forward(10)
    j.back(20)
    j.forward(10)
    j.left(45)
    j.penup()
    j.goto(102 + 50 * asukoht[0], -247 + 50 * asukoht[1])

def pomm():
    if not kaik:
        return None
    pass

laud = Tk()
laud.title("Laevade paigutamine")
canvas = Canvas(master = laud, width = 1400, height = 700)
canvas.pack()

j = turtle.RawTurtle(canvas)
j.speed(0)
j.hideturtle()
j.pensize(10)
j.penup()
for i in range(11):
    j.goto(-600, -250 + 50 * i)
    j.pendown()
    j.forward(500)
    j.penup()
j.left(90)
for i in range(11):
    j.goto(-600 + 50 * i,-250)
    j.pendown()
    j.forward(500)
    j.penup()
j.right(90)
j.goto(-350,270)
j.write("SINU LAUD",True,"center",("Arial",40,"bold"))
for i in range(11):
    j.goto(100, -250 + 50 * i)
    j.pendown()
    j.forward(500)
    j.penup()
j.left(90)
for i in range(11):
    j.goto(100 + 50 * i,-250)
    j.pendown()
    j.forward(500)
    j.penup()
j.goto(350,270)
j.write("ARVUTI LAUD",False,"center",("Arial",40,"bold"))

j.pencolor("#0000FF")
j.pensize(23)
for i in laevad:
    j.goto(-575 + 50 * i[0][0], -225 + 50 * i[0][1])
    j.pendown()
    for e in range(len(i)):
        j.goto(-575 + 50 * i[e][0], -225 + 50 * i[e][1])
    j.penup()

j.pensize(5)
j.goto(102,-247)
asukoht = [0,0]
j.pencolor("#00FF00")
j.pendown()
for i in range(4):
    j.forward(45)
    j.right(90)
j.penup()

control = Toplevel(laud)
control.title("Pommitaja kontrollimine")
control.geometry('300x210')
nupp1 = ttk.Button(control, text="N", command=ules)
nupp1.place(x=75, y=20, width=150)
nupp2 = ttk.Button(control, text="W", command=vasakule)
nupp2.place(x=75, y=45, width=75)
nupp3 = ttk.Button(control, text="E", command=paremale)
nupp3.place(x=150, y=45, width=75)
nupp4 = ttk.Button(control, text="S", command=alla)
nupp4.place(x=75, y=70, width=150)
nupp5 = ttk.Button(control, text="Märgista", command=mark)
nupp5.place(x=75, y=120, width=150)
nupp6 = ttk.Button(control, text="Eemalda märgistus", command=unmark)
nupp6.place(x=75, y=145, width=150)
nupp7 = ttk.Button(control, text="Allahu akbar!", command=pomm)
nupp7.place(x=75, y=170, width=150)

kaik = True
laud.mainloop()

print()
print(encode("Hello World"))
a = base64.b64encode(bytes("Hello World", "utf-8"))
print(a)
b = base64.b64decode(a)
print(b)
print(str(b,"utf-8"))