#!/usr/bin/env python3
import os
import sys
import fnmatch
import argparse
import glob
import cv2
import numpy as np
from ControlNet.annotator.util import resize_image, HWC3

#import hashlib

script_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(script_dir)
sys.path.append(os.path.join(script_dir, 'ControlNet'))

# Global model initializations
model_canny = None
model_hed = None
model_mlsd = None
model_midas = None
model_openpose = None
model_uniformer = None

DETECTOR_NAMES = ["canny", "hed", "mlsd", "midas", "openpose", "uniformer"]

def get_image_files(input_path, filters=None):
    valid_extensions = [".jpg", ".JPG", ".png", ".PNG"]
    if os.path.isdir(input_path):
        image_files = []
        for ext in valid_extensions:
            image_files.extend(glob.glob(os.path.join(input_path, '**', '*' + ext), recursive=True))

        # Filter out images with detector names
        image_files = [img for img in image_files if not any(detector in img for detector in DETECTOR_NAMES)]

        # Apply additional filters if provided
        if filters:
            filtered_files = []
            for pattern in filters:
                filtered_files.extend(fnmatch.filter(image_files, pattern))
            image_files = filtered_files

    elif os.path.isfile(input_path) and any(input_path.endswith(ext) for ext in valid_extensions):
        image_files = [input_path]
    else:
        image_files = []

    return image_files

# Detector functions
def canny(img, low, high):
    global model_canny
    if model_canny is None:
        from ControlNet.annotator.canny import CannyDetector
        model_canny = CannyDetector()
    result = model_canny(img, low, high)
    return result

def hed(img):
    global model_hed
    if model_hed is None:
        from ControlNet.annotator.hed import HEDdetector
        model_hed = HEDdetector()
    result = model_hed(img)
    return result

def mlsd(img, thr_v, thr_d):
    global model_mlsd
    if model_mlsd is None:
        from ControlNet.annotator.mlsd import MLSDdetector
        model_mlsd = MLSDdetector()
    result = model_mlsd(img, thr_v, thr_d)
    return result

def midas(img, a):
    global model_midas
    if model_midas is None:
        from ControlNet.annotator.midas import MidasDetector
        model_midas = MidasDetector()
    result = model_midas(img, a)
    return result

def openpose(img, has_hand):
    #the_hash = hashlib.md5(img.tobytes()).hexdigest()
    #print(f"openpose() The hash {the_hash}")
    global model_openpose
    if model_openpose is None:
        from ControlNet.annotator.openpose import OpenposeDetector
        model_openpose = OpenposeDetector()
    result, _ = model_openpose(img, has_hand)
    return result

def uniformer(img):
    global model_uniformer
    if model_uniformer is None:
        from ControlNet.annotator.uniformer import UniformerDetector
        model_uniformer = UniformerDetector()
    result = model_uniformer(img)
    return result

def process_image(img_path, args, detector):
    print(f"Processing {img_path}")
    result = None
    img = cv2.imread(img_path)
    #print(f"Original dimensions of {img_path}: {img.shape}")
    img = resize_image(HWC3(img), args.resolution)
    #the_hash = hashlib.md5(img.tobytes()).hexdigest()
    #print(f"Resized dimensions of {img_path}: {img.shape}")
    #print(f"Resized hash {the_hash}")

    base_name = os.path.splitext(os.path.basename(img_path))[0]
    output_dir = os.path.dirname(img_path)

    # Save the resized image if it doesn't exist
    resized_image_path = os.path.join(output_dir, f"{base_name}_resize{args.resolution}.png")
    if not os.path.exists(resized_image_path):
        cv2.imwrite(resized_image_path, img)

    if detector == "canny":
        result = canny(img, args.canny_low, args.canny_high)
        output_name = f"{base_name}_canny_res{args.resolution}_low{args.canny_low}_high{args.canny_high}.png"
        cv2.imwrite(os.path.join(output_dir, output_name), result)

    elif detector == "hed":
        result = hed(img)
        output_name = f"{base_name}_hed_resize{args.resolution}.png"
        cv2.imwrite(os.path.join(output_dir, output_name), result)

    elif detector == "mlsd":
        result = mlsd(img, args.mlsd_value, args.mlsd_distance)
        output_name = f"{base_name}_mlsd_resize{args.resolution}_v{args.mlsd_value}_d{args.mlsd_distance}.png"
        cv2.imwrite(os.path.join(output_dir, output_name), result)

    elif detector == "openpose":
        #print(f"Running Openpose")
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        #the_hash = hashlib.md5(img.tobytes()).hexdigest()
        #print(f"process_image openpose The hash {the_hash}")

        result = openpose(img, args.pose_hand)
        result = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)

        # Check if the result is an all-black image
        if np.all(result == 0):
            print(f"No openpose could be detected for {img_path}.")
        else:
            hand_suffix = "_hand" if args.pose_hand else ""
            output_name = f"{base_name}_openpose{hand_suffix}_res{args.resolution}.png"
            cv2.imwrite(os.path.join(output_dir, output_name), result)

    elif detector == "midas":
        depth_result, normal_result = midas(img, args.midas_alpha)
        depth_output_name = f"{base_name}_midas_depth_res{args.resolution}_alpha{args.midas_alpha}.png"
        normal_output_name = f"{base_name}_midas_normal_res{args.resolution}_alpha{args.midas_alpha}.png"
        normal_result = cv2.cvtColor(normal_result, cv2.COLOR_BGR2RGB)
        cv2.imwrite(os.path.join(output_dir, depth_output_name), depth_result)
        cv2.imwrite(os.path.join(output_dir, normal_output_name), normal_result)

    elif detector == "uniformer":
        primary_result = uniformer(img)
        primary_result = cv2.cvtColor(primary_result, cv2.COLOR_BGR2RGB)
        primary_output_name = f"{base_name}_uniformer_res{args.resolution}.png"
        cv2.imwrite(os.path.join(output_dir, primary_output_name), primary_result)

# Main function
def main():
    parser = argparse.ArgumentParser(description="Batch command line version of the Gradio application.")
    parser.add_argument("-i", "--input", type=str, required=True, help="Path to the input image or directory.")
    parser.add_argument("-r", "--resolution", type=int, default=512,
                        help="Resolution for processing. Default is 512.")
    parser.add_argument("-f", "--filter", nargs='*',
                        help="Input filter(s) for processing images in a directory. E.g. '*.rembg.jpg'")

    # Canny specific arguments
    parser.add_argument("-c", "--canny", action="store_true", help="Use Canny detector.")
    parser.add_argument("-cl", "--canny_low", type=int, default=100, help="Canny low threshold. Default is 100.")
    parser.add_argument("-ch", "--canny_high", type=int, default=200, help="Canny high threshold. Default is 200.")

    # HED specific arguments
    parser.add_argument("-e", "--hed", action="store_true", help="Use HED detector.")

    # MLSD specific arguments
    parser.add_argument("-m", "--mlsd", action="store_true", help="Use MLSD detector.")
    parser.add_argument("-mv", "--mlsd_value", type=float, default=0.1,
                        help="MLSD value threshold. Default is 0.1.")
    parser.add_argument("-md", "--mlsd_distance", type=float, default=0.1,
                        help="MLSD distance threshold. Default is 0.1.")

    # MIDAS specific arguments
    parser.add_argument("-d", "--midas", action="store_true", help="Use MIDAS detector.")
    parser.add_argument("-ma", "--midas_alpha", type=float, default=6.2,
                        help="MIDAS alpha value. Default is 6.2.")

    # Openpose specific arguments
    parser.add_argument("-p", "--openpose", action="store_true", help="Use Openpose detector.")
    parser.add_argument("-ph", "--pose_hand", action="store_true",
                        help="Detect hand in Openpose. Default is False.")

    # Uniformer specific arguments
    parser.add_argument("-u", "--uniformer", action="store_true", help="Use Uniformer detector.")

    args = parser.parse_args()

    DETECTOR_NAMES.append(f"resize{args.resolution}")

    image_files = get_image_files(args.input, args.filter)

    # Initialize and process images with Canny detector
    if args.canny:
        global model_canny
        from ControlNet.annotator.canny import CannyDetector
        model_canny = CannyDetector()
        for img_path in image_files:
            process_image(img_path, args, detector="canny")

    # Initialize and process images with HED detector
    if args.hed:
        global model_hed
        from ControlNet.annotator.hed import HEDdetector
        model_hed = HEDdetector()
        for img_path in image_files:
            process_image(img_path, args, detector="hed")

    # Initialize and process images with MLSD detector
    if args.mlsd:
        global model_mlsd
        from ControlNet.annotator.mlsd import MLSDdetector
        model_mlsd = MLSDdetector()
        for img_path in image_files:
            process_image(img_path, args, detector="mlsd")

    # Initialize and process images with MIDAS detector
    if args.midas:
        global model_midas
        from ControlNet.annotator.midas import MidasDetector
        model_midas = MidasDetector()
        for img_path in image_files:
            process_image(img_path, args, detector="midas")

    # Initialize and process images with OpenPose detector
    if args.openpose:
        global model_openpose
        from ControlNet.annotator.openpose import OpenposeDetector
        model_openpose = OpenposeDetector()
        for img_path in image_files:
            process_image(img_path, args, detector="openpose")

    # Initialize and process images with Uniformer detector
    if args.uniformer:
        global model_uniformer
        from ControlNet.annotator.uniformer import UniformerDetector
        model_uniformer = UniformerDetector()
        for img_path in image_files:
            process_image(img_path, args, detector="uniformer")

if __name__ == "__main__":
    main()


from bs4 import BeautifulSoup
import json
from py_bandcamp.session import SESSION as requests
from py_bandcamp.utils import extract_ldjson_blob, get_props, extract_blob

