from typing import List, Sequence, Tuple, Union

import megengine.data as data
import megengine.data.transform as T
import numpy as np

__all__ = ["MixupCutmixTransform", "MixupCutmixCollator"]

def _one_hot(
    x: np.ndarray, num_classes: int, on_value: float = 1.0, off_value: float = 0.0
) -> np.ndarray:
    one_hot = np.full((x.shape[0], num_classes), off_value)
    np.put_along_axis(one_hot, x[:, np.newaxis], values=on_value, axis=1)
    return one_hot

def _mixup_target(
    target: np.ndarray,
    num_classes: int,
    lam: Union[float, np.ndarray] = 1.0,
    perm: Sequence[int] = None,
) -> np.ndarray:
    if perm is None:
        perm = slice(None, None, -1)
    y1 = _one_hot(target, num_classes)
    y2 = _one_hot(target[perm], num_classes)
    return y1 * lam + y2 * (1.0 - lam)

def _rand_bbox(img_shape: Tuple, lam: float, margin: float = 0.0, count: int = None) -> Tuple:
    """Standard CutMix bounding-box.

    Generates a random square bbox based on lambda value. This impl includes
    support for enforcing a border margin as percent of bbox dimensions.

    Args:
        img_shape: image shape as tuple.
        lam: cutmix lambda value.
        margin: percentage of bbox dimension to enforce as margin
            (reduce amount of box outside image).
        count: number of bbox to generate.

    Returns:
        (y1, y2, x1, x2) represents (up, down, left, righ) of bbox.
    """
    ratio = np.sqrt(1.0 - lam)
    img_h, img_w = img_shape
    cut_h, cut_w = int(img_h * ratio), int(img_w * ratio)
    margin_y, margin_x = int(margin * cut_h), int(margin * cut_w)
    cy = np.random.randint(0 + margin_y, img_h - margin_y, size=count)
    cx = np.random.randint(0 + margin_x, img_w - margin_x, size=count)
    y1 = np.clip(cy - cut_h // 2, 0, img_h)
    y2 = np.clip(cy + cut_h // 2, 0, img_h)
    x1 = np.clip(cx - cut_w // 2, 0, img_w)
    x2 = np.clip(cx + cut_w // 2, 0, img_w)
    return y1, y2, x1, x2

def _rand_bbox_minmax(img_shape: Tuple, minmax: Sequence[float], count: int = None) -> Tuple:
    """Min-Max CutMix bounding-box.

    Inspired by Darknet cutmix impl, generates a random rectangular bbox
    based on min/max percent values applied to each dimension of the input image.

    Typical defaults for minmax are usually in the  .2-.3 for min and .8-.9 range for max.

    Args:
        img_shape: image shape as tuple.
        minmax: min and max bbox ratios (as percent of image size).
        count: number of bbox to generate.

    Returns:
        (y1, y2, x1, x2) represents (up, down, left, righ) of bbox.
    """
    assert len(minmax) == 2
    img_h, img_w = img_shape
    cut_h = np.random.randint(int(img_h * minmax[0]), int(img_h * minmax[1]), size=count)
    cut_w = np.random.randint(int(img_w * minmax[0]), int(img_w * minmax[1]), size=count)
    y1 = np.random.randint(0, img_h - cut_h, size=count)
    x1 = np.random.randint(0, img_w - cut_w, size=count)
    y2 = y1 + cut_h
    x2 = x1 + cut_w
    return y1, y2, x1, x2

def _cutmix_bbox_and_lam(
    img_shape: Tuple,
    lam: float,
    ratio_minmax: Sequence[float] = None,
    correct_lam: bool = True,
    count: int = None,
) -> Tuple:
    """Generate bbox and apply lambda correction."""
    if ratio_minmax is not None:
        y1, y2, x1, x2 = _rand_bbox_minmax(img_shape, ratio_minmax, count=count)
    else:
        y1, y2, x1, x2 = _rand_bbox(img_shape, lam, count=count)
    if correct_lam or ratio_minmax is not None:
        bbox_area = (y2 - y1) * (x2 - x1)
        lam = 1.0 - bbox_area / float(img_shape[-2] * img_shape[-1])
    return (y1, y2, x1, x2), lam

class MixupCutmixTransform(T.VisionTransform):
    """Implement Mixup and CutMix as VisionTransform.

    .. note::

        When composed in :py:class:`~megengine.data.transform.Compose` ,
        ``batch_compose`` must be set to ``True``.

    Args:
        mixup_alpha: mixup alpha value, mixup is active if > 0. Default: ``1.0``
        cutmix_alpha: cutmix alpha value, cutmix is active if > 0. Default: ``0.0``
        cutmix_minmax: cutmix min/max image ratio, cutmix is active and uses this vs alpha
            if not None. Default: ``None``
        prob: probability of applying mixup or cutmix per batch or element. Default: ``1.0``
        switch_prob: probability of switching to cutmix instead of mixup when both are active.
            Default: 0.5
        mode: how to apply mixup/cutmix params, supports  ``"batch"``, ``"pair"``
            (pair of elements) and ``"elem"`` (element). Default: ``"batch"``
        data_format: ``"CHW"`` or ``"HWC"``, use ``"HWC"`` if use this transform before
            ``T.ToMode()``. Default: ``"HWC"``
        num_classes: number of classes for target. Default: ``1000``
        calibrate_cutmix_lambda: apply lambda correction when cutmix bbox clipped by image borders.
            Correction is based on clipped area for cutmix. Default: ``True``
        calibrate_mixup_lambda: enforce mixup lambda to be greater than 0.5, only make difference
            in ``"elem"`` mode. Default: ``False``
        permute: whether mixup with permuted samples instead of flipped samples. Default: ``False``
    """

    def __init__(
        self,
        mixup_alpha: float = 1.0,
        cutmix_alpha: float = 0.0,
        cutmix_minmax: List[float] = None,
        prob: float = 1.0,
        switch_prob: float = 0.5,
        mode: str = "batch",
        data_format: str = "HWC",
        num_classes: int = 1000,
        calibrate_cutmix_lambda: bool = True,
        calibrate_mixup_lambda: bool = False,
        permute: bool = False,
        *,
        order=None,
    ):
        super().__init__(order)
        self.mixup_alpha = mixup_alpha
        self.cutmix_alpha = cutmix_alpha
        self.cutmix_minmax = cutmix_minmax
        if self.cutmix_minmax is not None:
            assert len(self.cutmix_minmax) == 2
            # force cutmix alpha == 1.0 when minmax active to keep logic simple & safe
            self.cutmix_alpha = 1.0
        self.mix_prob = prob
        self.switch_prob = switch_prob
        if mode not in ("batch", "pair", "elem"):
            raise ValueError(f"Mixup/CutMix mode '{mode}' not supported")
        self.mode = mode
        self.calibrate_cutmix_lambda = calibrate_cutmix_lambda
        if data_format not in ("CHW", "HWC"):
            raise ValueError(f"Data format '{data_format}' not supported")
        self.data_format = data_format
        self.num_classes = num_classes
        self.calibrate_mixup_lambda = calibrate_mixup_lambda
        self.permute = permute

    def _params_per_elem(self, batch_size: int):
        lam = np.ones(batch_size, dtype=np.float32)
        use_cutmix = np.zeros(batch_size, dtype=np.bool_)
        if self.mixup_alpha == 0.0 and self.cutmix_alpha == 0.0:
            return lam, use_cutmix
        if self.mixup_alpha > 0.0 and self.cutmix_alpha > 0.0:
            use_cutmix = np.random.rand(batch_size) < self.switch_prob
            lam_mix = np.where(
                use_cutmix,
                np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size),
                np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size),
            )
        elif self.mixup_alpha > 0.0:
            lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size)
        elif self.cutmix_alpha > 0.0:
            use_cutmix = np.ones(batch_size, dtype=np.bool_)
            lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size)
        else:
            raise ValueError(
                "One of mixup_alpha > 0.0, cutmix_alpha > 0.0,"
                "cutmix_minmax not None should be true."
            )
        if self.calibrate_mixup_lambda:
            lam_mix = np.where(use_cutmix, lam_mix, np.maximum(lam_mix, 1 - lam_mix))
        lam = np.where(np.random.rand(batch_size) < self.mix_prob, lam_mix.astype(np.float32), lam)
        return lam, use_cutmix

    def _params_per_batch(self):
        lam = 1.0
        use_cutmix = False
        if (self.mixup_alpha > 0.0 or self.cutmix_alpha > 0.0) and np.random.rand() < self.mix_prob:
            if self.mixup_alpha > 0.0 and self.cutmix_alpha > 0.0:
                use_cutmix = np.random.rand() < self.switch_prob
                lam_mix = (
                    np.random.beta(self.cutmix_alpha, self.cutmix_alpha)
                    if use_cutmix
                    else np.random.beta(self.mixup_alpha, self.mixup_alpha)
                )
            elif self.mixup_alpha > 0.0:
                lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha)
            elif self.cutmix_alpha > 0.0:
                use_cutmix = True
                lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha)
            else:
                raise ValueError(
                    "One of mixup_alpha > 0.0, cutmix_alpha > 0.0,"
                    "cutmix_minmax not None should be true."
                )
            lam = float(lam_mix)
        return lam, use_cutmix

    def _mix_elem(self, x, perm: Sequence[int]):
        batch_size = len(x)
        lam_batch, use_cutmix = self._params_per_elem(batch_size)
        x_ori = x.copy()  # need to keep an unmodified original for mixing source
        for i in range(batch_size):
            j = perm[i]
            lam = lam_batch[i]
            if lam != 1.0:
                if use_cutmix[i]:
                    (y1, y2, x1, x2), lam = _cutmix_bbox_and_lam(
                        x.shape[-2:] if self.data_format == "CHW" else x.shape[1:3],
                        lam,
                        ratio_minmax=self.cutmix_minmax,
                        correct_lam=self.calibrate_cutmix_lambda,
                    )
                    if self.data_format == "CHW":
                        x[i, :, y1:y2, x1:x2] = x_ori[j, :, y1:y2, x1:x2]
                    else:
                        x[i, y1:y2, x1:x2] = x_ori[j, y1:y2, x1:x2]
                    lam_batch[i] = lam
                else:
                    x[i] = x[i] * lam + x_ori[j] * (1.0 - lam)
        return lam_batch[:, np.newaxis]

    def _mix_pair(self, x, perm: Sequence[int]):
        batch_size = len(x)
        lam_batch, use_cutmix = self._params_per_elem(batch_size // 2)
        x_ori = x.copy()  # need to keep an unmodified original for mixing source
        for i in range(batch_size // 2):
            j = perm[i]
            lam = lam_batch[i]
            if lam != 1.0:
                if use_cutmix[i]:
                    (y1, y2, x1, x2), lam = _cutmix_bbox_and_lam(
                        x.shape[-2:] if self.data_format == "CHW" else x.shape[1:3],
                        lam,
                        ratio_minmax=self.cutmix_minmax,
                        correct_lam=self.calibrate_cutmix_lambda,
                    )
                    if self.data_format == "CHW":
                        x[i, :, y1:y2, x1:x2] = x_ori[j, :, y1:y2, x1:x2]
                        x[j, :, y1:y2, x1:x2] = x_ori[i, :, y1:y2, x1:x2]
                    else:
                        x[i, y1:y2, x1:x2] = x_ori[j, y1:y2, x1:x2]
                        x[j, y1:y2, x1:x2] = x_ori[i, y1:y2, x1:x2]
                    lam_batch[i] = lam
                else:
                    x[i] = x[i] * lam + x_ori[j] * (1.0 - lam)
                    x[j] = x[j] * lam + x_ori[i] * (1.0 - lam)
        lam_batch = np.concatenate((lam_batch, lam_batch[perm]))
        return lam_batch[:, np.newaxis]

    def _mix_batch(self, x, perm: Sequence[int]):
        lam, use_cutmix = self._params_per_batch()
        if lam == 1.0:
            return 1.0
        if use_cutmix:
            (y1, y2, x1, x2), lam = _cutmix_bbox_and_lam(
                x.shape[-2:] if self.data_format == "CHW" else x.shape[1:3],
                lam,
                ratio_minmax=self.cutmix_minmax,
                correct_lam=self.calibrate_cutmix_lambda,
            )
            if self.data_format == "CHW":
                x[:, :, y1:y2, x1:x2] = x[perm, :, y1:y2, x1:x2]
            else:
                x[:, y1:y2, x1:x2] = x[perm, y1:y2, x1:x2]
        else:
            x[:] = x * lam + x[perm] * (1.0 - lam)
        return lam

    def apply_batch(self, inputs: Sequence[Tuple]):
        images, targets = tuple(zip(*inputs))
        images = np.stack(images)
        targets = np.stack(targets)

        dtype = images.dtype
        images = images.astype(np.float32)

        batch_size = len(images)
        if self.mode == "pair":
            batch_size = batch_size // 2
        if self.permute:
            perm = np.random.permutation(batch_size)
        else:
            perm = np.arange(batch_size)[::-1]

        if self.mode == "elem":
            lam = self._mix_elem(images, perm=perm)
        elif self.mode == "pair":
            lam = self._mix_pair(images, perm=perm)
        else:
            lam = self._mix_batch(images, perm=perm)
        targets = _mixup_target(targets, self.num_classes, lam, perm=perm)

        return tuple(zip(images.clip(0, 255).astype(dtype), targets.astype(np.float32)))

class MixupCutmixCollator(data.Collator):
    """A faster version implemented as a collator."""

    def __init__(self, *args, **kwargs):
        self.collator = data.Collator()
        self.transform = MixupCutmixTransform(*args, data_format="CHW", **kwargs)

    def apply(self, inputs: Sequence[Tuple]):
        inputs = self.transform.apply_batch(inputs)
        inputs = self.collator.apply(inputs)
        return inputs


from pathlib import Path
from typing import Tuple, Optional, Callable, Any

import numpy as np
from torchvision.datasets import CIFAR10

from definitions import DATASETS_DIR
from PIL import Image

class CIFAR10SSL(CIFAR10):
    """
    Dataset CIFAR10 adapted for semi-supervised learning.

    Adapts CIFAR10 dataset class provided by PyTorch by allowing a
    range which selects a subset of images for each class.

    CIFAR-10 dataset consists of 60k 32x32 colour images, from 10
    classes, 6k images per class. 50k are training images and 10k
    are test images. The home page of the dataset is provided
    in <https://www.cs.toronto.edu/~kriz/cifar.html> by the
    University of Toronto.
    """

    # number of examples per class in train and test
    per_class_train = 5000
    per_class_test = 1000

    def __init__(self,
                 root_path: str or Path,
                 train: bool,
                 data_range: Tuple[int, int],
                 weak_transform: Optional[Callable] = None,
                 strong_transform: Optional[Callable] = None,
                 target_transform: Optional[Callable] = None):
        """
        Constructor of CIFAR10SSL dataset object.

        :param root_path:
            path to store or look up data.
        :param train:
            get data from train set (50000 images) or from test set (10000 images).
        :param data_range:
            range of images to select from every class.
        """

        super(CIFAR10SSL, self).__init__(root=root_path,
                                         train=train,
                                         download=True,
                                         target_transform=target_transform)

        self.__order_data()
        self.data_range = data_range
        self.__resolve_data_range()
        self.shuffle_data()

        # weak and strong transformations
        self.weak_transform = weak_transform
        self.strong_transform = strong_transform

    def __getitem__(self, index: int) -> Tuple[Any, ...]:
        """
        Get example from dataset using index.

        :param index:
            index to search in database.

        :return:
            Image applying transformations if exists, and label.
        """

        # retrieve data based on index
        img, target = self.data[index], self.targets[index]

        # consistency with original implementation
        img = Image.fromarray(img)
        weak, strong = None, None

        # weak augmentation
        if self.weak_transform is not None:
            weak = self.weak_transform(img)
        # strong augmentation
        if self.strong_transform is not None:
            strong = self.strong_transform(img)

        # target transform
        if self.target_transform is not None:
            target = self.target_transform(target)

        # if no weak transformation original img is output
        weak = img if not self.weak_transform else weak

        # if not strong augmentation, usual return
        if not self.strong_transform:
            return weak, target

        return weak, strong, target

    def shuffle_data(self):
        """
        Shuffle both data and its targets randomly.
        """

        # obtain random permutation
        permutation = np.random.permutation(len(self))

        # apply permutation to data and targets
        self.targets = self.targets[permutation]
        self.data = self.data[permutation]

    def mean_and_std(self) -> Tuple[list, list]:
        """
        :return:
            mean and standard deviation of dataset per channel.
        """

        return ((self.data / 255).mean(axis=(0, 1, 2)),
                (self.data / 255).std(axis=(0, 1, 2)))

    def __order_data(self):
        """
        Order data sequentially by class index (0 to 9).
        """

        # get order from targets then apply it to data and targets
        order = np.asarray(self.targets).argsort()
        self.targets = np.asarray(self.targets)[order].astype(np.int64)
        self.data = self.data[order]

    def __resolve_data_range(self):
        """
        Select a reduced number of examples per class using a range.
        """

        # check if data_range is a tuple with 2 elements
        assert isinstance(self.data_range, tuple), 'range must be a tuple'
        assert len(self.data_range) == 2, 'range tuple must have exactly two integers'

        # check if both data_range elements are integers
        range_l, range_h = self.data_range
        assert isinstance(range_l, int) and isinstance(range_h, int), 'numbers must be integers'

        # check if data_range is within boundaries and valid
        max_val = self.per_class_train if self.train else self.per_class_test
        assert 0 <= range_l < range_h <= max_val, f'invalid range (max {max_val} img/class)'

        # select data and targets specified by validated data_range
        ids = [idx + max_val * nclass for nclass in range(len(self.classes)) for idx in range(range_l, range_h)]
        self.data = self.data[ids]
        self.targets = self.targets[ids]

class CIFAR100SSL(CIFAR10SSL):
    """
    Dataset CIFAR100 adapted for semi-supervised learning.

    Adapts CIFAR100 dataset class provided by PyTorch by allowing a
    range which selects a subset of images for each class.

    CIFAR-100 dataset consists of 60k 32x32 colour images, from 100
    classes, 600 images per class. 50k are training images and 10k
    are test images. The home page of the dataset is provided
    in <https://www.cs.toronto.edu/~kriz/cifar.html> by the
    University of Toronto.

    This is a subclass of the `CIFAR10SSL` Dataset.
    """

    base_folder = "cifar-100-python"
    url = "https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz"
    filename = "cifar-100-python.tar.gz"
    tgz_md5 = "eb9058c3a382ffc7106e4002c42a8d85"
    train_list = [
        ["train", "16019d7e3df5f24257cddd939b257f8d"],
    ]

    test_list = [
        ["test", "f0ef6b0ae62326f3e7ffdfab6717acfc"],
    ]
    meta = {
        "filename": "meta",
        "key": "fine_label_names",
        "md5": "7973b15100ade9c7d40fb424638fde48",
    }

    # number of examples per class in train and test
    per_class_train = 500
    per_class_test = 100

if __name__ == "__main__":
    path = DATASETS_DIR / 'cifar10'
    cifar10ds = CIFAR10SSL(root_path=path,
                           train=True,
                           data_range=(0, 5000))
    print('Total number of images in dataset: ', len(cifar10ds))
    print('Total number of classes in dataset: ', len(cifar10ds.classes))
    mean, std = cifar10ds.mean_and_std()
    print(f"""
    Mean +/- Std: {mean} +/- {std}
    """)

    path1 = DATASETS_DIR / 'cifar100'
    cifar100ds = CIFAR100SSL(root_path=path1,
                             train=True,
                             data_range=(0, 500))
    print('Total number of images in dataset: ', len(cifar100ds))
    print('Total number of classes in dataset: ', len(cifar100ds.classes))
    mean, std = cifar100ds.mean_and_std()
    print(f"""
    Mean +/- Std: {mean} +/- {std}
    """)


from pynput.keyboard import Key, Controller
import time
import pyautogui
import cv2
import numpy as np
import copy
import pyscreenshot as ImageGrab
from datetime import datetime
from mss import mss
from simulation import Simulation

NUMBER_OF_IMAGES = 500
SAMPLE_TIME = 0.01

class Vision():

	def __init__(self):
		self.keyboard = Controller()
		return

	def simulate_space_bar(self):
		#time.sleep(2)
		#for i in range(100):
		self.keyboard.press(" ")
		self.keyboard.release(" ")
	#	time.sleep(0.12)

	def take_screen_shot(self):
		#return ImageGrab.grab(bbox=(740,160, 490, 680))
	#	im.save(fname, 'png')
		mon = {"left": 740, "top": 160, "width": 490, "height":680}
		#mon':0, "top": 740, "left": 160, "width": 490, "height": 680}
		sct = mss()
		img = np.array(sct.grab(mon))
		return img
	#	print(filename)
	#	return pyautogui.screenshot(region=(740,160, 490, 680))

	def get_train_imgs(self):
		screen = []
		for i in range(NUMBER_OF_IMAGES):
			time.sleep(SAMPLE_TIME)
			screen.append(self.take_screen_shot())

		for i in range(NUMBER_OF_IMAGES):
			#image = cv2.cvtColor(np.array(screen[i]), cv2.COLOR_BGR2RGB)
			cv2.imwrite('images/'+str(i)+'.png', screen[i])

	def get_all_parameters(self):
		for i in range(NUMBER_OF_IMAGES):
			self.take_img_parameters(i)

	def take_img_parameters(self, number):
		img = cv2.imread('images/'+str(number)+'.png')
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

		lower = np.array([40,50,50])
		upper = np.array([60,255,255])
		mask = cv2.inRange(img, lower, upper)
		green = cv2.bitwise_and(img, img, mask= mask)
		kernel = np.ones((5,5),np.uint8)
		green = cv2.erode(green, kernel,iterations = 1)
		m, green = cv2.threshold(green, 10, 255, cv2.THRESH_BINARY)
		greencolor = np.array([0, 255, 0])
		green = cv2.bitwise_and(green, greencolor)
	#	cv2.imshow('teste', green)
	#	cv2.waitKey(0)
		cv2.imwrite('images/processed/'+str(number)+'.png', green)

	def get_bird(self, filename):
		#deprecated
		'''img = cv2.imread(filename)
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

		lower = np.array([10,10,50])
		upper = np.array([40,255,255])
		kernel = np.ones((10,10),np.uint8)
		yellow = cv2.erode(img, kernel,iterations = 1)
		mask = cv2.inRange(yellow, lower, upper)
		yellow = cv2.bitwise_and(img, img, mask= mask)
		m, yellow = cv2.threshold(yellow, 10, 255, cv2.THRESH_BINARY)
		yellowcolor = np.array([0, 255, 255])
		yellow = cv2.bitwise_and(yellow, yellowcolor)
		cv2.imshow('teste', yellow)
		cv2.waitKey(0)
		cv2.imwrite('images/bird.png', yellow)
		#print(len(yellow), len(yellow[0]))
		'''
		try:
			img = cv2.imread(filename)
		except:
			img = filename
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
		print(img[10][10])
		#218 338
		lower = np.array([0,0,50])
		upper = np.array([30,255,255])
		kernel = np.ones((0,0),np.uint8)
		yellow = cv2.erode(img, kernel,iterations = 1)
		mask = cv2.inRange(yellow, lower, upper)
		yellow = cv2.bitwise_and(img, img, mask= mask)

		m, yellow = cv2.threshold(yellow, 10, 255, cv2.THRESH_BINARY)
		yellowcolor = np.array([0, 255, 255])
		yellow = cv2.bitwise_and(yellow, yellowcolor)
		#cv2.imshow('teste', yellow)
		#cv2.waitKey(0)
		cv2.imwrite('yellow.png', yellow)

		for i in range(670, 0, -1):
			#print(yellow[i][218])
			if(np.array_equal(yellow[i][218], [0, 255, 255])):
				return i
		return -1

	def get_borders(self, filename):
		img = cv2.imread(filename)
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

		lower = np.array([10,0,0])
		upper = np.array([180,255,255])
		kernel = np.ones((10,10),np.uint8)
		yellow = cv2.erode(img, kernel,iterations = 1)
		mask = cv2.inRange(yellow, lower, upper)
		yellow = cv2.bitwise_and(img, img, mask= mask)
		m, yellow = cv2.threshold(yellow, 10, 255, cv2.THRESH_BINARY)
		yellowcolor = np.array([0, 255, 255])
		yellow = cv2.bitwise_and(yellow, yellowcolor)
		#cv2.imshow('teste', yellow)
		#cv2.waitKey(0)
		cv2.imwrite('images/borders.png', yellow)
		#print(len(yellow), len(yellow[0]))

	def find_borders_values(self):
		img = cv2.imread('images/borders.png')
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
		px = int(len(img[0])/2)
		py = int(len(img)/2)-100
		#print('img', px, py)

		#print(img[py, px])
		pxleft = copy.copy(px)
		while(np.array_equal(img[py, pxleft], [0,0,0])):
			pxleft -= 1

		pxright = copy.copy(px)
		while(np.array_equal(img[py, pxright], [0,0,0])):
			pxright += 1
		#print(px, pxleft, pxright-pxleft)
		last_px = self.draw_square(pxleft, pxright-pxleft)
		#print('last_px, pxright', last_px, pxright)
		return last_px, pxright

	#before jump -9
	#after jump -89
	#total vertical 60
	#total horizontal 70
	def draw_square(self, left_border, length):
		img = cv2.imread('images/borders.png')
		#print('left_boder, lengh', left_border, length)
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
		for x in range(70):
			for y in range(60):
				px = int(left_border+length/2.0-x)+4
				py = int(len(img)/2)-9+y
				img[py, px] = [255, 0,0]
		#cv2.imshow('teste', img)
		#cv2.waitKey(0)
		#print('simultation py', py)
		#print('last_x_pixel', px)
		return px

	def get_pipe_pixel(self, last_px, pxright, filename):
		try:
			img = cv2.imread(filename)
		except:
			img = filename

		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

		img[570,last_px] = [255,255,255]
		#cv2.imshow('teste', img)
		#cv2.waitKey(0)
		#print('last, pxright', last_px, pxright)
		pipe_pixel = pxright
		#[print(img[int(i),last_px]) for i in range(len(img))]
		for i in range(last_px, pxright):
			if(np.array_equal(img[570, i], [0,255,0])):
				pipe_pixel = i
				break
		#print('pipe', pipe_pixel)
		return pipe_pixel

	def get_distance(self, filename):
		return self.get_pipe_pixel(182, 483, filename)

	# pipe under pixel 318
	# pipe over pixel 295 (total len 23)
	# hole len 73 (295-122)
	def get_center(self, filename):
		try:
			img = cv2.imread(filename)
		except:
			img = filename

		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
		hole_len = 200
		pipe_inferior_len = 25

		last_px = 182
		pipe_pixel = self.get_pipe_pixel(182, 483, filename)
		#print(pipe_pixel)

		pipe_inferior_pixel = 340
		for i in range(570, 0 ,-1):
			if(np.array_equal(img[i, pipe_pixel], [0,255,0])):
				pipe_inferior_pixel = i
				break
		#cv2.imshow('teste', img)
		#cv2.waitKey(0)
		return pipe_inferior_pixel + pipe_inferior_len + int(hole_len/2)

	def transform_image_green(self):
		cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

		lower = np.array([40,50,50])
		upper = np.array([60,255,255])
		mask = cv2.inRange(img, lower, upper)
		green = cv2.bitwise_and(img, img, mask= mask)
		kernel = np.ones((5,5),np.uint8)
		green = cv2.erode(green, kernel,iterations = 1)
		m, green = cv2.threshold(green, 10, 255, cv2.THRESH_BINARY)
		greencolor = np.array([0, 255, 0])
		green = cv2.bitwise_and(green, greencolor)
		return green

	def play(self, mlp):
		running = True
		chrom = Simulation()
		while(running):
			img = self.take_screen_shot()
			cv2.imwrite('actual.png', img)
			img = cv2.imread('actual.png')
			chrom.set_pos(self.get_bird(img)+30)
			jump = mlp.predict([[self.get_distance(img),
				chrom.get_dist_to_center(self.get_center(img))]])
			if(jump):
				self.simulate_space_bar()
		return


import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score, roc_auc_score
import matplotlib.pyplot as plt

# Function to plot KS chart
def plot_ks_chart(ks_table):
    """Function to plot KS chart"""
    ks_table['%cum_true_num'] = ks_table['%cum_true'].str.replace('%','').astype('float')
    ks_table['%cum_false_num'] = ks_table['%cum_false'].str.replace('%','').astype('float')
    plt.figure(figsize=(10,6))
    plt.plot(ks_table.index, ks_table['%cum_true_num'], 'g')
    plt.plot(ks_table.index, ks_table['%cum_false_num'], 'r')
    plt.fill_between(ks_table.index, ks_table['%cum_true_num'], ks_table['%cum_false_num'], color="grey", alpha=0.2, hatch='|')
    plt.xticks(ks_table.index)
    plt.title('KS - Accumulated curves')
    plt.legend(['%true', '%false'], loc='lower right')
    plt.xlabel('Decile')
    plt.ylabel('% Accumulated')
    plt.show()

def ks_calculate(model, x_val, y_val, target='good', verbose=True, buckets=10):
    """Function to calculate KS metric"""
    pred = model.predict(x_val)
    proba = model.predict_proba(x_val)
    if isinstance(y_val, np.ndarray):
        y_val = pd.DataFrame(y_val, columns=[target])
    df_val_ks = y_val.reset_index(drop=True)
    df2 = pd.DataFrame(proba, columns=['p0','p'])
    data_ks = df2.join(df_val_ks)
    ks_score, kstable = ks_calc(data=data_ks, target=target, prob="p", verbose=verbose, buckets=buckets)
    if verbose == True:
        print("accuracy_score: ", accuracy_score(y_val.values, pred))
        print("roc_auc_score: ", roc_auc_score(y_true= y_val.values, y_score= proba[:,1]))
        print("ks_score: ", ks_score)
    return ks_score, kstable

def ks_calc(data=None, target=None, prob=None, verbose=True, buckets=10):
    """Support function to calculate KS metric"""
    data['target0'] = 1 - data[target]
    data['bucket'] = pd.qcut(data[prob], buckets)
    grouped = data.groupby('bucket', as_index = False)
    kstable = pd.DataFrame()
    kstable['min_prob'] = grouped.min()[prob]
    kstable['max_prob'] = grouped.max()[prob]
    kstable['true']   = grouped.sum()[target]
    kstable['false'] = grouped.sum()['target0']
    kstable = kstable.sort_values(by="min_prob", ascending=False).reset_index(drop = True)
    kstable['true_rate'] = (kstable.true / data[target].sum()).apply('{0:.2%}'.format)
    kstable['false_rate'] = (kstable.false / data['target0'].sum()).apply('{0:.2%}'.format)
    kstable['%cum_true']=(kstable.true / data[target].sum()).cumsum()
    kstable['%cum_false']=(kstable.false / data['target0'].sum()).cumsum()
    kstable['KS'] = np.round(kstable['%cum_true']-kstable['%cum_false'], 3) * 100

    #Formating
    kstable['%cum_true']= kstable['%cum_true'].apply('{0:.2%}'.format)
    kstable['%cum_false']= kstable['%cum_false'].apply('{0:.2%}'.format)
    kstable.index = range(1,11)
    kstable.index.rename('Decile', inplace=True)
    pd.set_option('display.max_columns', 9)
    if verbose==True:
        print(kstable)
        print("KS is " + str(max(kstable['KS']))+"%"+ " at decile " + str((kstable.index[kstable['KS']==max(kstable['KS'])][0])))
    return round(max(kstable['KS']),4), kstable


from typing import Iterable

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from mutagen.id3 import TALB, TDRC, TIT2, TOPE, TPE1, TPE2, TRCK
from mutagen.oggopus import OggOpus

class BaseMetadataSetter:
    input_metadata_key_to_target_tag_map = {
        "artist": "",
        "album": "",
        "title": "",
        "track_number": "",
        "recording_year": "",
    }

    def __init__(self, filething, filepath, input_metadata_key, *args, **kwargs):
        if input_metadata_key not in self.input_metadata_key_to_target_tag_map.keys():
            raise ValueError(
                "Input metadata key not supported. Supported input names: {}".format(
                    ",".join(self.input_metadata_key_to_target_tag_map.keys())
                )
            )
        super().__init__(*args, **kwargs)
        self.filething = filething
        self.filepath = filepath
        self.input_metadata_key = input_metadata_key

    def set_tag(self, value):
        key = self.input_metadata_key_to_target_tag_map[self.input_metadata_key]
        self.filething.tags[key] = value

    def save_tags_to_file(self):
        self.filething.save(self.filepath)

class MP4MetadataSetter(BaseMetadataSetter):
    """
    Metadata setter for MP4 files.
    Info on mutagen's MP4 API:
    https://mutagen.readthedocs.io/en/latest/api/mp4.html
    """

    input_metadata_key_to_target_tag_map = {
        "artist": "\xa9ART",
        "album": "\xa9alb",
        "title": "\xa9nam",
        "track_number": "trkn",
        "recording_year": "\xa9day",
    }

    def set_tag(self, value):
        key = self.input_metadata_key_to_target_tag_map[self.input_metadata_key]
        # edge case: track number takes in a tuple of ints, not an int
        # the second int is the number of total tracks
        # setting to 0 for simplicity
        if key == "trkn":
            value = [[int(value), 0]]
        self.filething.tags[key] = value

class VorbisMetadataSetter(BaseMetadataSetter):
    """
    Metadata setter for files with Vorbis tags (.ogg family, .flac files).
    using metadata fieldname standard outlined by Ogg Vorbis:
    https://xiph.org/vorbis/doc/v-comment.html#fieldnames
    Info on mutagen's Ogg Vorbis API:
    https://mutagen.readthedocs.io/en/latest/api/ogg.html
    """

    input_metadata_key_to_target_tag_map = {
        "artist": "artist",
        "album": "album",
        "title": "title",
        "track_number": "tracknumber",
        "recording_year": "date",
    }

class ID3MetadataSetter(BaseMetadataSetter):
    """
    Metadata setter for files with ID3 tags (mostly .mp3 files).
    Info on mutagen's ID3 API:
    https://mutagen.readthedocs.io/en/latest/api/id3.html
    """

    input_metadata_key_to_id3_tag_map = {
        "artist": [TPE1, TPE2, TOPE],
        "album": TALB,
        "title": TIT2,
        "track_number": TRCK,
        "recording_year": TDRC,
    }

    def set_tag(self, value):
        mapped_ID3_tags = self.input_metadata_key_to_id3_tag_map[
            self.input_metadata_key
        ]
        tags = []
        if not isinstance(mapped_ID3_tags, list):
            mapped_ID3_tags = [mapped_ID3_tags]
        for tag in mapped_ID3_tags:
            filled_tag = tag(encoding=3, text=value)
            self.filething[filled_tag.__class__.__name__] = filled_tag


"""test_plotwindow_model.py - tests the plotwindow_model module

Chris R. Coughlin (TRI/Austin, Inc.)
"""

__author__ = 'Chris R. Coughlin'

from controllers import pathfinder
import models.plotwindow_model as model
import models.mainmodel as mainmodel
import models.abstractplugin as abstractplugin
import models.ultrasonicgate as ultrasonicgate
import numpy as np
from matplotlib import cm
import matplotlib.colors
import scipy.signal
import json
import os
import os.path
import random
import unittest

class TestBasicPlotWindowModel(unittest.TestCase):
    """Tests the BasicPlotWindowModel class"""

    def setUp(self):
        self.mock_controller = ""
        self.mock_data_file = ""
        self.basic_model = model.BasicPlotWindowModel(self.mock_controller,
                                                      self.mock_data_file)

    def random_data(self):
        """Returns a list of random data"""
        return [random.uniform(-100, 100) for i in range(25)]

    def test_revert_data(self):
        """Verify data is reverted to original"""
        original_data = np.array(self.random_data())
        self.assertIsNone(self.basic_model.original_data)
        self.assertIsNone(self.basic_model.data)
        self.basic_model.original_data = original_data
        self.basic_model.data = np.array(self.random_data())
        self.basic_model.revert_data()
        self.assertTrue(np.array_equal(self.basic_model.original_data, original_data))
        self.assertTrue(np.array_equal(self.basic_model.original_data,
                             self.basic_model.data))

    def test_get_plugins(self):
        """Verify a list of available plugins is returned"""
        expected_plugin_list = mainmodel.load_plugins()
        expected_plugin_names = [plugin[0] for plugin in expected_plugin_list]
        retrieved_plugin_list = self.basic_model.get_plugins()
        self.assertEqual(len(expected_plugin_list), len(retrieved_plugin_list))
        for plugin in retrieved_plugin_list:
            plugin_name = plugin[0]
            plugin_instance = plugin[1]
            self.assertTrue(plugin_name in expected_plugin_names)
            self.assertTrue(issubclass(plugin_instance, abstractplugin.AbstractPlugin))

    def test_get_plugin(self):
        """Verify a class name and an instance of a plugin is returned"""
        retrieved_plugin_list = self.basic_model.get_plugins()
        for plugin in retrieved_plugin_list:
            plugin_name = plugin[0]
            plugin_instance = plugin[1]
            plg_cls = self.basic_model.get_plugin(plugin_name)
            self.assertEqual(type(plugin_instance), type(plg_cls))

class TestPlotWindowModel(unittest.TestCase):
    """Tests the PlotWindowModel class"""

    def setUp(self):
        self.mock_controller = ""
        self.mock_data_file = ""
        self.model = model.PlotWindowModel(self.mock_controller, self.mock_data_file)

    def random_data(self):
        """Returns a list of random data"""
        return [random.uniform(-100, 100) for i in range(25)]

    def test_load_user_gate_functions(self):
        """Verify load_user_gate_functions returns the user's custom gate functions"""
        expected_gates = mainmodel.load_dynamic_modules(pathfinder.gates_path(), ultrasonicgate.UltrasonicGate)
        retrieved_gates = self.model.load_user_gate_functions()
        self.assertEqual(len(expected_gates), len(retrieved_gates))
        for idx in range(len(expected_gates)):
            self.assertEqual(expected_gates[idx][0], retrieved_gates[idx][0])
            self.assertTrue(issubclass(retrieved_gates[idx][1], ultrasonicgate.UltrasonicGate))

    def test_apply_window(self):
        """Verify apply_window function applies a given gate function and returns an ndarray"""
        #original_data = np.ones(55)
        original_data = np.array(self.random_data())
        for gate in self.model.gates:
            gate_name = gate[0]
            windowed_data = self.model.apply_window(gate_name, original_data, 3, 21)
            self.assertTrue(isinstance(windowed_data, np.ndarray))
            self.assertEqual(original_data.size, windowed_data.size)

    def test_apply_gate(self):
        """Verify apply_gate function"""
        original_data = np.array(self.random_data())
        self.model.original_data = original_data
        for gate in self.model.gates:
            gate_name = gate[0]
            self.model.revert_data()
            start_idx = 2
            end_idx = 4
            winder_cls = model.TwoDManipMixin()
            winder_cls._define_gate_functions()
            expected_data = winder_cls.apply_window(gate_name, self.model.data,
                                                    start_idx, end_idx)
            self.model.apply_gate(gate_name, start_idx, end_idx)
            self.assertTrue(np.array_equal(original_data, self.model.original_data))
            self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_rectify_full(self):
        """Verify full rectification of data"""
        original_data = np.array(self.random_data())
        self.model.original_data = original_data
        self.model.revert_data()
        self.model.rectify_full()
        self.assertTrue(np.array_equal(np.absolute(original_data), self.model.data))

class TestImgPlotWindowModel(unittest.TestCase):
    """Tests the ImgPlotWindowModel class"""

    def setUp(self):
        self.mock_controller = ""
        self.mock_data_file = ""
        self.mock_read_parameters = {}
        self.model = model.ImgPlotWindowModel(self.mock_controller, self.mock_data_file)

    def random_data(self):
        """Generates a random list of data"""
        return np.array([random.uniform(-100, 100) for i in range(25)])

    def random3D_data(self):
        """Generates a random 3D array of data"""
        raw_array = np.array([random.uniform(-100, 100) for i in range(24)])
        three_d_array = raw_array.reshape((3, 2, 4))
        return three_d_array

    def test_average_detrend(self):
        """Verify mean detrending along an axis"""
        self.model.original_data = self.random_data()
        self.model.revert_data()
        expected_data = scipy.signal.detrend(self.model.original_data, type='constant')
        self.model.detrend_data(0, 'constant')
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_linear_detrend(self):
        """Verify linear detrending along an axis"""
        self.model.original_data = self.random_data()
        self.model.revert_data()
        expected_data = scipy.signal.detrend(self.model.original_data, type='linear')
        self.model.detrend_data(0, 'linear')
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_slice_data(self):
        """Verify a 3D array is replaced by a 2D slice"""
        three_d_array = self.random3D_data()
        self.model.original_data = three_d_array
        self.model.revert_data()
        slice_idx = random.choice(range(three_d_array.shape[2]))
        expected_data = three_d_array[:, :, slice_idx]
        self.model.slice_data(slice_idx)
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_flipud_data(self):
        """Verify data are flipped vertically"""
        self.model.original_data = self.random_data()
        self.model.revert_data()
        expected_data = np.flipud(self.model.data)
        self.model.flipud_data()
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_fliplr_data(self):
        """Verify data are flipped horizontally"""
        three_d_array = self.random3D_data()
        self.model.original_data = np.array(three_d_array)
        self.model.revert_data()
        expected_data = np.fliplr(self.model.data)
        self.model.fliplr_data()
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_rotate_data(self):
        """Verify data are rotated counter-clockwise"""
        self.model.original_data = self.random3D_data()
        self.model.revert_data()
        num_rotations = random.choice((1, 2, 3))
        expected_data = np.rot90(self.model.data, k=num_rotations)
        self.model.rotate_data(num_rotations)
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_transpose_data(self):
        """Verify data are transposed"""
        self.model.original_data = self.random3D_data()
        self.model.revert_data()
        expected_data = self.model.data.T
        self.model.transpose_data()
        self.assertTrue(np.array_equal(expected_data, self.model.data))

    def test_get_colormaps(self):
        """Verify returning a list of colormaps"""
        cmap_choices = [m for m in cm.datad]
        cmap_choices.extend(self.model.get_user_colormaps())
        cmap_choices.sort()
        self.assertListEqual(cmap_choices, self.model.get_colormap_choices())

    def test_get_system_colormaps(self):
        """Verify returning a list of predefined colormaps"""
        cmap_choices = [m for m in cm.datad]
        self.assertListEqual(cmap_choices, self.model.get_system_colormaps())

    def test_get_user_colormaps(self):
        """Verify returning a list of user-defined colormaps"""
        colormap_folder = os.path.join(pathfinder.app_path(), 'colormaps')
        expected_colormaps = []
        for root, dirs, files in os.walk(colormap_folder):
            for fname in files:
                with open(os.path.join(root, fname), "r") as fidin:
                    cmap_dict = json.load(fidin)
                    expected_colormaps.append(cmap_dict.get('name', fname))
        self.assertListEqual(expected_colormaps, self.model.get_user_colormaps(colormap_folder))

    def test_save_colormap(self):
        """Verify saving a colormap"""
        shipped_colormaps_folder = os.path.join(pathfinder.app_path(), 'colormaps')
        shipped_colormaps = os.listdir(shipped_colormaps_folder)
        for shipped_colormap in shipped_colormaps:
            shipped_colormap_file = os.path.join(shipped_colormaps_folder, shipped_colormap)
            with open(shipped_colormap_file, "r") as fidin:
                cmap_dict = json.load(fidin)
                self.model.save_colormap(cmap_dict)
                cmap_file = os.path.join(pathfinder.colormaps_path(), cmap_dict['name'])
                self.assertTrue(os.path.exists(cmap_file))

    def test_get_cmap(self):
        """Verify returning a valid matplotlib Colormap (predefined or user-created)"""
        colormap_folder = os.path.join(pathfinder.app_path(), 'colormaps')
        colormaps = self.model.get_system_colormaps()
        colormaps.extend(self.model.get_user_colormaps(colormap_folder))
        for cmap_name in colormaps:
            cmap = self.model.get_cmap(cmap_name, colormap_folder)
            self.assertTrue(isinstance(cmap, matplotlib.colors.Colormap))

    def test_load_colormap(self):
        """Verify load_colormap returns a valid matplotlib Colormap"""
        colormap_folder = os.path.join(pathfinder.app_path(), 'colormaps')
        colormaps = self.model.get_user_colormaps(colormap_folder)
        for cmap_name in colormaps:
            cmap_file = os.path.join(colormap_folder, cmap_name)
            cmap = self.model.load_colormap(cmap_file)
            self.assertTrue(isinstance(cmap, matplotlib.colors.Colormap))

if __name__ == "__main__":
    random.seed()
    unittest.main()


#!/usr/bin/python

#from __future__ import print_function
# argv argument
import sys
# REGEX
import re
# prace se soubory
import os.path
#xml data
import xml.etree.ElementTree as ET

class Frame:
     def __init__(self, frame ):
         self.table = []
         self.frame = frame
         self.inicialized = 1

class Interpret:

    def __init__(self, structure ):
       self.glob_frame = Frame ('global' ) ;
       self.local_frame = Frame ('local' ) ;
       self.tmp_frame = Frame ('temporary' ) ;

       # inicializujeme globalni ramec, dame sem empty array
       self.glob_frame.table = ([[]])

       self.expectedLabel = []
       self.labels = []
       self.dataStack = []
       self.callStack = []; # zasobnik volani
       self.structure = structure
       # zacneme u instrukce 1
       self.processedInstruction = 1

       # abychom vedeli jake volat funkce k jednotlivym instrkcim
       self.callInstruction = {
            "ADD" : "getAdd", "SUB" : "getSub" , "MUL" : "getMul", "IDIV" : "getIdiv",
            "LT" : "getLT" , "GT" : "getGT" , "EQ" :"getEQ", "AND" :"getAnd",
            "OR" : "getOr", "STRI2INT" : "getStri2int", "GETCHAR" : "getGetchar" , "SETCHAR" : "getSetchar","CONCAT" : "getConcat",
            "JUMPIFEQ": "getJumpIfEq", "JUMPIFNEQ" : "getJumpIfNeq",
            "INT2CHAR" : "getInt2char", "STRLEN" : "getStrlen", "TYPE" : "getTypeI", "MOVE" : "getMove" ,"NOT" : "getNot",
            "READ" :"getRead" ,
            "DEFVAR" : "getDefvar" , "POPS" : "getPops",
            "PUSHS" : "getPushs", "WRITE" : "getWrite", "DPRINT" : "getDprint",
            "CALL" : "getCall", "LABEL" :"getLabel", "JUMP" : "getJump" ,
            "BREAK" : "getBreak", "CREATEFRAME" : "getCreateFrame" , "PUSHFRAME" : "getPushFrame", "POPFRAME" : "getPopFrame",
            "RETURN" : "getReturn"
        }

    def getTableAccorrdingToFrame( self, frame ):
        # je neco na vrcholu zasobniku
        if ( frame == 'GF' ):
             table_name = 'glob_frame';
        if ( frame == 'TF' ):
            table_name = 'tmp_frame';
        elif( frame == 'LF' ):
            table_name = 'local_frame';

        frame_obj = getattr(self, table_name )
        if ( len( frame_obj.table ) != 0):
            return frame_obj.table[len( frame_obj.table ) - 1]
        else:
            print ( "Snazime se deklarovat lokalni promennou bez definovani ramce" , file=sys.stderr )
            exit ( 55 ) # ramec neexistuje

    # pridame item do tabulky podle framu
    def addNewItem( self, name, frame ):
        # mohu vlozit pouze pokud na vrcholu zasobniku je nejake pole, do ktereho muzu vlozit
        table = self.getTableAccorrdingToFrame(frame)
        table.append( { 'name' : name, 'inicialized' : 0 } )

    # hledam item podle jmena a framu
    def searchItem( self, name, frame ):
        table = self.getTableAccorrdingToFrame(frame)

        for hash_item in table:
            if hash_item[ 'name' ] == name:
                return hash_item
        # pokud nic nenajdeme
        return 0

    # najdu v tabulce, inicliazuju
    # pro bool si to ukladame v pythonovkych makrech True a False
    def initItem( self, name, value, typevar, frame ):
        table = self.getTableAccorrdingToFrame(frame);
        for hash_item in table:
            if name in hash_item[ 'name' ] == name:
                hash_item[ 'inicialized' ] = 1
                if typevar == 'bool':
                    if ( value == 'true' or value == True ):
                        value = True
                    else:
                        value = False
                elif( typevar == 'int' ):
                     value = int(value)

                hash_item[ 'value' ] = value
                hash_item[ 'type' ] = typevar
                return hash_item # jak najdeme, muzeme skoncit
        return None

    def initItemElseExit( self, name, value, typevar, frame ):
        table = self.getTableAccorrdingToFrame(frame)
        for hash_item in table:
            if name in hash_item[ 'name' ] == name:
                hash_item[ 'inicialized' ] = 1
                if typevar == 'bool':
                    if ( value == 'true' or value == True ):
                        value = True
                    else:
                        value = False
                hash_item[ 'value' ] = value
                hash_item[ 'type' ] = typevar
                #print (table);
                return hash_item # jak najdeme, muzeme skoncit

        #nenasli jsme, neni v tabulce
        print ( "Nedefinovana promenna %s" % name, file=sys.stderr )
        exit ( 54) #semanticka kontrola

    # zjistim, jestli uz je inicilaizovana
    def isInit( self, name, frame ):
        item = self.searchItem(name, frame)
        if item:
            return item[ 'inicialized' ]
        else:
            return 0

    # funkce vraci typ promenne
    def getTypeVar(self, name, frame):
        item = self.searchItem(name, frame)
        # vracim hodnotu pouze pokud je inicializovana
        if item and item[ 'inicialized' ]:
            return item[ 'type' ]
        else:
            return None

     # funkce vraci hodnotu promenne pokud je inicializovana
    def getValueVar(self, name, frame):
        item = self.searchItem(name, frame)
        # vracim hodnotu pouze pokud je inicializovana
        if item and item[ 'inicialized' ]:
            # pokud se jedna o typ bool => vracim 1/0
            #if item[ 'type' ] == 'bool':
             #   return True if item[ 'value' ] == 'true' else False
            #else:
            return item[ 'value' ]
        else:
            return None

    # funkce vraci hodnotu symbolu => kontanta/promenna
    def getVal(self, symb):

        if ( symb[ 'type' ] == 'var' ):
            # u promenne hledame v tabulce
            return self.getValueVar( symb[ 'name' ], symb[ 'frame' ] )
        else:
            # u retezce primo vypiseme
            return symb[ 'text' ]

    # funkce vraci typ symbolu => kontanta/promenna
    def getType(self, symb):
        if ( symb[ 'type' ] == 'var' ):
            # hledame v tabulce jaky ma typ
            return self.getTypeVar( symb[ 'name' ], symb[ 'frame' ] )
        else:
            return symb[ 'type' ]

    # tisknu tabulku podle framu
    def printStructure(self, frame):
        table = self.getTableAccorrdingToFrame(frame)
        print (table)

     # nazev promenne v argumentech metody
     # kontrola, ze promenna je  inicializovana a musi mit ocekavany typ jinak chyba
    def _checkVarIfInitIfType(self, var_name, expected_type, frame):
        if ( self.isInit( var_name, frame ) ):
                if ( self.getTypeVar( var_name, frame ) != expected_type ):
                     print ( "Ocekavam typ %s u promenne %s" % ( expected_type, var_name), file=sys.stderr )
                     exit ( 53) #semanticka kontrola
        else:
            # zjistim, jestli vubecexistuje a podle toho vyhodim hlasku
            if self.searchItem(var_name, frame):
                print ( "Cteni neinicializovane promenne %s" % ( var_name), file=sys.stderr )
                exit ( 56) #semanticka kontrola
            else:
                print ( "Cteni nedefinovane promenne %s" % ( var_name), file=sys.stderr )
                exit ( 54) #semanticka kontrola

    # vraci hodnotu promenne, ktera musi existovat, jinak chyba
    # vraci promennou v pripade uspechu
    def _checkVarIfInit(self, var_name, frame):
        if self.isInit( var_name, frame ):
            return self.searchItem( var_name, frame )
        else:
            # zjistim, jestli vubecexistuje a podle toho vyhodim hlasku
            if self.searchItem(var_name, frame):
                print ( "Cteni neinicializovane promenne %s" % ( var_name), file=sys.stderr )
                exit ( 56) #semanticka kontrola
            else:
                print ( "Cteni nedefinovane promenne %s" % ( var_name), file=sys.stderr )
                exit ( 54) #semanticka kontrola

    # vrati nam poradi navesti, nazev navesti je unikatni
    def _orderOfLabel(self, label_name ):
        for lab in self.labels:
            if lab[ 'text' ] == label_name:
                return lab[ 'order' ]
        # pokud nic nenajdeme
        return 0

    def _orderOfLabelElseExit(self, label_name ):
        for lab in self.labels:
            if lab[ 'text' ] == label_name:
                return lab[ 'order' ]
        # pokud nic nenajdeme
        print ( "Neexistujici navesti %s" % label_name, file=sys.stderr )
        exit ( 52)

    #############
    # INSTRUKCE #
    #############
    # kontrola, ze label existuje, musim to kontrolovat az bude konec prochazeni, ulozim si proto ocekavane labely
    def getJump(self, label):
        orderLabel = self._orderOfLabelElseExit( label[ 'text' ] );
        self.processedInstruction = orderLabel;

    #pokud o redefinici navesti => 52
    def getLabel( self, label ):
        if ( self._orderOfLabel( label[ 'text' ] ) ):
            print ( "Pokud o redefinici navesti %s" % label[ 'text' ], file=sys.stderr )
            exit ( 52)
        self.labels.append( { "text" : label[ 'text' ], "order" : self.processedInstruction } );

    # 1. pokud ctu promennou, musi existovat
    # 2. pokud zapisuji do promenne, muzu menit jeji typ
    # 3. pristupy k ramcum, pristup k nedefinovanemu ramci vede na chybu 55 => resi interpret
    def getMove(self, var, symb):
        # var musi existovat
        searchvar = self.searchItem(  var[ 'name' ], var[ 'frame' ] )
        # nedefinovana
        if ( searchvar == 0):
            print ( "Zapis nedefinovane promenne %s pomoci instrukce MOVE" % ( var[ 'name' ]), file=sys.stderr )
            exit ( 54) #semanticka kontrola

        if ( symb[ 'type' ] == 'var' ):
            variable = self._checkVarIfInit( symb[ 'name' ], symb[ 'frame' ] )

            # zjistim si typ a hodnoty z tabulky promennych

            typ = variable[ 'type' ]
            val = variable[ 'value' ]
        else:
            typ = symb[ 'type' ]
            val = symb[ 'text' ]

        # definovana je, ulozim si informace

        self.initItemElseExit( var[ 'name' ], val, typ, var[ 'frame' ])

    # pokud vytvorim ramec, mohu pouzivat TF temporary
    def getCreateFrame(self):
        self.tmp_frame.table = ([[]])

    # uz nebudu moct pouzivat TF, ale muzu pouzivat LF
    def getPushFrame(self):
        if ( len( self.tmp_frame.table ) ):
            self.local_frame.table.append( self.tmp_frame.table[len( self.tmp_frame.table ) - 1]  )
            # TF bude pro provedeni nedefinovan
            self.tmp_frame.table.pop()

        else:
            print ( "Pristup k nedefinovanym ramci", file=sys.stderr )
            exit ( 55 ) # semanticka kontrola

    # presun LF do TF, pokud nic v LF => 55 chyba
    def getPopFrame(self):
        if ( len( self.local_frame.table ) ):
            #self.tmp_frame.table = [ self.local_frame.table[len( self.local_frame.table ) - 1] ]
            self.tmp_frame.table = [ self.local_frame.table.pop() ]
        else:
            print ( "Pristup k nedefinovanym ramci", file=sys.stderr )
            exit ( 55 ) # semanticka kontrola

    # definuje promennou
    # 1. pozor, kdy muzu definovat LF a TF, kontrola
    def getDefvar(self, arg):
        self.addNewItem( arg[ 'name' ], arg[ 'frame' ] )

    # kontrola na existenci label, musim si pockat na konci
    def getCall(self, label):
        order = self._orderOfLabelElseExit( label[ 'text' ] )
        # ulozim si navratovou adresu
        self.callStack.append( self.processedInstruction );
        self.processedInstruction = order;

    # vyjmu pozici ze zasobniku volani
    # uklid lokalnich ramcu zajistuji jine instrukce
    def getReturn(self):
        if ( len ( self.callStack ) ):
            order = self.callStack.pop();
            self.processedInstruction = order;
        else:
            print ( "Chybejici hodnota v zasobniku volani" , file=sys.stderr )
            exit ( 56) # chybejici hodnota

    # pokud prom => musi byt definiovana a inicializovana
    # staci mi si ukladat typ a hodnotu
    def getPushs(self,symb):
        value = self.getVal( symb )
        typevar = self.getType( symb )
        if ( value is not None ):
             self.dataStack.append( { 'type' : typevar, 'value' :  value } );
        else:
            print ( "Promenna %s, kterou chceme vlozit na zasobnik, neni inicializovana" % ( symb[ 'text' ] ), file=sys.stderr )
            exit ( 56) # chybejici hodnota

    # je zasobnik prazdny ? -> 56
    def getPops(self, var):
        if ( len( self.dataStack ) == 0 ):
            print ( "Datovy zasobnik je prazdny", file=sys.stderr )
            exit ( 56)

        value = self.dataStack.pop();
        # zmenim typ a jmeno o promenne var na typ a hodnotu z value
        # do var dam value
        self.initItemElseExit( var[ 'name' ], value[ 'value' ], value[ 'type' ], var[ 'frame' ] )

     # funkce na konvertovani spravneho typu
    def _getConvertVal(self, symb):
        # musim porovnavat spravne typy
        val = self.getVal(symb)
        typ = self.getType(symb)
        return self._getConvertConst( val, typ )

     # funkce na konvertovani spravneho typu
    def _getConvertConst(self, val, typ):
        # musim porovnavat spravne typy
        if (typ == 'int'):
            return int(val)
        if (typ == 'string'):
            return str(val)
        if typ == 'bool':
            if ( val == 'true' or val == True ):
               return( True )
            else:
               return ( False )

    # 1.source musi byt typu expected_type
    def _controlType(self, source, expected_type):
        # pokud se jedna o promennou, musim zjistit, jestli existuje a je inicializovana a pokud ano zkontrolovat jeji typ
        if ( source[ 'type' ] == 'var' ):
            self._checkVarIfInitIfType( source[ 'name' ], expected_type, source[ 'frame' ] )

        elif ( source[ 'type' ] != expected_type ):
            print ( "Ocekavam typ %s" % expected_type, file=sys.stderr )
            exit ( 53) #semanticka kontrola

    # 1.source1 a source2 musi byt typu expected_type
    def _controlTypeTwoValues(self, source1, source2, expected_type):
        # pokud se jedna o promennou, musim zjistit, jestli existuje a je inicializovana a pokud ano zkontrolovat jeji typ
        self._controlType( source1, expected_type )
        self._controlType( source2, expected_type )

    # dostaneme vysledek operace
    def _operation( self, source1, source2, operation, typ ):

        val1 = self._getConvertVal( source1 )
        val2 = self._getConvertVal( source2 )

        if ( operation == 'plus' ):
            return int(val1) + int(val2)
        elif( operation == 'minus'  ):
            return int(val1) - int(val2)
        elif( operation == 'mul'  ):
            return int(val1) * int(val2)
        elif( operation == 'idiv'  ):
            #konstrola nuly
            if int(val2) != 0:
                return int ( int(val1) / int(val2) )
            else:
                print ( "POZOR, snazite se delit nulou" , file=sys.stderr )
                exit ( 57) # deleni nulou

        elif( operation == 'lt' ):
            return ( val1 < val2 )
        elif( operation == 'gt' ):
            return ( val1 > val2 )
        elif( operation == 'eq' ):
            return ( val1 == val2)

        elif( operation == 'and' ):
            return (val1 and val2)
        elif( operation == 'or' ):
            return (val1 or val2)
        elif( operation == 'not' ):
            return (not val1 )

    def _getArithmetic( self, desc, source1, source2, expected_type, expected_result, operation  ):
        self._controlTypeTwoValues(source1, source2, expected_type )
        vysl = self._operation( source1, source2, operation, expected_type  )
        self.initItemElseExit( desc[ 'name' ], vysl, expected_result, desc[ 'frame' ] )

    # 2. vysledek do desc a kdyztak to prepisu
    def getAdd(self, desc, source1, source2):
       self._getArithmetic( desc, source1, source2, 'int', 'int', 'plus' )

    def getSub(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, 'int', 'int','minus' )

    def getMul(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, 'int', 'int','mul' )

    # pozor na deleni nulou => 57
    def getIdiv(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, 'int', 'int','idiv' )

    # vraci typ a kontroluje zda jsou typy stejne
    def _sameType(self, source1, source2):
        if ( source1[ 'type' ] == 'var' ):
            type1 = self.getTypeVar( source1[ 'name' ], source1[ 'frame' ] )
        else:
            type1 = source1[ 'type' ]

        if ( source2[ 'type' ] == 'var' ):
            type2 = self.getTypeVar( source2[ 'name' ], source2[ 'frame' ] )
        else:
            type2 = source2[ 'type' ]

        #print("Source1: " + type1 + "Source2: "+ type2)
        #print(source1)
        #print(source2)
        if ( type1 == type2  ):
            return type1
        else:
            print ( "U instrukci pracujeme s odlisnymi typy, typ1 %s != typ2 %s" % ( type1, type2 ), file=sys.stderr )
            exit ( 53 ) # jine typy

    # 1. ukladam stejny typ
    # do bool prom var zapise false pri neplatnosti nebo true v pripade platnosti relace
    # false < true
    # muzeme pouzit AND,OR< NOT
    def getLT(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, self.getType(source1 ), 'bool', 'lt' )

    def getGT(self, desc, source1, source2):
        #print(desc)
        #print(source1)
        #print(source2)
        self._getArithmetic( desc, source1, source2, self.getType(source1), 'bool', 'gt' )

    def getEQ(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, self.getType(source1), 'bool', 'eq' )

    # kontrola zda se jedna o bool
    def getAnd(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, 'bool','bool', 'and' )

    def getOr(self, desc, source1, source2):
        self._getArithmetic( desc, source1, source2, 'bool', 'bool','or' )

    def getNot(self, desc, source1 ):
        self._getArithmetic( desc, source1, source1, 'bool', 'bool','not' )

    # var - kdyztak prepisu
    # symb - typ int, musi byt validni ordinalni hodnota znaku v unicode (viz chr) => 58
    def getInt2char(self, var, symb):
        self._controlType( symb, 'int' )
        val = int ( self.getVal( symb ) );
        if ( val is not None ):
            try:
                ordinal_val = chr( val )
            except ValueError:
                print ( "Pokus o prevedeni nevalidni ordinalni hodnoty %s na unicode znak" % ( val ), file=sys.stderr )
                exit ( 58 )

            # povedlo se, prepisu hodnotu a typ promenne
            # musim ji najit napred v tabulce
            self.initItemElseExit( var[ 'name' ], ordinal_val, 'string', var[ 'frame' ] )

        else:
            print ( "Prace s neinicializovanou promennou %s" % ( symb[ 'name' ]), file=sys.stderr )
            exit ( 56 )

    # symb2 - pozice, index od 0, musi byt int
    # symb1 - typ string
    # ve var je string
    # indexace mimo => 58 viz ord, pozice nesmi byt zaporna, nesmi byt vetsi nez pocet znaku v symb1
    def getStri2int(self, var, symb1, symb2):
        self._controlType( symb1, 'string' )
        self._controlType( symb2, 'int' )

        val1 = str ( self.getVal( symb1 ) )   #string
        val2 = int( self.getVal( symb2 ) ) # int

        if ( len(val1) > val2 and val2 >= 0 ):
            try:
                ordinal_val = ord( val1[ val2 ] )
            except TypeError:
                print ( "Pokus o prevedeni nevalidni unicode hodnoty %s na Int" % ( val1[ val2 ] ), file=sys.stderr )
                exit ( 58 )
        else:
            print ( "Indexace mimo pole retezec %s, index %s" % ( val1, val2, ), file=sys.stderr )
            exit ( 58)
        # povedlo se, prepisu hodnotu a typ promenne
        # musim ji najit napred v tabulce
        # priradim ji nove hodnoty a jdu dal
        self.initItemElseExit( var[ 'name' ], ordinal_val, 'int', var[ 'frame' ] )

    # var musi existovat, nemusi byt inicializovana
    # cte typ, funkci input
    # provede se konverze na specifikovany typ, retezec true se prevadi na bool@true jinak bool@false
    # v pripade chybneho vstupu do var ulozena implicitni hodnota (0,prazdny retezec nebo false)
    def getRead(self, var, type_input):
        input_val = input()

        # musime osetrit chybny vstup
        if ( type_input[ 'text' ] == 'int' ):
            # matchuje cislo
            if ( re.match( input_val, '^((\+|-)?\d+|)$'  ) == 0 ):
                input_val = 0
        if ( type_input[ 'text' ] == 'string' ):
            # retezec
            if ( re.match(  input_val, '^(([^\\\\\s#]|(\\\\[0-9]{3}))*)$' ) == 0 ):
                input_val = ""

        # bool se prevede vzdy dobre
        # priradim ji nove hodnoty a jdu dal
        self.initItemElseExit( var['name'], input_val, type_input[ 'text' ], var[ 'frame' ] )

    # var musi existovat, musi byt inicializovana
    def getWrite(self, symb):
        if ( symb[ 'type' ] == 'var' ):
            self._checkVarIfInit( symb[ 'name' ], symb[ 'frame' ] )
        #print(symb)
        val = self.getVal(symb)
        typ = self.getType(symb)
        # pozor na typ bool, True se vypise jako true a False jako false
        if typ == 'bool':
               if ( val == True ):
                    val = 'true'
               elif ( val == False ):
                    val = 'false'

        print( val )

    # symb1, symb2 jsou retezce
    # ve var bude string
    def getConcat(self, desc, source1, source2):
        self._controlTypeTwoValues( source1, source2, 'string' )
        val1 = self.getVal(source1)
        val2 = self.getVal(source2)
        ret_val = val1 + val2
        variable = self.searchItem( desc[ 'name' ], desc[ 'frame' ] )
        # priradim ji nove hodnoty a jdu dal
        self.initItemElseExit( desc['name'], ret_val, 'string', desc[ 'frame' ] )

    # ve var bude int
    # symb je string
    def getStrlen(self, var, symb):
        #self._controlType( var, 'int' )
        self._controlType( symb, 'string' )
        val = self.getVal( symb )
        length = len( val )
        #print(var['name'])
        self.initItemElseExit( var[ 'name' ], length, 'int', var[ 'frame' ] )

    # symb2 - int (pozice)
    # sym1 - string
    # ve var bude string
    # indexace mimo => 58 viz ord, pozice nesmi byt zaporna, nesmi byt vetsi nez pocet znaku v symb1
    def getGetchar(self, desc, symb1, symb2):
        self._controlType( symb1, 'string' )
        self._controlType( symb2, 'int' )

        val1 = self._getConvertVal( symb1 )
        val2 = self._getConvertVal( symb2 )

        if ( len( val1 ) > val2 and val2 >= 0):
            ordinal_val = val1[ val2 ]
        else:
            print ( "Indexace mimo pole retezec %s, index %s" % ( val1, val2 ), file=sys.stderr )
            exit ( 58)

        # povedlo se, prepisu hodnotu a typ promenne
        # musim ji najit napred v tabulce
        self.initItemElseExit( desc[ 'name' ], ordinal_val, 'string', desc[ 'frame' ] )

    # symb2 - string, beru prvni znak, pokud symb2 obsahuje vice znaku
    # symb1 - int, pozice, index od nuly
    # ve var musi byt na zacatku string => modifukuju pozici symb1 znakem symb2
    # indexace mimo => 58 viz ord, pozice nesmi byt zaporna, nesmi byt vetsi nez pocet znaku v symb1
    def getSetchar(self, desc, symb1, symb2):
        self._controlType( symb1, 'int' )
        self._controlType( symb2, 'string' )
        self._controlType( desc, 'string' )

        val1 = self._getConvertVal( symb1 )
        val2 = self._getConvertVal( symb2 )
        var = self.getVal( desc )

        # bereme prvni znak
        #print("val2: " + val2)
        if ( val2 ):
            val2 = val2[0]
        else:
            print ( "Neexistuje prvni znak na pozici 2" ,file=sys.stderr )
            exit ( 58)

        if ( len( var ) > val1 and val1 >= 0):
            #var[ val1 ] = val2;
            var = var[:val1] + val2 + var[val1+1:]
        else:
            print ( "Indexace mimo pole retezec %s, index %s, hodnota %s" % ( var, val1, val2 ), file=sys.stderr )
            exit ( 58)

        # povedlo se, prepisu hodnotu a typ promenne
        # musim ji najit napred v tabulce
        self.initItemElseExit( desc[ 'name' ], var, 'string', desc[ 'frame' ] )

    # zde pouze kontrola, aby symb v pripade var byla definovana, ale nemusi byt inicializovana
    def getTypeI(self, var, symb):
        #print(symb)
        if ( symb[ 'type' ] == 'var' ):
            if ( self.searchItem( symb[ 'name' ], symb[ 'frame' ] ) == 0):
                print ( "Prace s nedefinovanou promennou %s" % ( symb[ 'name' ]), file=sys.stderr )
                exit ( 54) #54 pokus o cteni neexistujici promenne

        typ = self.getType(symb)
        if ( typ is None ):
            # neni inicializovana, jedna se o prazdny string
            typ = ''

        # zapisi retezec znacici tento typ symbolu
        self.initItemElseExit( var[ 'name' ], typ, 'string', var[ 'frame' ] )

    # pridam label do expected label, pokud neni v labels
    # symb1 a symb2 musi byt stejneho typu
    def getJumpIfEq(self, label, symb1, symb2):
        #if ( label[ 'text' ] not in self.labels ):
            #self.expectedLabel.append( label[ 'text' ] )
        self._sameType(symb1, symb2)

        val1 = self._getConvertVal(symb1)
        val2 = self._getConvertVal(symb2)

        if ( val1 == val2 ):
            self.getJump( label )

    def getJumpIfNeq(self, label, symb1, symb2):
        #if ( label[ 'text' ] not in self.labels ):
            #self.expectedLabel.append( label[ 'text' ] )
        self._sameType(symb1, symb2)
        val1 = self._getConvertVal(symb1)
        val2 = self._getConvertVal(symb2)
        if ( val1 != val2 ):
            self.getJump( label )

    # pokud promenna -musi mit init
    def getDprint(self, symb):
        if ( symb[ 'type' ] == 'var' ):
            self._checkVarIfInit( symb[ 'name' ], symb[ 'frame' ] )
        val = self.getVal(symb)
        print ( "%s" % ( val), file=sys.stderr )

    def getBreak(self):
        print ( "Number of instruction: %s" % self.processedInstruction )
        print ( "GF frame:" , file=sys.stderr )
        print ( "%s" % self.glob_frame.table , file=sys.stderr )
        print ( "LF frame:" , file=sys.stderr )
        print ( "%s" % self.local_frame.table , file=sys.stderr )
        print ( "TF frame:" , file=sys.stderr )
        print ( "%s" % self.tmp_frame.table , file=sys.stderr )

    def findAllLabels(self):
        instructionInfo = self.structure[ self.processedInstruction ]
        while ( instructionInfo[ 'instruction_name' ] != 'END' ):
            # zavolam danou funkci k dane instrukci s parametry instrukce
            if ( instructionInfo[ 'instruction_name' ] == 'LABEL' ):
                getattr(self, self.callInstruction[ instructionInfo[ 'instruction_name' ] ] )( *instructionInfo[ 'arg' ] )

            self.processedInstruction = self.processedInstruction + 1
            if ( self.processedInstruction in self.structure):
                instructionInfo = self.structure[ self.processedInstruction ]

        # musime zase na zacatek
        self.processedInstruction = 1;

    def proceed(self):
        # jedu az do az do konce
        instructionInfo = self.structure[ self.processedInstruction ]
        while ( instructionInfo[ 'instruction_name' ] != 'END' ):
            # zavolam danou funkci k dane instrukci s parametry instrukce
            if ( instructionInfo[ 'instruction_name' ] != 'LABEL' ):
                #print(instructionInfo[ 'instruction_name' ])
                #print( instructionInfo[ 'arg' ] )
                getattr(self, self.callInstruction[ instructionInfo[ 'instruction_name' ] ] )( *instructionInfo[ 'arg' ] )

            self.processedInstruction = self.processedInstruction +1

            if ( self.processedInstruction in self.structure):
                instructionInfo = self.structure[ self.processedInstruction ]

        # todo pridat linebreaky
        #print()

class SyntaxParse:

    def __init__(self,xml):
        self.xml = xml

        self.instruction_map = {
            "ADD": "A1", "SUB" : "A1", "MUL" : "A1", "IDIV" : "A1", "LT" : "A1", "GT" : "A1", "EQ" : "A1", "AND" : "A1",
            "OR" : "A1", "STRI2INT" : "A1", "GETCHAR" : "A1", "SETCHAR" : "A1","CONCAT" : "A1",

            "JUMPIFEQ" : "A2", "JUMPIFNEQ" : "A2",

            "INT2CHAR" : "B1", "STRLEN" : "B1", "TYPE" : "B1", "MOVE" : "B1","NOT" : "B1",

            "READ" : "B2",

            "DEFVAR" : "C1", "POPS" : "C1",

            "PUSHS" : "C2", "WRITE" : "C2", "DPRINT" : "C2",

            "CALL" : "C3", "LABEL" : "C3", "JUMP" : "C3",

            "BREAK" : "D", "CREATEFRAME" : "D", "PUSHFRAME" : "D", "POPFRAME" : "D", "RETURN" : "D",
        }
        type_xml = "type"
        type_reg = "(string|int|bool)"
        label_reg = "\D(\w|%|\*|&|\\$|-|)+"
        variable_reg = "^(GF|LF|TF)@("+label_reg+")$"
        int_reg = '^((\+|-)?\d+|)$'
        bool_reg = '^(false|true)$'
        string_reg = '^(([^\\\\\s#]|(\\\\[0-9]{3}))*)$'

        constant_reg = '^(([^\\\\\s#]|(\\\\[0-9]{3}))*)|(((\+|-)?\d+|))|(false|true)$'
        symbol_reg = "("+ constant_reg +"|"+ variable_reg +")"

        # a) 1. ADD, SUB, MUL, IDIV, LT, GT, EQ, AND, OR, STRI2INT, GETCHAR, SETCHAR, CONCAT (3 operandy) <var> <symm1> <symb2> ^
        #    2. JUMPIFEQ, JUMPIFNEQ, <label> <symm1> <symb2>
        #
        # b) 1. INT2CHAR, STRLEN, TYPE, MOVE, NOT <var> <symb>
        #    2. READ, <var> <type>  (2 operandy)
        #
        # c) 1. DEFVAR, POPS (1 operand) <var>
        #    2. PUSHS, WRITE, DPRINT <symb>
        #    3. CALL, LABEL, JUMP <label>
        #
        # d) BREAK, CREATEFRAME, PUSHFRAME, POPFRAME, RETURN (0 operandu)
        self.dictionaryInstruction = {
            "A1": { 'number' : 3, 'arg0' : variable_reg, 'arg1' : symbol_reg, 'arg2' : symbol_reg },
            "A2": { 'number' : 3, 'arg0' : label_reg, 'arg1' : symbol_reg, 'arg2' : symbol_reg },
            "B1": { 'number' : 2, 'arg0' : variable_reg, 'arg1' : symbol_reg },
            "B2": { 'number' : 2, 'arg0' : variable_reg, 'arg1' : type_reg },
            "C1": { 'number' : 1, 'arg0' : variable_reg },
            "C2": { 'number' : 1, 'arg0' : symbol_reg },
            "C3": { 'number' : 1, 'arg0' : label_reg },
            "D": { 'number' : 0 }  ,
        }
        self.dictionaryType = {
            "int" : int_reg,
            "string" : string_reg,
            "bool" : bool_reg,
            "label" : '^'+label_reg+'$',
            "var" : variable_reg,
            "type" : type_reg
        }

    def _checkFormatOfOneInstruction( self, instruction_name, instruction_arg ):
        if ( instruction_name in self.instruction_map ):
             type_instruction = self.instruction_map[ instruction_name ]
        else:
           print ( "Spatny nazev instrukce  %s" % instruction_name, file=sys.stderr )
           exit ( 32)

        structure = self.dictionaryInstruction[ type_instruction ]
        if ( len( instruction_arg ) == structure[ 'number' ] ):
            for arg in range( structure[ 'number' ]  ):
                index = "arg" + str(arg);
                if ( instruction_arg[ arg ][ 'text' ] is None ):
                    # aby regex nehodil chybu
                    instruction_arg[ arg ][ 'text' ] = ''
                if ( re.match(  structure[ index ], instruction_arg[ arg ][ 'text' ] ) ):
                    # kontrola regexem kazdy operand instrukce
                    # proslo, tak jeste zkontroluj typ
                    if ( instruction_arg[ arg ][ 'type' ] in self.dictionaryType ):

                        if ( re.match(  self.dictionaryType[ instruction_arg[ arg ][ 'type' ]  ], instruction_arg[ arg ][ 'text' ] ) is None):
                            print ( "Spatny typ operandu u instrukce %s, operand %s" % ( instruction_name, instruction_arg[ arg ][ 'text' ]  ), file=sys.stderr )
                            exit ( 32)
                        # tady by se hodilo prevedeni stringu na normalni string :)
                        if ( instruction_arg[ arg ][ 'type' ] == 'string' ):
                            # prevedeme
                            def replace(m): return chr(int(m.group(1)))
                            instruction_arg[ arg ][ 'text' ] = re.sub( '\\\\([0-9]{3})', replace, instruction_arg[ arg ][ 'text' ]  )

                    else:
                        print ( "Neznamy typ u instrukce %s, typ %s" % ( instruction_name, instruction_arg[ arg ][ 'type' ]  ), file=sys.stderr )
                        exit ( 32)

                else:
                    print ( "Spatny format operandu u instrukce %s, operand %s" % ( instruction_name, instruction_arg[ arg ][ 'text' ]  ), file=sys.stderr )
                    #print >> sys.stderr, "Spatny format operandu u instrukce "
                    exit ( 32)
        else:
            print ( "Spatny pocet operandu u instrukce %s" % instruction_name, file=sys.stderr )
            exit ( 32)

        return True

    # funkce zkontroluje syntax a v pripade uspechu vraci strukturu xml v poli slovniku, ktera vypada asi takto:
    # {1: {'arg': [{'type': 'label', 'text': 'MAIN'}], 'instruction_name': 'JUMP'},
    # 2: {'arg': [{'type': 'label', 'text': 'FOO'}], 'instruction_name': 'LABEL'},
    # 3: {'arg': [], 'instruction_name': 'END'} }
    def checkParseSyntax(self):
        try:
            tree = ET.parse( self.xml)
            root = tree.getroot()
        except:
            print ( "Chybna struktura xml" , file=sys.stderr )
            exit ( 31)

        sums = 0
        instruction_arg = []
        instruction = {}
        for child in root:
            #print(child.tag, child.attrib)
            if ( 'opcode' in child.attrib and 'order' in child.attrib ):
                instruction_name = child.attrib[ 'opcode' ]
                instruction_order = int (child.attrib[ 'order' ])
            else:
                print ( "Chybi argument opcode nebo order u instrukce %s" % instruction_name, file=sys.stderr )
                exit ( 31)
            for child2 in child:
                # ulozim struktutu a zkontroluju syntax
                sums = sums +1
                if ('type' in child2.attrib ):
                    # pokud se jedna o promennou, chceme si navic ukladat zvlast promennou a zvlast ramec
                    if ( child2.attrib[ 'type' ] == 'var' ):
                         var = re.match(  '^(GF|LF|TF)@(.*)$', child2.text)
                         if (var is not None):
                             instruction_arg.append( { 'type' : child2.attrib[ 'type' ], 'text' : child2.text, 'name' : var.group(2), 'frame' : var.group(1) } )
                    else:
                        # nejedna se o promennnou, ale kontantu
                        instruction_arg.append( { 'type' : child2.attrib[ 'type' ], 'text' : child2.text } )
                else:
                     print ( "Chybi argument type u instrukce %s" % instruction_name, file=sys.stderr )
                     exit ( 31)
            # ulozime do struktury, kterou budeme vracet
            instruction[ instruction_order ] = { 'instruction_name' : instruction_name, 'arg' : instruction_arg }
            if ( self._checkFormatOfOneInstruction( instruction_name, instruction_arg ) == False ):
                 print ( "Syntakticka chyba u instrukce %s" % instruction_name, file=sys.stderr )
                 exit ( 32)
            instruction_arg = []

        # konec zpracovani oznacime retezcem END, zarazka
        instruction[ instruction_order+1 ] = { 'instruction_name' : 'END', 'arg' : [] }
        return instruction

class Main:
    def __init__(self):
        ########################
        # ZPRACOVANI ARGUMENTU #
        ########################

        if (len( sys.argv ) != 2 ):
            # ocekavame vzdy jeden argument
            print >> sys.stderr, "Spatny pocet argumentu, ocekavam jeden"
            exit( 10 )

        if (sys.argv[ 1 ] == '--help') :
            print( "POUZITI:\npython3 interpret.py --source=zdroj_xml\n" )
            exit(0)
        #print (sys.argv[1])
        split = re.match(  r"(--source=)(.+)", sys.argv[1] )
        #print( "source: %s" % sys.argv[1] );
        if (split is None):
            print ( "Pouzijte argument --help pro vypsani napovedy" , file=sys.stderr )
            #print >> sys.stderr, "Pouzijte argument --help pro vypsani napovedy"
            exit( 10 )

        syntax = SyntaxParse( split.group(2) )
        structTree = syntax.checkParseSyntax()
        #print (structTree)
        # mame strukturu, musime provest semantickou kontrolu
        interpret = Interpret( structTree )
        interpret.findAllLabels();
        interpret.proceed()

main = Main()

exit(0)


from functional import *
from interface import start
import os
os.system('cls')

def clear_console():
    os.system('cls')

path = "phone_book.txt"

start()
actions = {"1": "вывод контактов", "2": "добавление контакта", "3": "поиск", "4": "редактирование", "5": "удаление", "q": "назад"}
action = None

while action != "q":
    print( *[f"{i} - {actions[i]}" for i in actions])
    print()
    action = input("выберите действие? ")
    clear_console()
    if action != "q":
        if action == "1":
            print('\n'*2)
            print("               Cписок контактов : ")
            print('            ======================')
            print_records(path)
        elif action == "2":
            input_records(path)
        elif action == "3":
            find_records(path, *find_char())
        elif action == "4":
            change_records(path)
        elif action == "5":
            delete_records(path)
        else:
            print('Данный параметр неиспользуется')
        print()


import json
import urllib.request as ur
import urllib.parse as up

serviceurl = 'http://py4e-data.dr-chuck.net/json?'
api_key = 42

while True:
    address = input('Enter location: ')
    if len(address) < 1: break

    param = dict()
    param['sensor'] = 'false'
    param['address'] = address
    param['key'] = api_key
    url = serviceurl + up.urlencode(param)

    print ('Retrieving ',url)
    url_handle = ur.urlopen(url)
    data = url_handle.read()

    print ('Retrieved',len(data),'characters')

    try:
        js = json.loads(data)
    except:
        js = None

    if not js or 'status' not in js or js['status'] != 'OK':
        print('==== Failure To Retrieve ====')
        print(data)
        continue

    #print(json.dumps(js, indent=4))

    #lat = js['results'][0]['geometry']['location']['lat']
    #lng = js['results'][0]['geometry']['location']['lng']
    #print('lat', lat, 'lng', lng)

    #location = js['results'][0]['formatted_address']
    #print(location)

    print ('Place id',js['results'][0]['place_id'])

#Sample output
#Enter location: UIUC
#Retrieving  http://py4e-data.dr-chuck.net/json?sensor=false&address=UIUC&key=42
#Retrieved 1654 characters
#Place id ChIJ6VUmqSTXDIgR-iZoBCUFPKU
#Enter location:


from flask import Flask, render_template
import requests

app = Flask(__name__)

flake_blogs_api_endpoint = "https://api.npoint.io/c790b4d5cab58020d391"

all_blogs = requests.get(flake_blogs_api_endpoint).json()

@app.route('/')
def home():
    return render_template("index.html", all_blogs=all_blogs)

@app.route("/blog/<int:index>")
def get_blog(index):
    for blog in all_blogs:
        if blog['id'] == index:
            title = blog["title"]
            subtitle = blog["subtitle"]
            body = blog["body"]
    return render_template("post.html", title=title, subtitle=subtitle, body=body)

if __name__ == "__main__":
    app.run(debug=True)

3 -  Blog capstone part 1 with flask/main.py


import sys
from io import StringIO
import unittest

class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)

    def test_Sample_Input_1(self):
        input = """5
2 2
3 1
1 3
4 2
5 3"""
        output = """12"""
        self.assertIO(input, output)

    def test_Sample_Input_2(self):
        input = """9
5 5
-4 4
4 3
6 3
-5 5
-3 2
2 2
3 3
1 4"""
        output = """38"""
        self.assertIO(input, output)

def resolve():
  inf = 10**18+1
  # 各色の min max を管理する
  from collections import defaultdict
  N = int(input())
  # BALLES = [list(map(int, input().split(" "))) for _ in range(N)]

  min_ = [inf]*(N+2)
  max_ = [-inf]*(N+2)
  C = set()
  min_[0] = min_[N+1] = max_[0] = max_[N+1] = 0
  C.add(0)
  C.add(N+1)
  for n in range(N):
    x, c = map(int, input().split(" "))
    min_[c] = min(min_[c], x)
    max_[c] = max(max_[c], x)
    C.add(c)
  C = sorted(list(C))

  last_min = last_max = 0
  min_ans = max_ans = 0
  for i in range(1, len(C)):
    min_ans, max_ans = min(min_ans + abs(min_[C[i-1]] - max_[C[i]]), max_ans + abs(max_[C[i-1]] - max_[C[i]])) + max_[C[i]]-min_[C[i]], min(min_ans + abs(min_[C[i-1]] - min_[C[i]]), max_ans + abs(max_[C[i-1]] - min_[C[i]])) + max_[C[i]]-min_[C[i]]
  print(min(min_ans, max_ans))

resolve()

if __name__ == "__main__":
    unittest.main()


from selenium import webdriver

BASE_URL = "https://github.com/"

# How long to wait for commands.
IMPLICITLY_WAIT = 4

# For negative assertions, set the delay much lower.
IMPLICITLY_WAIT_QUICK_ASSERT = 1

# Add a delay after page navigation.
GOTO_DELAY = 0.5

# Add a delay between commands.
PER_COMMAND_DELAY = 0.1

# Configure the browser to use.
DRIVER = webdriver.Firefox


from __future__ import absolute_import, division, print_function

import tensorflow as tf
import tensorflow_datasets as tfds

# Helper libraries
import math
import numpy as np
import matplotlib.pyplot as plt

# Improve progress bar display
import tqdm
import tqdm.auto

tf.logging.set_verbosity(tf.logging.ERROR)
tqdm.tqdm = tqdm.auto.tqdm

print(tf.__version__)       # 1.12.0

# tf.enable_eager_execution()

dataset, metadata = tfds.load('fashion_mnist', as_supervised=True, with_info=True)
train_dataset, test_dataset = dataset['train'], dataset['test']

'''
Dataset fashion_mnist downloaded and prepared to /home/hdh/tensorflow_datasets/fashion_mnist/1.0.0. Subsequent calls will reuse this data.
Process finished with exit code 0
'''

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

# Explorer the data
num_train_examples = metadata.splits['train'].num_examples
num_test_examples = metadata.splits['test'].num_examples

print('Number of training examples: {}'.format(num_train_examples))
print('Number of testing examples: {}'.format(num_test_examples))

# Preprocess the data(normalize)
def normalize(images, labels):
    images = tf.cast(images, tf.float32)
    images /= 255
    return images, labels

train_dataset = train_dataset.map(normalize)
test_dataset = test_dataset.map(normalize)

'''
# Explorer the progressed data
# Take a single image and remove the color dimension
for image, label in test_dataset.take(1):
    break
image = image.numpy().reshape((28, 28))

plt.figure()
plt.imshow(image, cmap=plt.cm.binary)
plt.colorbar()
plt.grid(False)
plt.show()

plt.figure(figsize=(10, 10))
i = 0
for (image, label) in test_dataset.take(25):
    image = image.numpy().reshape((28, 28))
    plt.subplot(5, 5, i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(image, cmap=plt.cm.binary)
    plt.xlabel(class_names[label])
    i += 1
plt.show()
'''

# Build a model only with fully connected layers
# l0 = tf.keras.layers.Flatten(input_shape=(28, 28, 1))       # input
# l1 = tf.keras.layers.Dense(128, activation=tf.nn.relu)      # hidden
# l2 = tf.keras.layers.Dense(10, activation=tf.nn.softmax)    # output

# Build a model only with fully connected layers
model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(filters=64, kernel_size=(3, 3), activation=tf.nn.relu,
                           padding='same', input_shape=(28, 28, 1)),
    tf.keras.layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same'),
    tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
    tf.keras.layers.Conv2D(filters=128, kernel_size=(3, 3), activation=tf.nn.relu, padding='same'),
    tf.keras.layers.Conv2D(filters=128, kernel_size=(3, 3), activation=tf.nn.relu, padding='valid'),
    tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
    tf.keras.layers.Conv2D(filters=256, kernel_size=(3, 3), activation=tf.nn.relu, padding='same'),
    tf.keras.layers.Conv2D(filters=256, kernel_size=(3, 3), activation=tf.nn.relu, padding='same'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
# input_shape = (28, 28, 1)
# Conv : (28, 28, 64)
# Conv : (28, 28, 64)
# Pool : (14, 14, 64)
# Conv : (14, 14, 128)
# Conv : (12, 12, 128)
# Pool : (6, 6, 128)
# Conv : (6, 6, 256)
# Conv : (6, 6, 256)
# Flatten : 6*6*256
# Dense1 : 512
# Dense2 : 10

# Compile the model
# opt = tf.keras.optimizers.SGD(lr=0.1, decay=0.000225, momentum=0.5)
opt = tf.keras.optimizers.Adam(lr=0.001)
model.compile(optimizer=opt,
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
# adam 옵티마이저와 tf.enable_eager_execution()과는 문제가 있는듯.
# https://github.com/tensorflow/tensorflow/issues/25324
# 위 문장을 주석처리하면 정상적으로 실행됨

# train the model
batch_size = 32
train_dataset = train_dataset.repeat().shuffle(num_train_examples).batch(batch_size)
test_dataset = test_dataset.batch(batch_size)

model.fit(train_dataset, epochs=1, steps_per_epoch=math.ceil(num_train_examples/batch_size))

# Evaluate accuracy
test_loss, test_accuracy = model.evaluate(test_dataset, steps=math.ceil(num_test_examples/batch_size))
print('Accuracy on testset: {}'.format(test_accuracy))

# Make predictions and explore
for test_images, test_labels in test_dataset.take(1):
    test_images = test_images.numpy()
    test_labels = test_labels.numpy()
    predictions = model.predict(test_images)
print(predictions.shape)
print(predictions[0])
'''
(32, 10)
[9.9332246e-04 3.0070751e-07 5.4520708e-02 5.4992433e-03 5.0916857e-01
 4.4711786e-08 4.2935511e-01 2.3336844e-08 4.6259694e-04 3.6422879e-08]
'''
# https://classroom.udacity.com/courses/ud187/lessons/e52f6e56-2fbc-4ba8-9f74-377937b7da5c/concepts/69c86393-9b29-4875-b0b6-68b1d3cef4ed
# 05:35 진행. eager 옵션을 주석처리해서 에러 발생.
'''
Traceback (most recent call last):
  File "/home/hdh/Documents/TensorflowStudy/DeepLearning Basic/Udacity/lab04_Fashion_Mnist.py", line 109, in <module>
    for test_images, test_labels in test_dataset.take(1):
  File "/home/hdh/Env/p3ten10/lib/python3.5/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 167, in __iter__
    raise RuntimeError("dataset.__iter__() is only supported when eager "
RuntimeError: dataset.__iter__() is only supported when eager execution is enabled.
'''
# Solve: Adjust the environment to Tensorflow 1.13, Cuda 10.0(Not 10.1), CuDNN7

print(np.argmax(predictions[0]))
print(test_labels[0])

def plot_image(i, predictions_array, true_labels, images):
    predictions_array, true_labels, img = predictions_array[i], true_labels[i], images[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    plt.imshow(img[..., 0], cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_labels:
        color = 'blue'
    else:
        color = 'red'
    plt.xlabel("{} {:0.2f}% ({})".format(class_names[predicted_label],
                                         100*np.max(predictions_array),
                                         class_names[true_labels]), color=color)

def plot_value_array(i, predictions_array, true_labels):
    predictions_array, true_labels = predictions_array[i], true_labels[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])
    thisplot = plt.bar(range(10), predictions_array, color="#777777")
    plt.ylim([0, 1])
    predicted_label = np.argmax(predictions_array)

    thisplot[predicted_label].set_color('red')
    thisplot[true_labels].set_color('blue')

# i = 0
# plt.figure(figsize=(6, 3))
# plt.subplot(1, 2, 1)
# plot_image(i, predictions, test_labels, test_images)
# plt.subplot(1, 2, 2)
# plot_value_array(i, predictions, test_labels)
# plt.show()

# num_rows = 5
# num_cols = 3
# num_images = num_rows * num_cols
# plt.figure(figsize=(2*2*num_cols, 2*num_rows))
# for i in range(num_images):
#     plt.subplot(num_rows, 2*num_cols, 2*i+1)
#     plot_image(i, predictions, test_labels, test_images)
#     plt.subplot(num_cols, 2*num_cols, 2*i+2)
#     plot_value_array(i, predictions, test_labels)

# img = test_images[0]
# print(img.shape)
#
# img = np.array([img])
# print(img.shape)
#
# prediction_single = model.predict(img)
# print(prediction_single)
#
# plot_value_array(0, prediction_single, test_labels)\
# _ = plt.xticks(range(10), class_names, rotation=45)
#
# np.argmax(prediction_single[0])


import os
import urllib.parse

from prefect.environments.storage import Docker
from prefect.environments import DaskKubernetesEnvironment
from prefect import Flow, task
import pandas as pd

def score_check(grade, subject, student):
    """
    This is a normal "business logic" function which is not a Prefect task.
    If a student achieved a score > 90, multiply it by 2 for their effort! But only if the subject is not NULL.
    :param grade: number of points on an exam
    :param subject: school subject
    :param student: name of the student
    :return: final nr of points
    """
    if pd.notnull(subject) and grade > 90:
        new_grade = grade * 2
        print(
            f"Doubled score: {new_grade}, Subject: {subject}, Student name: {student}"
        )
        return new_grade
    else:
        return grade

@task
def extract():
    """ Return a dataframe with students and their grades"""
    data = {
        "Name": [
            "Hermione",
            "Hermione",
            "Hermione",
            "Hermione",
            "Hermione",
            "Ron",
            "Ron",
            "Ron",
            "Ron",
            "Ron",
            "Harry",
            "Harry",
            "Harry",
            "Harry",
            "Harry",
        ],
        "Age": [12] * 15,
        "Subject": [
            "History of Magic",
            "Dark Arts",
            "Potions",
            "Flying",
            None,
            "History of Magic",
            "Dark Arts",
            "Potions",
            "Flying",
            None,
            "History of Magic",
            "Dark Arts",
            "Potions",
            "Flying",
            None,
        ],
        "Score": [100, 100, 100, 68, 99, 45, 53, 39, 87, 99, 67, 86, 37, 100, 99],
    }

    df = pd.DataFrame(data)
    return df

@task(log_stdout=True)
def transform(x):
    x["New_Score"] = x.apply(
        lambda row: score_check(
            grade=row["Score"], subject=row["Subject"], student=row["Name"]
        ),
        axis=1,
    )
    return x

@task(log_stdout=True)
def load(y):
    old = y["Score"].tolist()
    new = y["New_Score"].tolist()
    print(f"ETL finished. Old scores: {old}. New scores: {new}")

flow = Flow(
    "etl-flow",
    storage=Docker(
        "tomaugspurger",
        python_dependencies=[
            "pandas==1.1.0",
            "dask-kubernetes",
            "dask==2.25.0",
            "distributed==2.25.0",
        ],
        image_tag="latest",
    ),
    environment=DaskKubernetesEnvironment(min_workers=1, max_workers=3),
)
with flow:
    extracted_df = extract()
    transformed_df = transform(extracted_df)
    load(transformed_df)

if __name__ == "__main__":
    flow.register(project_name="pangeo-forge")


from flask import Flask, request, jsonify
from hackMIT import run_hackMIT
app = Flask(__name__)

@app.route('/chat', methods=['POST'])
def chat():
    data = request.json
    user_input = data.get('user_input')
    state = data.get('state', 'start')

    next_state, response = run_hackMIT(state, user_input)

    return jsonify({'state': next_state, 'response': response})