class BandCamper:
    @staticmethod
    def tags(tag_list=True):
        data = extract_blob("https://bandcamp.com/tags")
        tags = {"genres": data["signup_params"]["genres"],
                "subgenres": data["signup_params"]["subgenres"]}
        if not tag_list:
            return tags
        tag_list = []
        for genre in tags["subgenres"]:
            tag_list.append(genre)
            tag_list += [sub["norm_name"] for sub in tags["subgenres"][genre]]
        return tag_list

    @staticmethod
    def search_tag(tag, page=1, pop_date=1):
        tag = tag.strip().replace(" ", "-").lower()
        if tag not in BandCamper.tags():
            return []
        params = {"page": page, "sort_field": pop_date}
        url = 'http://bandcamp.com/tag/' + str(tag)
        data = extract_blob(url, params=params)

        related_tags = [{"name": t["norm_name"], "score": t["relation"]}
                        for t in data["hub"].pop("related_tags")]

        collections, dig_deeper = data["hub"].pop("tabs")
        dig_deeper = dig_deeper["dig_deeper"]["results"]
        collections = collections["collections"]

        _to_remove = ['custom_domain', 'custom_domain_verified', "item_type",
                      'packages', 'slug_text', 'subdomain', 'is_preorder',
                      'item_id', 'num_comments', 'tralbum_id', 'band_id',
                      'tralbum_type', 'genre_id', 'audio_track_id']

        for c in collections:
            if c["name"] == "bc_dailys":
                continue
            for result in c["items"]:
                result["image"] = "https://f4.bcbits.com/img/a{art_id}_1.jpg". \
                    format(art_id=result.pop("art_id"))
                for _ in _to_remove:
                    if _ in result:
                        result.pop(_)
                result["related_tags"] = related_tags
                result["collection"] = c["name"]
                if "tralbum_url" in result:
                    result["album_url"] = result.pop("tralbum_url")
                # TODO featured track object
                yield BandcampTrack(result, scrap=False)

        for k in dig_deeper:
            for result in dig_deeper[k]["items"]:
                for _ in _to_remove:
                    if _ in result:
                        result.pop(_)
                result["related_tags"] = related_tags
                result["collection"] = "dig_deeper"
                if "tralbum_url" in result:
                    result["album_url"] = result.pop("tralbum_url")
                # TODO featured track object
                yield BandcampTrack(result, scrap=False)

    @staticmethod
    def search_albums(album_name):
        for album in BandCamper.search(album_name, albums=True, tracks=False,
                                       artists=False, labels=False):
            yield album

    @staticmethod
    def search_tracks(track_name):
        for t in BandCamper.search(track_name, albums=False, tracks=True,
                                   artists=False, labels=False):
            yield t

    @staticmethod
    def search_artists(artist_name):
        for a in BandCamper.search(artist_name, albums=False, tracks=False,
                                   artists=True, labels=False):
            yield a

    @staticmethod
    def search_labels(label_name):
        for a in BandCamper.search(label_name, albums=False, tracks=False,
                                   artists=False, labels=True):
            yield a

    @staticmethod
    def search(name, page=1, albums=True, tracks=True, artists=True,
               labels=False):
        params = {"page": page, "q": name}
        response = requests.get('http://bandcamp.com/search', params=params)
        html_doc = response.content
        soup = BeautifulSoup(html_doc, 'html.parser')

        seen = []
        for item in soup.find_all("li", class_="searchresult"):
            item_type = item.find('div', class_='itemtype').text.strip().lower()
            if item_type == "album" and albums:
                data = BandCamper._parse_album(item)
            elif item_type == "track" and tracks:
                data = BandCamper._parse_track(item)
            elif item_type == "artist" and artists:
                data = BandCamper._parse_artist(item)
            elif item_type == "label" and labels:
                data = BandCamper._parse_label(item)
            else:
                continue
            #data["type"] = type
            yield data
            seen.append(data)
        if not len(seen):
            return  # no more pages
        for item in BandCamper.search(name, page=page + 1, albums=albums,
                                      tracks=tracks, artists=artists,
                                      labels=labels):
            if item in seen:
                return  # duplicate data, fail safe out of loops
            yield item

    @staticmethod
    def get_track_lyrics(track_url):
        track_page = requests.get(track_url)
        track_soup = BeautifulSoup(track_page.text, 'html.parser')
        track_lyrics = track_soup.find("div", {"class": "lyricsText"})
        if track_lyrics:
            return track_lyrics.text

        return "lyrics unavailable"

    @staticmethod
    def get_streams(urls):
        if not isinstance(urls, list):
            urls = [urls]
        direct_links = [BandCamper.get_stream_url(url) for url in urls]
        return direct_links

    @staticmethod
    def get_stream_url(url):
        data = BandCamper.get_stream_data(url)
        for p in data['additionalProperty']:
            if p['name'] == 'file_mp3-128':
                return p["value"]
        return url

    @staticmethod
    def get_stream_data(url):

        txt_string = requests.get(url).text

        json_blob = txt_string. \
            split('<script type="application/ld+json">')[-1]. \
            split("</script>")[0]

        data = json.loads(json_blob)
        from pprint import pprint
        pprint(data)

        artist_data = data['byArtist']
        album_data = data['inAlbum']
        result = {
            "categories": data["@type"],
            'album_name': album_data['name'],
            'artist': artist_data['name'],
            'image': data['image'],
            "title": data['name'],
            "url": url,
            "tags": data['keywords'].split(", ") + data["tags"]
        }

        for p in data['additionalProperty']:
            if p['name'] == 'file_mp3-128':
                result["stream"] = p["value"]
            if p['name'] == 'duration_secs':
                result["length"] = p["value"] * 1000

        return result

    @staticmethod
    def _parse_label(item):
        art = item.find("div", {"class": "art"}).find("img")
        if art:
            art = art["src"]
        name = item.find('div', class_='heading').text.strip()
        url = item.find('div', class_='heading').find('a')['href'].split("?")[
            0]
        location = item.find('div', class_='subhead').text.strip()
        try:
            tags = item.find('div', class_='tags').text \
                .replace("tags:", "").split(",")
            tags = [t.strip().lower() for t in tags]
        except:  # sometimes missing
            tags = []

        data = {"name": name, "location": location,
                "tags": tags, "url": url, "image": art
                }
        return BandcampLabel(data)

    @staticmethod
    def _parse_artist(item):
        name = item.find('div', class_='heading').text.strip()
        url = item.find('div', class_='heading').find('a')['href'].split("?")[
            0]
        genre = item.find('div', class_='genre').text.strip().replace(
            "genre: ", "")
        location = item.find('div', class_='subhead').text.strip()
        try:
            tags = item.find('div', class_='tags').text \
                .replace("tags:", "").split(",")
            tags = [t.strip().lower() for t in tags]
        except:  # sometimes missing
            tags = []
        art = item.find("div", {"class": "art"}).find("img")["src"]
        data = {"name": name, "genre": genre, "location": location,
                "tags": tags, "url": url, "image": art, "albums": []
                }

        return BandcampArtist(data)

    @staticmethod
    def _parse_track(item):
        track_name = item.find('div', class_='heading').text.strip()
        url = item.find('div', class_='heading').find('a')['href'].split("?")[
            0]
        album_name, artist = item.find('div', class_='subhead').text.strip(

        ).split("by")
        album_name = album_name.strip().replace("from ", "")
        artist = artist.strip()
        released = item.find('div', class_='released').text.strip().replace(
            "released ", "")
        try:
            tags = item.find('div', class_='tags').text \
                .replace("tags:", "").split(",")
            tags = [t.strip().lower() for t in tags]
        except:  # sometimes missing
            tags = []

        art = item.find("div", {"class": "art"}).find("img")["src"]
        data = {"track_name": track_name, "released": released, "url": url,
                "tags": tags, "album_name": album_name, "artist": artist,
                "image": art
                }
        return BandcampTrack(data)

    @staticmethod
    def _parse_album(item):
        art = item.find("div", {"class": "art"}).find("img")["src"]
        album_name = item.find('div', class_='heading').text.strip()
        url = item.find('div', class_='heading').find('a')['href'].split("?")[
            0]
        lenght = item.find('div', class_='length').text.strip()
        tracks, minutes = lenght.split(",")
        tracks = tracks.replace(" tracks", "").replace(" track", "").strip()
        minutes = minutes.replace(" minutes", "").strip()
        released = item.find('div', class_='released').text.strip().replace(
            "released ", "")
        tags = item.find('div', class_='tags').text.replace("tags:",
                                                            "").split(",")
        tags = [t.strip().lower() for t in tags]
        artist = item.find("div", {"class": "subhead"}).text.strip()
        if artist.startswith("by "):
            artist = artist[3:]
        data = {"album_name": album_name,
                "length": lenght,
                "minutes": minutes,
                "url": url,
                "image": art,
                "artist": artist,
                "track_number": tracks,
                "released": released,
                "tags": tags
                }
        return BandcampAlbum(data, scrap=False)

class BandcampTrack:
    def __init__(self, data, scrap=True):
        self._url = data.get("url")
        self._data = data or {}
        self._page_data = {}
        if scrap:
            self.scrap()
        if not self.url:
            raise ValueError("bandcamp url is not set")

    def scrap(self):
        self._page_data = self.get_track_data(self.url)
        return self._page_data

    @staticmethod
    def from_url(url):
        return BandcampTrack({"url": url})

    @property
    def url(self):
        return self._url or self.data.get("url")

    @property
    def album(self):
        return self.get_album(self.url)

    @property
    def artist(self):
        return self.get_artist(self.url)

    @property
    def data(self):
        for k, v in self._page_data.items():
            self._data[k] = v
        return self._data

    @property
    def title(self):
        return self.data.get("title") or self.data.get("name") or \
               self.url.split("/")[-1]

    @property
    def image(self):
        return self.data.get("image")

    @property
    def track_num(self):
        return self.data.get("tracknum")

    @property
    def stream(self):
        return self.data.get("file_mp3-128")

    @staticmethod
    def get_album(url):
        data = extract_ldjson_blob(url, clean=True)
        if data.get('inAlbum'):
            return BandcampAlbum({
                "title": data['inAlbum'].get('name'),
                "url": data['inAlbum'].get('id', url).split("#")[0],
                'type': data['inAlbum'].get("type"),
            })

    @staticmethod
    def get_artist(url):
        data = extract_ldjson_blob(url, clean=True)
        d = data.get("byArtist")
        if d:
            return BandcampArtist({
                "title": d.get('name'),
                "url": d.get('id', url).split("#")[0],
                'genre': d.get('genre'),
                "artist_type": d.get('type')
            }, scrap=False)
        return None

    @staticmethod
    def get_track_data(url):
        data = extract_ldjson_blob(url, clean=True)
        kwords = data.get('keywords', "")
        if isinstance(kwords, str):
            kwords = kwords.split(", ")
        track = {
            'dateModified': data.get('dateModified'),
            'datePublished': data.get('datePublished'),
            "url": data.get('id') or url,
            "title": data.get("name"),
            "type": data.get("type"),
            'image': data.get('image'),
            'keywords': kwords
        }
        for k, v in get_props(data).items():
            track[k] = v
        return track

    def __repr__(self):
        return self.__class__.__name__ + ":" + self.title

    def __str__(self):
        return self.url

class BandcampAlbum:
    def __init__(self, data, scrap=True):
        self._url = data.get("url")
        self._data = data or {}
        self._page_data = {}
        if scrap:
            self.scrap()
        if not self.url:
            raise ValueError("bandcamp url is not set")

    def scrap(self):
        self._page_data = self.get_album_data(self.url)
        return self._page_data

    @staticmethod
    def from_url(url):
        return BandcampAlbum({"url": url})

    @property
    def image(self):
        return self.data.get("image")

    @property
    def url(self):
        return self._url or self.data.get("url")

    @property
    def title(self):
        return self.data.get("title") or self.data.get("name") or \
               self.url.split("/")[-1]

    @property
    def releases(self):
        return self.get_releases(self.url)

    @property
    def artist(self):
        return self.get_artist(self.url)

    @property
    def keywords(self):
        return self.data.get("keywords") or []

    @property
    def tracks(self):
        return self.get_tracks(self.url)

    @property
    def featured_track(self):
        if not len(self.tracks):
            return None
        num = self.data.get('featured_track_num', 1) or 1
        return self.tracks[int(num) - 1]

    @property
    def comments(self):
        return self.get_comments(self.url)

    @property
    def data(self):
        for k, v in self._page_data.items():
            self._data[k] = v
        return self._data

    @staticmethod
    def get_releases(url):
        data = extract_ldjson_blob(url, clean=True)
        releases = []
        for d in data.get("albumRelease", []):
            release = {
                "description": d.get("description"),
                'image': d.get('image'),
                "title": d.get('name'),
                "url": d.get('id', url).split("#")[0],
                'format': d.get('musicReleaseFormat'),
            }
            releases.append(release)
        return releases

    @staticmethod
    def get_artist(url):
        data = extract_ldjson_blob(url, clean=True)
        d = data.get("byArtist")
        if d:
            return BandcampArtist({
                "description": d.get("description"),
                'image': d.get('image'),
                "title": d.get('name'),
                "url": d.get('id', url).split("#")[0],
                'genre': d.get('genre'),
                "artist_type": d.get('type')
            }, scrap=False)
        return None

    @staticmethod
    def get_tracks(url):
        data = extract_ldjson_blob(url, clean=True)
        if not data.get("track"):
            return []

        data = data['track']

        tracks = []

        for d in data.get('itemListElement', []):
            d = d['item']
            track = {
                "title": d.get('name'),
                "url": d.get('id') or url,
                'type': d.get('type'),
            }
            for k, v in get_props(d).items():
                track[k] = v
            tracks.append(BandcampTrack(track, scrap=False))
        return tracks

    @staticmethod
    def get_comments(url):
        data = extract_ldjson_blob(url, clean=True)
        comments = []
        for d in data.get("comment", []):
            comment = {
                "text": d["text"],
                'image': d["author"].get("image"),
                "author": d["author"]["name"]
            }
            comments.append(comment)
        return comments

    @staticmethod
    def get_album_data(url):
        data = extract_ldjson_blob(url, clean=True)
        props = get_props(data)
        kwords = data.get('keywords', "")
        if isinstance(kwords, str):
            kwords = kwords.split(", ")
        return {
            'dateModified': data.get('dateModified'),
            'datePublished': data.get('datePublished'),
            'description': data.get('description'),
            "url": data.get('id') or url,
            "title": data.get("name"),
            "type": data.get("type"),
            "n_tracks": data.get('numTracks'),
            'image': data.get('image'),
            'featured_track_num': props.get('featured_track_num'),
            'keywords': kwords
        }

    def __repr__(self):
        return self.__class__.__name__ + ":" + self.title

    def __str__(self):
        return self.url

class BandcampLabel:
    def __init__(self, data, scrap=True):
        self._url = data.get("url")
        self._data = data or {}
        self._page_data = {}
        if scrap:
            self.scrap()
        if not self.url:
            raise ValueError("bandcamp url is not set")

    def scrap(self):
        self._page_data = {}  # TODO
        return self._page_data

    @staticmethod
    def from_url(url):
        return BandcampTrack({"url": url})

    @property
    def url(self):
        return self._url or self.data.get("url")

    @property
    def data(self):
        for k, v in self._page_data.items():
            self._data[k] = v
        return self._data

    @property
    def name(self):
        return self.data.get("title") or self.data.get("name") or \
               self.url.split("/")[-1]

    @property
    def location(self):
        return self.data.get("location")

    @property
    def tags(self):
        return self.data.get("tags") or []

    @property
    def image(self):
        return self.data.get("image")

    def __repr__(self):
        return self.__class__.__name__ + ":" + self.name

    def __str__(self):
        return self.url

class BandcampArtist:
    def __init__(self, data, scrap=True):
        self._url = data.get("url")
        self._data = data or {}
        self._page_data = {}
        if scrap:
            self.scrap()

    def scrap(self):
        self._page_data = {}  # TODO
        return self._page_data

    @property
    def featured_album(self):
        return BandcampAlbum.from_url(self.url + "/releases")

    @property
    def featured_track(self):
        if not self.featured_album:
            return None
        return self.featured_album.featured_track

    @staticmethod
    def get_albums(url):
        albums = []
        soup = BeautifulSoup(requests.get(url).text, "html.parser")
        for album in soup.find_all("a"):
            album_url = album.find("p", {"class": "title"})
            if album_url:
                title = album_url.text.strip()
                art = album.find("div", {"class": "art"}).find("img")["src"]
                album_url = url + album["href"]
                album = BandcampAlbum({"album_name": title,
                                       "image": art,
                                       "url": album_url})
                albums.append(album)
        return albums

    @property
    def albums(self):
        return self.get_albums(self.url)

    @staticmethod
    def from_url(url):
        return BandcampTrack({"url": url})

    @property
    def url(self):
        return self._url or self.data.get("url")

    @property
    def data(self):
        for k, v in self._page_data.items():
            self._data[k] = v
        return self._data

    @property
    def name(self):
        return self.data.get("title") or self.data.get("name") or \
               self.url.split("/")[-1]

    @property
    def location(self):
        return self.data.get("location")

    @property
    def genre(self):
        return self.data.get("genre")

    @property
    def tags(self):
        return self.data.get("tags") or []

    @property
    def image(self):
        return self.data.get("image")

    def __repr__(self):
        return self.__class__.__name__ + ":" + self.name

    def __str__(self):
        return self.url

    def __eq__(self, other):
        if str(self) == str(other):
            return True
        return False


import blenderproc as bproc
import argparse
import os

parser = argparse.ArgumentParser()
parser.add_argument('shape_net', help="path to the downloaded shape net core v2 dataset, get it from (http://www.shapenet.org/)")
parser.add_argument('house', help="Path to the house.json file of the SUNCG scene to load")
parser.add_argument('output_dir', nargs='?', default="examples/datasets/shapenet_with_suncg/output", help="Path to where the final files, will be saved")
args = parser.parse_args()

bproc.init()

# load suncg house into the scene
label_mapping = bproc.utility.LabelIdMapping.from_csv(bproc.utility.resolve_resource(os.path.join('id_mappings', 'nyu_idset.csv')))
suncg_objs = bproc.loader.load_suncg(args.house, label_mapping=label_mapping)

# Find all bed objects, to sample the shapenet objects on
bed_objs = bproc.filter.by_cp(suncg_objs, "category_id", label_mapping.id_from_label("bed"))

# makes Suncg objects emit light
bproc.lighting.light_suncg_scene()

# load selected shapenet object
shapenet_obj = bproc.loader.load_shapenet(args.shape_net, used_synset_id="02801938")

# Sample a point above any bed
sample_point = bproc.sampler.upper_region(
    objects_to_sample_on=bed_objs,
    min_height=0.75,
    use_ray_trace_check=True
)
# move the shapenet object to the sampled position
shapenet_obj.set_location(sample_point)

# adding a modifier we avoid that the objects falls through other objects during the physics simulation
shapenet_obj.add_modifier(name="SOLIDIFY", thickness=0.001)

# enable rigid body component of the objects which makes them participate in physics simulations
shapenet_obj.enable_rigidbody(active=True, mass_factor=2000, collision_margin=0.0001)
for obj in bproc.filter.all_with_type(suncg_objs, bproc.types.MeshObject):
    obj.enable_rigidbody(active=False, mass_factor=2000, collision_margin=0.0001)

# Run the physics simulation
bproc.object.simulate_physics_and_fix_final_poses(min_simulation_time=0.5, max_simulation_time=4, check_object_interval=0.25)

# sample five camera poses
for i in range(5):
    # sample random camera location around the shapenet object
    location = bproc.sampler.part_sphere(center=shapenet_obj.get_location(), mode="SURFACE", radius=2, dist_above_center=0.5)
    # compute rotation based on vector going from the camera location towards shapenet object
    rotation_matrix = bproc.camera.rotation_from_forward_vec(shapenet_obj.get_location() - location)
    # add homog cam pose based on location an rotation
    cam2world_matrix = bproc.math.build_transformation_mat(location, rotation_matrix)
    bproc.camera.add_camera_pose(cam2world_matrix)

# activate normal and depth rendering
bproc.renderer.enable_normals_output()
bproc.renderer.enable_depth_output(activate_antialiasing=False)

# render the whole pipeline
data = bproc.renderer.render()

# write the data to a .hdf5 container
bproc.writer.write_hdf5(args.output_dir, data)


#!/usr/bin/env python3

import reports
import os
import datetime
import emails

text_file_location = "./supplier-data/descriptions/"

file_list = os.listdir(text_file_location)
Summary = ""
currDate = datetime.datetime.now()

for file in file_list:
  with open (text_file_location + file, "r") as f:
    iLines = f.readlines()
    Summary += "name: " + iLines[0] + "
"
    Summary += "weight: " + iLines[1] + "

"

if __name__ == "__main__":
  dstr = currDate.strftime("%B %d, %Y")
  reports.generate_report("/tmp/processed.pdf", "Proccessed Update on " + dstr, str(Summary))
  sender = "automation@example.com"
  recipient = "student-00-44b312fcfd51@example.com "
  subject = "Upload Completed - Online Fruit Store"
  body = "All fruits are uploaded to our website successfully. A detailed list is attached to this email."
  attachment_path = "/tmp/processed.pdf"
  message = emails.generate_email(sender, recipient, subject, body, attachment_path)
  emails.send_email(message)


from ..zhimi.entity import ZhiMIoTEntity
from .viomi_washer_v13 import *
from asyncio import sleep
from homeassistant.components.vacuum import SUPPORT_CLEAN_SPOT, SUPPORT_FAN_SPEED, SUPPORT_LOCATE, SUPPORT_PAUSE, SUPPORT_RETURN_HOME, SUPPORT_SEND_COMMAND, SUPPORT_START, SUPPORT_STATUS, SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, VacuumEntity
from homeassistant.const import CONF_HOST, CONF_TOKEN
from datetime import datetime, timedelta
import logging

_LOGGER = logging.getLogger(__name__)

APPOINT_MIN = 1  # 3 in app default
APPOINT_MAX = 23  # 19 in app default
DEFAULT_APPOINT_TIME = -8  # -8 means 8 o'clock, 8 means 8 hours later

PROP_IIDS = {
    'switch_status': PROP_Switch_Status,
    'mode': PROP_Mode,
    'target_temperature': PROP_Target_Temperature,
    'spin_speed': PROP_Spin_Speed,
    'drying_time': PROP_Drying_Time,
    'rinsh_times': PROP_Rinsh_Times,
    'speed_level': PROP_Speed_Level,
}

class ZhiViomiCloudWasher(ZhiMIoTEntity, VacuumEntity):

    def __init__(self, conf):
        super().__init__(ALL_PROPS, conf, 'mdi:washing-machine')
        self.values = {}

    async def async_poll(self):
        await self.mi_poll()
        self._status = VALUE_Status(self.values[PROP_Status]).name
        if self.values[PROP_Status] == VALUE_Status.暂停:
            self._status += '｜暂停'
        if self.values[PROP_Status] != VALUE_Status.关机:
            left_time = self.values[PROP_Left_Time]
            if left_time:
                self._status += '｜剩%s分钟' % left_time
            drying_time = self.values[PROP_Drying_Time]
            if drying_time:
                self._status += '|' + VALUE_Drying_Time(drying_time).name
            appoint_time = self.values[PROP_预约完成时间]
            if appoint_time:
                self._status += '｜预约%s' % datetime.fromtimestamp(appoint_time).strftime('%H:%M')
        return self.values

    async def mi_poll(self):
        data = await super().async_poll()
        for k, v in data.items():
            self.values[k] = v

    @property
    def supported_features(self):
        return SUPPORT_STATUS | SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_FAN_SPEED | SUPPORT_START | SUPPORT_PAUSE | SUPPORT_STOP | SUPPORT_RETURN_HOME | SUPPORT_SEND_COMMAND | SUPPORT_CLEAN_SPOT | SUPPORT_LOCATE

    @property
    def status(self):
        return self._status

    async def async_update_status(self, status):
        self._status = status
        self.async_write_ha_state()

    @property
    def is_on(self):
        return self.values[PROP_Status] != VALUE_Status.关机

    async def async_turn_on(self, **kwargs):
        if self.values[PROP_Status] == VALUE_Status.待机:
            await self.async_update_status('已是待机状态')
        else:
            if self.values[PROP_Status] != VALUE_Status.关机:
                await self.async_turn_off()
                await sleep(1)

            def success(siid, iid, value):
                self.values[PROP_Status] = VALUE_Status.待机
            await self.async_control(SRV_Washer, PROP_Switch_Status, True, '开机', success, True)

    async def async_turn_off(self, **kwargs):
        def success(siid, iid, value):
            self.values[PROP_Status] = VALUE_Status.关机
        await self.async_control(SRV_Washer, PROP_Switch_Status, False, '关机', success, True)

    @property
    def fan_speed(self):
        return VALUE_Mode(self.values[PROP_Mode]).name

    @property
    def fan_speed_list(self):
        return [e.name for e in VALUE_Mode]

    async def async_set_fan_speed(self, fan_speed, **kwargs):
        await self.async_control(SRV_Washer, PROP_Mode, self.fan_speed_list.index(fan_speed) + 1, '设定' + fan_speed + '模式')

    async def async_start(self):
        if self.values[PROP_Status] == VALUE_Status.繁忙:
            lock = not self.values[PROP_Physical_Control_Locked]
            return await self.async_control(SRV_Physical_Control_Locked, PROP_Physical_Control_Locked, lock, '锁定' if lock else '解锁')
        if not self.is_on:
            await self.async_turn_on()
            await sleep(1)
        await self.async_action(ACTION_Start_Wash, '启动')

    async def async_pause(self):
        if self.values[PROP_Status] == VALUE_Status.繁忙:
            await self.async_action(ACTION_Pause, '暂停')
        else:
            await self.async_update_status('非工作状态，无法暂停')

    async def async_stop(self, **kwargs):
        if self.values[PROP_Status] == VALUE_Status.关机:
            await self.async_update_status('已经是关机状态')
        else:
            await self.async_turn_off()

    async def async_return_to_base(self, **kwargs):
        await self.async_stop()

    async def async_send_command(self, command, params=None, **kwargs):
        for item in command.split(';'):
            parts = item.split('=', 1)
            count = len(parts)
            cmd = parts[0]
            if count > 1:
                value = parts[1][1:] if parts[1].startswith('$') else int(parts[1])
            async_cmd = 'async_' + cmd
            if hasattr(self, async_cmd):
                # turn_on/turn_off,start/pause/stop/return_to_base,locate/clean_spot
                # fanspeed=$[value],dry_mode|appoint[=value]
                async_func = getattr(self, async_cmd)
                await (async_func(value) if count > 1 else async_func())
            elif count > 1 and cmd in PROP_IIDS:
                piid = PROP_IIDS[cmd]
                code = await self.async_control(SRV_Washer, piid, value, '设定' + (ALL_PROPS[SRV_Washer].get(piid, '')))
                if code is None:
                    continue
                elif code == False:
                    return
            else:
                _LOGGER.error("Invalid speed format:%s", params)
                continue
            await sleep(1)

    async def async_action(self, aiid, op):
        await self.async_control(SRV_Washer, aiid, [self.values[PROP_Mode]], op, self.action_success)

    def action_success(self, siid, aiid, value):
        self.values[PROP_Status] = (VALUE_Status.繁忙, VALUE_Status.暂停)[aiid == ACTION_Start_Wash]

    async def async_clean_spot(self, **kwargs):
        if not self.is_on:
            await self.async_turn_on()
            await sleep(1)
        await self.async_dry_mode(0 if self.values[PROP_Drying_Time] else 1)

    async def async_locate(self, **kwargs):
        if not self.is_on:
            await self.async_turn_on()
            await sleep(1)
        await self.async_appoint()

    async def async_dry_mode(self, mode=1):
        await self.async_control(SRV_Washer, PROP_Drying_Time, VALUE_Drying_Time.智能烘干 if mode == 1 else mode, ('设定' if mode else '取消') + '烘干模式')

    async def async_appoint(self, atime=DEFAULT_APPOINT_TIME):
        now = datetime.now()
        if atime < 0:
            aclock = -atime
            if now.hour > aclock:
                now += timedelta(days=1)
            status = '预约%s点钟完成洗衣' % aclock
            stamp = datetime(now.year, now.month, now.day, aclock).timestamp()
        else:
            status = '预约%s小时后完成洗衣' % atime
            stamp = now.timestamp() + atime * 60 * 60 * 1000
        await (self.async_control(SRV_自定义属性, PROP_预约完成时间, int(stamp), status) if atime else self.async_start())

class ZhiViomiWasher(ZhiViomiCloudWasher):
    pass


#!usr/bin/python3

"""define class FileStorage"""
import json
from models.base_model import BaseModel
from models.user import User
from models.state import State
from models.city import City
from models.place import Place
from models.amenity import Amenity
from models.review import Review

class FileStorage:
    """
    Public class attribute of class FileStorage
    """
    __file_path = "file.json"
    __objects = {}

    def all(self):
        """returns the dictionary __objects"""
        return self.__objects

    def new(self, obj):
        """sets in __objects the obj with key <obj class name>.id"""
        key = f"{obj.__class__.__name__}.{obj.id}"
        self.__objects[key] = obj

    def save(self):
        """serializes __objects to the JSON file (path: __file_path)"""
        obj_dict = {}
        for key, value in self.__objects.items():
            obj_dict[key] = value.to_dict()
        with open(self.__file_path, 'w') as file:
            json.dump(obj_dict, file)

    def reload(self):
        """
        deserializes the JSON file to __objects (only if the JSON file
        (__file_path) exists ; otherwise, do nothing.
        If the file doesn’t exist, no exception should be raised)
        """
        try:
            with open(self.__file_path, 'r') as file:
                obj_dict = json.load(file)
                for key, value in obj_dict.items():
                    class_name, obj_id = key.split('.')
                    class_obj = eval(class_name)
                    self.__objects[key] = class_obj(**value)
        except FileNotFoundError:
            return

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


import setuptools

with open('README.md') as fh:
	long_description = fh.read()

setuptools.setup(
	name="pyexample_psg",
	version="0.0.1",
	author="psg",
	author_email="pranavg456@gmail.com",
	description="A small python example project",
	long_description=long_description,
	long_description_content_type="text/markdown",
	url="https://github.com/Alexmhack/python_packaging",
	packages=setuptools.find_packages(),
	classifiers=[
		"Programming Language :: Python :: 3",
		"License :: OSI Approved :: MIT License",
		"Operating System :: OS Independent",
	]
)


import re
import sys
import getopt
import xml.etree.ElementTree as ET

# IPP - projekt 2
# Dominik Nejedly (xnejed09)
# Interpret XML reprezentace kodu jazyka IPPcode20

class errorCodes:
    # parametry skriptu a chyby souboru
    PAR_ERR = 10
    INPUT_FILE_ERR = 11
    OUTPUT_FILE_ERR = 12

    # chyby XML souboru
    XML_FORMAT_ERR = 31
    XML_STRUCT_LEX_SYNTAX_ERR = 32

    # behove chyby
    SEMANTIC_ERR = 52
    BAD_OPERAND_TYPE = 53
    NONEXISTENT_VAR = 54
    NONEXISTENT_FRAME = 55
    MISSING_VALUE = 56
    BAD_OPERAND_VALUE = 57
    STRING_ERR = 58

    # neovlivnitelna chyba programu
    INTERNAL_ERR = 99

# trida instrukce s konstruktorem
class instruction:
    def __init__(self, opcode):
        self.opcode = opcode

# trida argumentu s kontruktorem
class argument:
    def __init__(self, value):
        self.value = value

# trida promenne s kontruktorem
class variable:
    def __init__(self, name, varType, value):
        self.name = name
        self.varType = varType
        self.value = value

# trida jednotky datoveho zasobniku s kontruktorem
class dataStackEl:
    def __init__(self, elType, value):
        self.elType = elType
        self.value = value

# Uzavreni souboru, pracuje s globalnim deskriptorem.
def closeFile():
    global fd

    if(fd != None):
        fd.close()

# vypis na standardni chybovy vystup
def printToStderr(someStr):
    print(someStr, file = sys.stderr)

# vypis chyboveho hlaseni a ukonceni programu
def errExit(errCode, errMsg):
    closeFile()
    printToStderr("ERROR: " + errMsg)
    sys.exit(errCode)

# vypis obsahu ramce na standardni chybovy vystup
def printFrameStderr(frame, frames):
    if(len(frames[frame]) == 0):
        printToStderr("Frame is empty.")
    else:
        for var in frames[frame]:
            varType = frames[frame][var].varType
            value = frames[frame][var].value

            if(varType == None):
                varType = "None"
                value = "None"

            printToStderr(var + "\t|\t" + varType + "\t|\t" + str(value))

# nahrada ciselnych escape sekvenci za znaky
def dealWithEscape(editStr):
    escSeqList = re.findall(r'\\\d{3}', editStr)

    while(len(escSeqList) > 0):
        escSeq = escSeqList[0]
        editStr = editStr.replace(escSeq, chr(int(escSeq.replace("\\", ""))))

        while(escSeq in escSeqList):
            escSeqList.remove(escSeq)

    return editStr

# kontrola existence ramce
def frameExist(frame, frames):
    if(frames[frame] != None):
        return True

    return False

# kontrola existence promenne v urcitem ramci
def varInFrame(varName, frame, frames):
    if(varName in frames[frame]):
        return True

    return False

# Zkontroluje, zdali dana promenna ci ramec existuji.
def checkVarExistance(varName, frame, frames):
    if(not frameExist(frame, frames)):
        errExit(errorCodes.NONEXISTENT_FRAME, "Frame does not exist!")
    elif(not varInFrame(varName, frame, frames)):
        errExit(errorCodes.NONEXISTENT_VAR, "Varialbe does not exist!")

# Zkotroluje, zdali je promenna inicializovana.
def checkVarInit(varName, frame, frames):
    if(frames[frame][varName].varType == None):
        errExit(errorCodes.MISSING_VALUE, "Variable is not initialized!")

# Zkontroluje 2. argument instrukce a jeho typ.
def getArg2(instr, frames, dataType):
    if(instr.arg2.type == "var"):
        var = instr.arg2.value.split('@')
        checkVarExistance(var[1], var[0], frames)
        checkVarInit(var[1], var[0], frames)

        if(frames[var[0]][var[1]].varType != dataType):
            errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
        value = frames[var[0]][var[1]].value
    else:
        if(instr.arg2.type != dataType):
            errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

        value = instr.arg2.value

    return value

# Zkontroluje 3. argument instrukce a jeho typ.
def getArg3(instr, frames, dataType):
    if(instr.arg3.type == "var"):
        var = instr.arg3.value.split('@')
        checkVarExistance(var[1], var[0], frames)
        checkVarInit(var[1], var[0], frames)

        if(frames[var[0]][var[1]].varType != dataType):
            errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

        value = frames[var[0]][var[1]].value
    else:
        if(instr.arg3.type != dataType):
            errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
        value = instr.arg3.value

    return value

# Zkontroluje 2. argument instrukce a vrati jeho typ a hodnotu.
def getArg2WType(instr, frames):
    if(instr.arg2.type == "var"):
        var = instr.arg2.value.split('@')
        checkVarExistance(var[1], var[0], frames)
        checkVarInit(var[1], var[0], frames)
        dataType = frames[var[0]][var[1]].varType
        value = frames[var[0]][var[1]].value
    else:
        dataType = instr.arg2.type
        value = instr.arg2.value

    return dataType, value

# Zkontroluje 3. argument instrukce a vrati jeho typ a hodnotu.
def getArg3WType(instr, frames):
    if(instr.arg3.type == "var"):
        var = instr.arg3.value.split('@')
        checkVarExistance(var[1], var[0], frames)
        checkVarInit(var[1], var[0], frames)
        dataType = frames[var[0]][var[1]].varType
        value = frames[var[0]][var[1]].value
    else:
        dataType = instr.arg3.type
        value = instr.arg3.value

    return dataType, value

# Zkontroluje existenci a typ hodnoty na datovem zasobniku a danou hodnotu vrati.
def getDStackEl(dataStack, dataType):
    if(len(dataStack) == 0):
        errExit(errorCodes.MISSING_VALUE, "Data stack is empty!")

    dataEl = dataStack.pop()

    if(dataEl.elType != dataType):
        errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

    return dataEl.value

# Zkontroluje hodnotu na datovem zasobniku a vrati ji i s jejim typem.
def getDStackElWType(dataStack):
    if(len(dataStack) == 0):
        errExit(errorCodes.MISSING_VALUE, "Data stack is empty!")

    dataEl = dataStack.pop()

    return dataEl.elType, dataEl.value

# zapsani statistik do souboru
def writeStats(statsFiles, statsRecords, numOfInstr, numOfVars):
    for fileName in statsFiles:
        try:
            fd = open(fileName, "w")
        except:
            errExit(errorCodes.OUTPUT_FILE_ERR, "Can not open output statistic file!")

        for record in statsRecords:
            if(record == "vars"):
                print(numOfVars, file = fd)
            else:
                print(numOfInstr, file = fd)

        fd.close()

# kontrola spravneho zapisu promenne
def checkVar(var):
    if(re.match(r'^(GF|LF|TF)@[a-zA-Z_\-$&%*!?][\w\-$&%*!?]*$', var) == None):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument invalid var name!")

# kontrola spravneho zapisu hodnoty nil
def checkNil(nil):
    if(nil != "nil"):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument invalid nil value!")

# kontrola spravneho zapisu hodnoty int
def checkInt(intVal):
    if(re.match(r'^[+\-]?\d+$', intVal)):
        return True
    return False

# kontrola spravneho zapisu bool hodnoty
def checkBool(boolVal):
    if(boolVal in ["true", "false"]):
        return True
    return False

# kontrola spravneho zapisu retezce
def checkString(stringVal):
    # Pokud neni zadana hodnota, pracuje se s prazdnym retezcem.
    if(stringVal == None):
        stringVal = ""

    if(re.match(r'^([^\s\\#]|(\\\d{3}))*$', stringVal)):
        return True
    return False

# kontrola spravneho zapisu navesti
def checkLabel(label):
    if(re.match(r'^[a-zA-Z_\-$&%*!?][\w\-$&%*!?]*$', label) == None):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument ivalid label name!")

# kontrola spravneho zapisu typu
def checkType(typeVal):
    if(typeVal not in ["int", "string", "bool"]):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument invalid data type name!")

# funkce na kontrolu argumentu v XML
def checkXMLArgs(args, numOfArgs, expectedTypes):
    # kontrola poctu argumentu u instrukce
    if(len(args) != numOfArgs):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid number of arguments!")

    expectedTags = []   # pole s ocekavanymi jmeny elementu
    ordOfArgs = []      # poradi argumentu

    # nahrani ocekavanych jmen argumentu
    for num in range(1, numOfArgs + 1):
        expectedTags.append("arg" + str(num))

    # kontrola jednotlivych argumentu
    for arg in args:
        # Argument nemuze mit dalsi potomky.
        if(len(arg) != 0):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Arguments can not have children!")

        # kotrola jmena argumentu a take duplicity jeho vyskytu
        if(arg.tag not in expectedTags):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid argument tag!")

        # kontrola atributu argumentu
        if(len(arg.attrib) != 1):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Argument has invalid number of attributes!")

        if("type" not in arg.attrib):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid argument attribute!")

        # vymazani jiz zpracovaneho argumentu
        expectedTags.remove(arg.tag)

        # ulozeni poradi argumentu
        ordOfArgs.append(arg.tag)

        # kotrola typu jednotlivych argumentu a take existence textoveho elementu nesouciho danou hodnotu
        if(expectedTypes[int(arg.tag[3]) - 1] == "symb"):
            if(arg.attrib["type"] == "var"):
                if(arg.text == None):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing name of variable!")

                checkVar(arg.text)
            elif(arg.attrib["type"] == "nil"):
                if(arg.text == None):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing nil value!")

                checkNil(arg.text)
            elif(arg.attrib["type"] == "int"):
                if(arg.text == None):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing int value!")

                if(checkInt(arg.text) == False):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument invalid int value!")
            elif(arg.attrib["type"] == "bool"):
                if(arg.text == None):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing bool value!")

                if(checkBool(arg.text) == False):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument invalid bool value!")
            elif(arg.attrib["type"] == "string"):
                if(checkString(arg.text) == False):
                    errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument invalid string value!")
            else:
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid XML argument type!")
        elif(expectedTypes[int(arg.tag[3]) - 1] == "var"):
            if(arg.attrib["type"] != "var"):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid XML argument type!")

            if(arg.text == None):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing name of variable!")

            checkVar(arg.text)
        elif(expectedTypes[int(arg.tag[3]) - 1] == "label"):
            if(arg.attrib["type"] != "label"):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid XML argument type!")

            if(arg.text == None):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing name of label!")

            checkLabel(arg.text)
        else:
            if(arg.attrib["type"] != "type"):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid XML argument type!")

            if(arg.text == None):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "XML argument missing type value!")

            checkType(arg.text)

    return ordOfArgs

if __name__ == "__main__":
    # Promenna ridici uzavreni input souboru
    fd = None

    # zpracovani parametru z prikazove radky
    try:
        opts, args = getopt.getopt(sys.argv[1:], "",["help", "source=", "input=", "stats=", "insts", "vars"])
    except:
        errExit(errorCodes.PAR_ERR, "Invalid parameter!")

    sourceFile = None
    inputFile = None
    statsFiles = []
    statsRecords = []

    # pruchod pres jednotlive argumenty, jejich kontrola a ulozeni ziskanych hodnot
    for opt, arg in opts:
        if(opt == "--help"):
            if(len(sys.argv) != 2):
                errExit(errorCodes.PAR_ERR ,"Invalid combination of parameters!")

            print("\nThe script loads XML representations of program, inteprets this program")
            print("using input according to parameters of command line and generate output.\n")
            print("--help\t\tprint out basic info about this script")
            print("--source=file\tinput file with XML representation of source code")
            print("--input=file\tfile with inputs for interpretation of source code")
            print("--stats=file\tfile with statistics")
            print("--insts\t\trecord number of executed instructions")
            print("--vars\t\trecord number of initialized variables\n")

            sys.exit(0)

        elif(opt == "--source"):
            if(sourceFile != None):
                errExit(errorCodes.PAR_ERR ,"Multiple source files!")
            sourceFile = arg
        elif(opt == "--input"):
            if(inputFile != None):
                errExit(errorCodes.PAR_ERR ,"Multiple input files!")
            inputFile = arg
        elif(opt == "--stats"):
            if(arg == sys.argv[0]):
                errExit(errorCodes.PAR_ERR ,"This script does not want to be rewrite!")
            statsFiles.append(arg)
        elif(opt == "--insts"):
            statsRecords.append("insts")
        else:
            statsRecords.append("vars")

    # Musi byt zadan alespon jeden ze souboru se vstupnim XML ci vstupem pro interpretovany program.
    if(sourceFile == None and inputFile == None):
        errExit(errorCodes.PAR_ERR ,"Missing source and input, at least one of them have to be there!")

    # Pokud jsou zadany argumenty urcujici statistiky, musi byt zadan alespon jeden soubor pro jejich zapsani.
    if(len(statsRecords) != 0 and len(statsFiles) == 0):
        errExit(errorCodes.PAR_ERR ,"Missing stats file!")

    # Pokud nebyl zadan soubor se vstupni XML reprezentaci, je tento format ocekavan na standardnim vstupu.
    if(sourceFile == None):
        sourceFile = sys.stdin

    # prace s XML
    try:
        tree = ET.parse(sourceFile)
    except IOError:
        errExit(errorCodes.INPUT_FILE_ERR, "Can not open source file!")
    except ET.ParseError:
        errExit(errorCodes.XML_FORMAT_ERR, "Invalid XML format!")

    root = tree.getroot()

    # kontrola korene stromu a jeho atributu
    if(root.tag != "program"):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Root tag is not program!")

    if("language" not in root.attrib):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Language attribute in root is missing!")

    if(root.attrib["language"].upper() != "IPPCODE20"):
        errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid language attribute!")

    del root.attrib["language"]

    for atrb in root.attrib:
        if(atrb not in ["name", "description"]):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid root attribute!")

    # Data slouzici k naslednemu provadeni instrukci

    orderArray = []     # pole s poradim instrukci
    fncDict = dict()    # slovnik instrukci (klicem je poradi instrukce a hodnotou jeji element)
    labelDict = dict()  # slovnik navesti

    # kontrola instrukci a jejich atributu
    for XMLInstr in root:
        if(XMLInstr.tag != "instruction"):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid instruction tag!")

        if(len(XMLInstr.attrib) != 2):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Instruction has invalid number of attributes!")

        for attrib in XMLInstr.attrib:
            if(attrib not in ["order", "opcode"]):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid instruction attribute!")

        if(re.match(r'^\+?\d+$' ,XMLInstr.attrib["order"]) == None):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Instruction order has to be positive number!")

        order = int(XMLInstr.attrib["order"])

        # Instrukce musi mit cislo vetsi nez 0.
        if(order == 0):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Instruction order can not be zero!")

        # Cisla instrukci se nesmi opakovat.
        if(order in orderArray):
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Instruction order has to be unique!")

        opcode = XMLInstr.attrib["opcode"].upper()

        orderArray.append(order)

        # funkce bez argumentu
        if(opcode in ["CREATEFRAME", "PUSHFRAME", "POPFRAME", "RETURN", "BREAK", "CLEARS", "ADDS", "SUBS", "MULS", "IDIVS", "LTS", "GTS", "EQS", "ANDS", "ORS", "NOTS", "INT2CHARS", "STRI2INTS"]):
            if(len(XMLInstr) != 0):
                errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Invalid number of arguments!")

            fncDict[order] = instruction(opcode)
        # funkce s jednim argumentem var
        elif(opcode in ["DEFVAR", "POPS"]):
            checkXMLArgs(XMLInstr, 1, ["var"])
            fncDict[order] = instruction(opcode)
            fncDict[order].arg1 = argument(XMLInstr[0].text)
        # funkce s jednim argumentem label
        elif(opcode in ["CALL", "LABEL", "JUMP", "JUMPIFEQS", "JUMPIFNEQS"]):
            checkXMLArgs(XMLInstr, 1, ["label"])
            fncDict[order] = instruction(opcode)
            fncDict[order].arg1 = argument(XMLInstr[0].text)

            # sber navesti
            if(opcode == "LABEL"):
                labelName = XMLInstr[0].text

                # kontrola jejich unikatnosti
                if(labelName in labelDict):
                    errExit(errorCodes.SEMANTIC_ERR, "Label name has to be unique!")

                labelDict[labelName] = order
        # funkce s jednim argumentem symb
        elif(opcode in ["PUSHS", "WRITE", "EXIT", "DPRINT"]):
            checkXMLArgs(XMLInstr, 1, ["symb"])
            fncDict[order] = instruction(opcode)

            if(XMLInstr[0].attrib["type"] == "string" and XMLInstr[0].text == None):
                fncDict[order].arg1 = argument("")
            else:
                fncDict[order].arg1 = argument(XMLInstr[0].text)

            fncDict[order].arg1.type = XMLInstr[0].attrib["type"]
        # funkce s prvnim argumentem var a druhym symb
        elif(opcode in ["MOVE", "NOT", "INT2CHAR", "STRLEN", "TYPE"]):
            ordOfArgs = checkXMLArgs(XMLInstr, 2, ["var", "symb"])
            fncDict[order] = instruction(opcode)
            fncDict[order].arg1 = argument(XMLInstr[ordOfArgs.index("arg1")].text)

            if(XMLInstr[ordOfArgs.index("arg2")].attrib["type"] == "string" and XMLInstr[ordOfArgs.index("arg2")].text == None):
                fncDict[order].arg2 = argument("")
            else:
                fncDict[order].arg2 = argument(XMLInstr[ordOfArgs.index("arg2")].text)

            fncDict[order].arg2.type = XMLInstr[ordOfArgs.index("arg2")].attrib["type"]
        # funkce s prvnim argumentem var a druhym type
        elif(opcode == "READ"):
            ordOfArgs = checkXMLArgs(XMLInstr, 2, ["var", "type"])
            fncDict[order] = instruction(opcode)
            fncDict[order].arg1 = argument(XMLInstr[ordOfArgs.index("arg1")].text)
            fncDict[order].arg2 = argument(XMLInstr[ordOfArgs.index("arg2")].text)
        # funkce s prvnim argumentem var a druhym a tretim symb
        elif(opcode in ["ADD", "SUB", "MUL", "IDIV", "LT", "GT", "EQ", "AND", "OR", "STRI2INT", "CONCAT", "GETCHAR", "SETCHAR"]):
            ordOfArgs = checkXMLArgs(XMLInstr, 3, ["var", "symb", "symb"])
            fncDict[order] = instruction(opcode)
            fncDict[order].arg1 = argument(XMLInstr[ordOfArgs.index("arg1")].text)

            if(XMLInstr[ordOfArgs.index("arg2")].attrib["type"] == "string" and XMLInstr[ordOfArgs.index("arg2")].text == None):
                fncDict[order].arg2 = argument("")
            else:
                fncDict[order].arg2 = argument(XMLInstr[ordOfArgs.index("arg2")].text)

            fncDict[order].arg2.type = XMLInstr[ordOfArgs.index("arg2")].attrib["type"]

            if(XMLInstr[ordOfArgs.index("arg3")].attrib["type"] == "string" and XMLInstr[ordOfArgs.index("arg3")].text == None):
                fncDict[order].arg3 = argument("")
            else:
                fncDict[order].arg3 = argument(XMLInstr[ordOfArgs.index("arg3")].text)

            fncDict[order].arg3.type = XMLInstr[ordOfArgs.index("arg3")].attrib["type"]
        # funkce s prvnim argumentem label a druhym a tretim symb
        elif(opcode in ["JUMPIFEQ", "JUMPIFNEQ"]):
            ordOfArgs = checkXMLArgs(XMLInstr, 3, ["label", "symb", "symb"])
            fncDict[order] = instruction(opcode)
            fncDict[order].arg1 = argument(XMLInstr[ordOfArgs.index("arg1")].text)

            if(XMLInstr[ordOfArgs.index("arg2")].attrib["type"] == "string" and XMLInstr[ordOfArgs.index("arg2")].text == None):
                fncDict[order].arg2 = argument("")
            else:
                fncDict[order].arg2 = argument(XMLInstr[ordOfArgs.index("arg2")].text)

            fncDict[order].arg2.type = XMLInstr[ordOfArgs.index("arg2")].attrib["type"]

            if(XMLInstr[ordOfArgs.index("arg3")].attrib["type"] == "string" and XMLInstr[ordOfArgs.index("arg3")].text == None):
                fncDict[order].arg3 = argument("")
            else:
                fncDict[order].arg3 = argument(XMLInstr[ordOfArgs.index("arg3")].text)

            fncDict[order].arg3.type = XMLInstr[ordOfArgs.index("arg3")].attrib["type"]
        else:
            errExit(errorCodes.XML_STRUCT_LEX_SYNTAX_ERR, "Unknown operation code!")

    # nastaveni vstupu pro pripadne cteni
    if(inputFile != None):
        try:
            fd = open(inputFile)
        except:
            errExit(errorCodes.INPUT_FILE_ERR, "Can not open input file!")

        sys.stdin = fd

    # usporadani instrukci podle poradi
    orderArray.sort()

    # provadeni programu
    numOfExecInstr = 0
    numOfDefVars = 0

    frames = dict()
    frames["GF"] = dict()
    frames["LF"] = None
    frames["TF"] = None

    frameStack = []
    dataStack = []
    callStack = []

    i = 0

    while(i < len(orderArray)):

        # aktualni instrukce
        instr = fncDict[orderArray[i]]

        # vytvori docasny ramec
        if(instr.opcode == "CREATEFRAME"):
            frames["TF"] = dict()
        # ramec docasny se stava ramcem lokalnim
        elif(instr.opcode == "PUSHFRAME"):
            if(frames["TF"] == None):
                errExit(errorCodes.NONEXISTENT_FRAME, "Temporary frame does not exist!")

            frameStack.append(frames["TF"])
            frames["LF"] = frames["TF"]
            frames["TF"] = None
        # lokalni ramec je presunut do docasneho ramce
        elif(instr.opcode == "POPFRAME"):
            if(frames["LF"] == None):
                errExit(errorCodes.NONEXISTENT_FRAME, "Local frame does not exist!")

            frames["TF"] = frames["LF"]
            frameStack.pop()

            if(len(frameStack) == 0):
                frames["LF"] == None
            else:
                frames["LF"] = frameStack.pop()
                frameStack.append(frames["LF"])
        # navrat za misto volani
        elif(instr.opcode == "RETURN"):
            if(len(callStack) == 0):
                errExit(errorCodes.MISSING_VALUE, "Call stack is empty!")

            i = callStack.pop()
        # vypis stavu interpretu na standardni chybovy vystup
        elif(instr.opcode == "BREAK"):
            line = i + 1

            printToStderr("\n\ninstruction number: " + str(line))
            printToStderr("instruction order: " + str(orderArray[i]))
            printToStderr("number of executed instructions: " + str(numOfExecInstr) + "\n\n")

            printToStderr("GLOBAL FRAME CONTENT(variable|type|value)")
            printToStderr("-----------------------------------------")
            printFrameStderr("GF", frames)
            printToStderr("\n")

            printToStderr("LOCAL FRAME CONTENT(variable|type|value)")
            printToStderr("----------------------------------------")

            if(frames["LF"] == None):
                printToStderr("Frame does not exit.")
            else:
                printFrameStderr("LF", frames)

            printToStderr("\n")

            printToStderr("TEMPORARY FRAME CONTENT(variable|type|value)")
            printToStderr("--------------------------------------------")

            if(frames["TF"] == None):
                printToStderr("Frame does not exit.")
            else:
                printFrameStderr("TF", frames)

            printToStderr("\n")
        # Smaze cely obsah datoveho zasobniku.
        elif(instr.opcode == "CLEARS"):
            while(len(dataStack) > 0):
                dataStack.pop()
        # Vybere z datoveho zasobniku dve hodnoty, secte je a vysledek ulozi na vrchol zasobniku.
        elif(instr.opcode == "ADDS"):
            value2 = int(getDStackEl(dataStack, "int"))
            value1 = int(getDStackEl(dataStack, "int"))

            result = value1 + value2

            dataStack.append(dataStackEl("int", result))
        # Vybere z datoveho zasobniku dve hodnoty, od prvni odecte druhou a vysledek vrati na vrchol zasobniku.
        elif(instr.opcode == "SUBS"):
            value2 = int(getDStackEl(dataStack, "int"))
            value1 = int(getDStackEl(dataStack, "int"))

            result = value1 - value2

            dataStack.append(dataStackEl("int", result))
        # Vybere z datoveho zasobniku dve hodnoty, vynasobi je a vysledek ulozi na vrchol zasobniku.
        elif(instr.opcode == "MULS"):
            value2 = int(getDStackEl(dataStack, "int"))
            value1 = int(getDStackEl(dataStack, "int"))

            result = value1 * value2

            dataStack.append(dataStackEl("int", result))
        # Vybere z datoveho zasobniku dve hodnoty, prvni vydeli druhou a vysledek ulozi na vrchol zasobniku.
        elif(instr.opcode == "IDIVS"):
            value2 = int(getDStackEl(dataStack, "int"))
            value1 = int(getDStackEl(dataStack, "int"))

            if(value2 == 0):
                errExit(errorCodes.BAD_OPERAND_VALUE, "Division by zero!")

            result = value1 // value2

            dataStack.append(dataStackEl("int", result))
        # Vybere z datoveho zasobniku dve hodnoty a zjisti, zdali je prvni z nich mensi nez druha.
        elif(instr.opcode == "LTS"):
            type2, value2 = getDStackElWType(dataStack)

            if(type2 == "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

            value1 = getDStackEl(dataStack, type2)

            if(type2 == "int"):
                value2 = int(value2)
                value1 = int(value1)

            if(value1 < value2):
                dataStack.append(dataStackEl("bool", "true"))
            else:
                dataStack.append(dataStackEl("bool", "false"))
        # Vybere z datoveho zasobniku dve hodnoty a zjisti, zdali je prvni z nich vetsi nez druha.
        elif(instr.opcode == "GTS"):
            type2, value2 = getDStackElWType(dataStack)

            if(type2 == "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

            value1 = getDStackEl(dataStack, type2)

            if(type2 == "int"):
                value2 = int(value2)
                value1 = int(value1)

            if(value1 > value2):
                dataStack.append(dataStackEl("bool", "true"))
            else:
                dataStack.append(dataStackEl("bool", "false"))
        # Vybere z datoveho zasobniku dve hodnoty a zjisti, zdali jsou stejne.
        elif(instr.opcode == "EQS"):
            type2, value2 = getDStackElWType(dataStack)
            type1, value1 = getDStackElWType(dataStack)

            if(type1 == type2):
                if(type1 == "int"):
                    value1 = int(value1)
                    value2 = int(value2)

                if(value1 == value2):
                    dataStack.append(dataStackEl("bool", "true"))
                else:
                    dataStack.append(dataStackEl("bool", "false"))
            elif(type1 == "nil" or type2 == "nil"):
                dataStack.append(dataStackEl("bool", "false"))
            else:
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
        # Vybere z datoveho zasobniku dve hodnoty a aplikuje na ne logickou konjunkci.
        elif(instr.opcode == "ANDS"):
            value2 = getDStackEl(dataStack, "bool")
            value1 = getDStackEl(dataStack, "bool")

            if(value1 == "true" and value2 == "true"):
                dataStack.append(dataStackEl("bool", "true"))
            else:
                dataStack.append(dataStackEl("bool", "false"))
        # Vybere z datoveho zasobniku dve hodnoty a aplikuje na ne logickou disjunkci.
        elif(instr.opcode == "ORS"):
            value2 = getDStackEl(dataStack, "bool")
            value1 = getDStackEl(dataStack, "bool")

            if(value1 == "true" or value2 == "true"):
                dataStack.append(dataStackEl("bool", "true"))
            else:
                dataStack.append(dataStackEl("bool", "false"))
        # Vybere z datoveho zasobniku hodnotu, zneguje ji a ulozi opet na zasobnik.
        elif(instr.opcode == "NOTS"):
            value = getDStackEl(dataStack, "bool")

            if(value == "true"):
                dataStack.append(dataStackEl("bool", "false"))
            else:
                dataStack.append(dataStackEl("bool", "true"))
        # Vybere z datoveho zasobniku ciselnou hodnotu a prevede ji na UNICODE znak.
        elif(instr.opcode == "INT2CHARS"):
            value = int(getDStackEl(dataStack, "int"))

            try:
                dataStack.append(dataStackEl("string", chr(value)))
            except:
                errExit(errorCodes.STRING_ERR, "Invalid ordinal value of character in UNICODE!")
        # Vybere z datoveho zasobniku dve hodnoty a ulozi na jeho vrchol ordinalni hodnotu znaku na urcite pozici v retezci.
        elif(instr.opcode == "STRI2INTS"):
            value2 = int(getDStackEl(dataStack, "int"))
            value1 = dealWithEscape(getDStackEl(dataStack, "string"))

            if(value2 < 0 or value2 >= len(value1)):
                errExit(errorCodes.STRING_ERR, "Index out of range!")

            dataStack.append(dataStackEl("int", ord(value1[value2])))
        # definice promenne v danem ramci
        elif(instr.opcode == "DEFVAR"):
            var = instr.arg1.value.split('@')

            if(not frameExist(var[0], frames)):
                errExit(errorCodes.NONEXISTENT_FRAME, "Frame does not exist!")
            elif(varInFrame(var[1], var[0], frames)):
                errExit(errorCodes.SEMANTIC_ERR, "Redefinition of variable!")
            else:
                frames[var[0]][var[1]] = variable(var[1], None, None)

            numOfDefVars += 1
        # Vyjme hodnotu z vrcholu datoveho zasobniku a ulozi ji do promenne.
        elif(instr.opcode == "POPS"):
            if(len(dataStack) == 0):
                errExit(errorCodes.MISSING_VALUE, "Data stack is empty!")
            else:
                var = instr.arg1.value.split('@')
                checkVarExistance(var[1], var[0], frames)

                dataEl = dataStack.pop()

                frames[var[0]][var[1]].varType = dataEl.elType
                frames[var[0]][var[1]].value = dataEl.value
        # skok na zadanou pozici s ulozenym navratem
        elif(instr.opcode == "CALL"):
            if(instr.arg1.value not in labelDict):
                errExit(errorCodes.SEMANTIC_ERR, "Undefined label!")

            callStack.append(i)
            i = orderArray.index(labelDict[instr.arg1.value]) - 1
        # oznaceni navesti, vse vyreseno pred interpretaci
        elif(instr.opcode == "LABEL"):
            pass
        # skok bez navratu
        elif(instr.opcode == "JUMP"):
            if(instr.arg1.value not in labelDict):
                errExit(errorCodes.SEMANTIC_ERR, "Undefined label!")

            i = orderArray.index(labelDict[instr.arg1.value]) - 1
        # Zasobnikova verze podmineneho skoku, ktery se vykona, pokud se hodnoty a typy operandu na datovem zasobniku rovnaji.
        elif(instr.opcode == "JUMPIFEQS"):
            if(instr.arg1.value not in labelDict):
                errExit(errorCodes.SEMANTIC_ERR, "Undefined label!")

            type2, value2 = getDStackElWType(dataStack)
            type1, value1 = getDStackElWType(dataStack)

            if(type1 == type2):
                if(type1 == "int"):
                    value1 = int(value1)
                    value2 = int(value2)

                if(value1 == value2):
                    i = orderArray.index(labelDict[instr.arg1.value]) - 1
            elif(type1 != "nil" and type2 != "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
        # Zasobnikova verze podmineneho skoku, ktery se vykona, pokud se hodnoty nebo typy operandu na datovem zasobniku nerovnaji.
        elif(instr.opcode == "JUMPIFNEQS"):
            if(instr.arg1.value not in labelDict):
                errExit(errorCodes.SEMANTIC_ERR, "Undefined label!")

            type2, value2 = getDStackElWType(dataStack)
            type1, value1 = getDStackElWType(dataStack)

            if(type1 == type2):
                if(type1 == "int"):
                    value1 = int(value1)
                    value2 = int(value2)

                if(value1 != value2):
                    i = orderArray.index(labelDict[instr.arg1.value]) - 1
            elif(type1 != "nil" and type2 != "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
            else:
                i = orderArray.index(labelDict[instr.arg1.value]) - 1
        # Ulozi hodnotu na datovy zasobnik.
        elif(instr.opcode == "PUSHS"):
            if(instr.arg1.type == "var"):
                var = instr.arg1.value.split('@')
                checkVarExistance(var[1], var[0], frames)
                checkVarInit(var[1], var[0], frames)

                dataStack.append(dataStackEl(frames[var[0]][var[1]].varType, frames[var[0]][var[1]].value))
            else:
                dataStack.append(dataStackEl(instr.arg1.type, instr.arg1.value))
        # Vypise hodnotu na standardni vytup.
        elif(instr.opcode == "WRITE"):
            if(instr.arg1.type == "var"):
                var = instr.arg1.value.split('@')
                checkVarExistance(var[1], var[0], frames)
                checkVarInit(var[1], var[0], frames)

                dataType = frames[var[0]][var[1]].varType
                value = frames[var[0]][var[1]].value
            else:
                dataType = instr.arg1.type
                value = instr.arg1.value

            if(dataType == "int"):
                print(int(value), end = '')
            elif(dataType == "bool"):
                print(value, end = '')
            elif(dataType == "string"):
                print(dealWithEscape(value), end = '')
            else:
                print("", end = '')
        # Ukonci interpretaci s navratovym kodem.
        elif(instr.opcode == "EXIT"):
            if(instr.arg1.type == "var"):
                var = instr.arg1.value.split('@')
                checkVarExistance(var[1], var[0], frames)
                checkVarInit(var[1], var[0], frames)

                if(frames[var[0]][var[1]].varType != "int"):
                    errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

                value = int(frames[var[0]][var[1]].value)
            else:
                if(instr.arg1.type != "int"):
                    errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

                value = int(instr.arg1.value)

            if(value < 0 or value > 49):
                errExit(errorCodes.BAD_OPERAND_VALUE, "Invalid operand value!")

            if(len(statsFiles) != 0):
                writeStats(statsFiles, statsRecords, numOfExecInstr + 1, numOfDefVars)

            closeFile()
            sys.exit(value)
        # Vypise zadanou hodnotu na standardni chybovy vystup.
        elif(instr.opcode == "DPRINT"):
            if(instr.arg1.type == "var"):
                var = instr.arg1.value.split('@')
                checkVarExistance(var[1], var[0], frames)
                checkVarInit(var[1], var[0], frames)

                dataType = frames[var[0]][var[1]].varType
                value = frames[var[0]][var[1]].value
            else:
                dataType = instr.arg1.type
                value = instr.arg1.value

            if(dataType == "int"):
                print(int(value), end = '', file = sys.stderr)
            elif(dataType == "bool"):
                print(value, end = '', file = sys.stderr)
            elif(dataType == "string"):
                print(dealWithEscape(value), end = '', file = sys.stderr)
            else:
                print("", end = '', file = sys.stderr)
        # Zkopiruje hodnotu 2. argumentu do promenne v 1. argumentu.
        elif(instr.opcode == "MOVE"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            dataType, value = getArg2WType(instr, frames)

            frames[var[0]][var[1]].varType = dataType
            frames[var[0]][var[1]].value = value
        # Aplikuje negaci na bool hodnotu v 2. argumentu a vysledek zapise do promenne v 1. argumentu.
        elif(instr.opcode == "NOT"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value = getArg2(instr, frames, "bool")

            if(value == "true"):
                value = "false"
            else:
                value = "true"

            frames[var[0]][var[1]].varType = "bool"
            frames[var[0]][var[1]].value = value
        # prevod ciselne hodnoty na UNICODE znak
        elif(instr.opcode == "INT2CHAR"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value = int(getArg2(instr, frames, "int"))

            try:
                frames[var[0]][var[1]].value = chr(value)
            except:
                errExit(errorCodes.STRING_ERR, "Invalid ordinal value of character in UNICODE!")

            frames[var[0]][var[1]].varType = "string"
        # Zjisti delku retezce a ulozi ji do promenne.
        elif(instr.opcode == "STRLEN"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value = getArg2(instr, frames, "string")
            strLen = len(dealWithEscape(value))

            frames[var[0]][var[1]].varType = "int"
            frames[var[0]][var[1]].value = strLen
        # Zjisti typ symbolu a zapise ho do promenne.
        elif(instr.opcode == "TYPE"):
            var1 = instr.arg1.value.split('@')
            checkVarExistance(var1[1], var1[0], frames)

            if(instr.arg2.type == "var"):
                var2 = instr.arg2.value.split('@')
                checkVarExistance(var2[1], var2[0], frames)

                if(frames[var2[0]][var2[1]].varType == None):
                    value = ""
                else:
                    value = frames[var2[0]][var2[1]].varType
            else:
                value = instr.arg2.type

            frames[var1[0]][var1[1]].varType = "string"
            frames[var1[0]][var1[1]].value = value
        # Nacte hodnotu dle zadaneho typu a ulozi ji do promenne.
        elif(instr.opcode == "READ"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            dataType = instr.arg2.value

            try:
                value = input()
            except:
                dataType = "nil"

            if(dataType == "int"):
                try:
                    value = int(value)
                except:
                    dataType == "nil"
            elif(dataType == "bool"):
                value = value.lower()

                if(value != "true"):
                    value = "false"

            if(dataType == "nil"):
                value = "nil"

            frames[var[0]][var[1]].varType = dataType
            frames[var[0]][var[1]].value = value
        # Secte dva symboly a vyslednou hodnotu ulozi do promenne.
        elif(instr.opcode == "ADD"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = int(getArg2(instr, frames, "int"))
            value2 = int(getArg3(instr, frames, "int"))

            result = value1 + value2

            frames[var[0]][var[1]].varType = "int"
            frames[var[0]][var[1]].value = result
        # Odecte symbol 2 od symbolu 1 a vysledek ulozi do promenne.
        elif(instr.opcode == "SUB"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = int(getArg2(instr, frames, "int"))
            value2 = int(getArg3(instr, frames, "int"))

            result = value1 - value2

            frames[var[0]][var[1]].varType = "int"
            frames[var[0]][var[1]].value = result
        # Vynasobi dva symboly a vysledek ulozi do promenne.
        elif(instr.opcode == "MUL"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = int(getArg2(instr, frames, "int"))
            value2 = int(getArg3(instr, frames, "int"))

            result = value1 * value2

            frames[var[0]][var[1]].varType = "int"
            frames[var[0]][var[1]].value = result
        # Celociselne vydeli hodnotu symb 1 hodnotou symb 2 a vysledek ulozi do promenne.
        elif(instr.opcode == "IDIV"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = int(getArg2(instr, frames, "int"))
            value2 = int(getArg3(instr, frames, "int"))

            if(value2 == 0):
                errExit(errorCodes.BAD_OPERAND_VALUE, "Division by zero!")

            result = value1 // value2

            frames[var[0]][var[1]].varType = "int"
            frames[var[0]][var[1]].value = result
        # Zjisti, zdali je hodnota symbolu 1 mensi nez hodnota symbolu 2.
        elif(instr.opcode == "LT"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            type1, value1 = getArg2WType(instr, frames)

            if(type1 == "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

            value2 = getArg3(instr, frames, type1)

            if(type1 == "int"):
                value1 = int(value1)
                value2 = int(value2)

            if(value1 < value2):
                frames[var[0]][var[1]].value = "true"
            else:
                frames[var[0]][var[1]].value = "false"

            frames[var[0]][var[1]].varType = "bool"
        # Zjisti, zdali je hodnota symbolu 1 vetsi nez hodnota symbolu 2.
        elif(instr.opcode == "GT"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            type1, value1 = getArg2WType(instr, frames)

            if(type1 == "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

            value2 = getArg3(instr, frames, type1)

            if(type1 == "int"):
                value1 = int(value1)
                value2 = int(value2)

            if(value1 > value2):
                frames[var[0]][var[1]].value = "true"
            else:
                frames[var[0]][var[1]].value = "false"

            frames[var[0]][var[1]].varType = "bool"
        # Zjisti, zdali je hodnota symbolu 1 stejna jako hodnota symbolu 2.
        elif(instr.opcode == "EQ"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            type1, value1 = getArg2WType(instr, frames)
            type2, value2 = getArg3WType(instr, frames)

            frames[var[0]][var[1]].value = "false"

            if(type1 == type2):
                if(type1 == "int"):
                    value1 = int(value1)
                    value2 = int(value2)

                if(value1 == value2):
                    frames[var[0]][var[1]].value = "true"
            elif(type1 != "nil" and type2 != "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

            frames[var[0]][var[1]].varType = "bool"
        # Aplikuje konjunkci na operandy a vysledek ulozi do promenne.
        elif(instr.opcode == "AND"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = getArg2(instr, frames, "bool")
            value2 = getArg3(instr, frames, "bool")

            if(value1 == "true" and value2 == "true"):
                frames[var[0]][var[1]].value = "true"
            else:
                frames[var[0]][var[1]].value = "false"

            frames[var[0]][var[1]].varType = "bool"
        # Aplikuje disjunkci na operandy a vysledek ulozi do promenne.
        elif(instr.opcode == "OR"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = getArg2(instr, frames, "bool")
            value2 = getArg3(instr, frames, "bool")

            if(value1 == "true" or value2 == "true"):
                frames[var[0]][var[1]].value = "true"
            else:
                frames[var[0]][var[1]].value = "false"

            frames[var[0]][var[1]].varType = "bool"
        # Ulozi do promenne ordinalni hodnotu znaku na urcite pozici v retezci.
        elif(instr.opcode == "STRI2INT"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = dealWithEscape(getArg2(instr, frames, "string"))
            value2 = int(getArg3(instr, frames, "int"))

            if(value2 < 0 or value2 >= len(value1)):
                errExit(errorCodes.STRING_ERR, "Index out of range!")

            frames[var[0]][var[1]].varType = "int"
            frames[var[0]][var[1]].value = ord(value1[value2])
        # Ulozi do promenne konkatenaci dvou retezcovych operandu.
        elif(instr.opcode == "CONCAT"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = getArg2(instr, frames, "string")
            value2 = getArg3(instr, frames, "string")

            result = value1 + value2

            frames[var[0]][var[1]].varType = "string"
            frames[var[0]][var[1]].value = result
        # Ulozi do promenne znak na urcite pozici v retezci.
        elif(instr.opcode == "GETCHAR"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)

            value1 = dealWithEscape(getArg2(instr, frames, "string"))
            value2 = int(getArg3(instr, frames, "int"))

            if(value2 < 0 or value2 >= len(value1)):
                errExit(errorCodes.STRING_ERR, "Index out of range!")

            frames[var[0]][var[1]].varType = "string"
            frames[var[0]][var[1]].value = value1[value2]
        # Zmeni znak na urcite pozici v retezci.
        elif(instr.opcode == "SETCHAR"):
            var = instr.arg1.value.split('@')
            checkVarExistance(var[1], var[0], frames)
            checkVarInit(var[1], var[0], frames)

            if(frames[var[0]][var[1]].varType != "string"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")

            editStr = dealWithEscape(frames[var[0]][var[1]].value)
            value1 = int(getArg2(instr, frames, "int"))
            value2 = dealWithEscape(getArg2(instr, frames, "string"))

            if(len(value2) == 0):
                errExit(errorCodes.STRING_ERR, "Replacement is empty!")

            if(value1 < 0 or value1 >= len(editStr)):
                errExit(errorCodes.STRING_ERR, "Index out of range!")

            editStr[value1] = value2[0]
            frames[var[0]][var[1]].value = editStr
        # Skok na navesti, pokud se hodnoty zbyvajicich dvou operandu rovnaji.
        elif(instr.opcode == "JUMPIFEQ"):
            if(instr.arg1.value not in labelDict):
                errExit(errorCodes.SEMANTIC_ERR, "Undefined label!")

            type1, value1 = getArg2WType(instr, frames)
            type2, value2 = getArg3WType(instr, frames)

            if(type1 == type2):
                if(type1 == "int"):
                    value1 = int(value1)
                    value2 = int(value2)

                if(value1 == value2):
                    i = orderArray.index(labelDict[instr.arg1.value]) - 1
            elif(type1 != "nil" and type2 != "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
        # Skok na navesti, pokud jsou hodnoty zbyvajicich dvou operandu ruzne.
        else:
            if(instr.arg1.value not in labelDict):
                errExit(errorCodes.SEMANTIC_ERR, "Undefined label!")

            type1, value1 = getArg2WType(instr, frames)
            type2, value2 = getArg3WType(instr, frames)

            if(type1 == type2):
                if(type1 == "int"):
                    value1 = int(value1)
                    value2 = int(value2)

                if(value1 != value2):
                    i = orderArray.index(labelDict[instr.arg1.value]) - 1
            elif(type1 != "nil" and type2 != "nil"):
                errExit(errorCodes.BAD_OPERAND_TYPE, "Incorrect operand type!")
            else:
                i = orderArray.index(labelDict[instr.arg1.value]) - 1

        numOfExecInstr += 1
        i += 1

    closeFile()

    # vypis statistik do souboru
    if(len(statsFiles) != 0):
        writeStats(statsFiles, statsRecords, numOfExecInstr, numOfDefVars)

    sys.exit(0)