import asyncio

from pyrogram import filters

# from NekoRobot import DRAGONS, pbot as app

import NekoRobot.modules.mongo.dalc_mongo as sql
from NekoRobot.modules.disable import (
    DisableAbleCommandHandler,
    DisableAbleMessageHandler,
)
from NekoRobot import pgram as app
from telegram.ext import CallbackContext, Filters, MessageHandler
from telegram import MessageEntity, Update
from NekoRobot.ex_plugins.dbfunctions import(
    alpha_to_int,
    get_karma,
    # get_karmas,
    int_to_alpha,
    update_karma,
)

from NekoRobot.pyro.errors import capture_err
from NekoRobot.utils.filter_groups import karma_negative_group, karma_positive_group

regex_upvote = r"^((?i)\+|\+\+|\+1|thx|thanx|thanks|pro|cool|good|pro|pero|op|nice|noice|best|uwu|owo|right|correct|peru|piro|👍|\+100)$"
regex_downvote = r"^(\-|\-\-|\-1|👎|noob|baka|idiot|chutiya|nub|noob|wrong|incorrect|chaprii|chapri|weak|\-100)$"

@app.on_message(
  filters.text
  & filters.group
  & filters.incoming
  & filters.reply
  & filters.regex(regex_upvote)
  & ~filters.via_bot
  & ~filters.bot,
  group=karma_positive_group,
)
async def upvote(_,message):
#   chat_id = message.chat.id
#   is_karma = sql.is_karma(chat_id)
#   if not is_karma:
#         return
  if not message.reply_to_message.from_user:
        return
  if not message.from_user:
        return
  if message.reply_to_message.from_user.id == message.from_user.id:
        return
  user_id = message.reply_to_message.from_user.id
  user_mention = message.reply_to_message.from_user.mention
  current_karma = await get_karma(await int_to_alpha(user_id)
    )
  if current_karma:
        current_karma = current_karma['karma']
        karma = current_karma + 100
  else:
        karma = 100
  new_karma = {"karma": karma}
  await update_karma(await int_to_alpha(user_id), new_karma
    )
  await message.reply_text(
        f"Waku Waku! Anya added 100 dalcs to {user_mention}'s Wallet\nCurrent Dalcs: {karma}Đ"
    )

@app.on_message(
    filters.text
    & filters.group
    & filters.incoming
    & filters.reply
    & filters.regex(regex_downvote)
    & ~filters.via_bot
    & ~filters.bot,
    group=karma_negative_group,
)

async def downvote(_, message):
    # chat_id = message.chat.id
    # is_karma = sql.is_karma(chat_id)
    # if not is_karma:
    #     return
    if not message.reply_to_message.from_user:
        return
    if not message.from_user:
        return
    if message.reply_to_message.from_user.id == message.from_user.id:
        return

    user_id = message.reply_to_message.from_user.id
    user_mention = message.reply_to_message.from_user.mention
    current_karma = await get_karma(await int_to_alpha(user_id))
    if current_karma:
        current_karma = current_karma["karma"]
        karma = current_karma - 100
    else:
        karma = 100
    new_karma = {"karma": karma}
    await update_karma(await int_to_alpha(user_id), new_karma)
    await message.reply_text(
        f"Anya is Sad :( took 100 dalcs from {user_mention}'s Wallet\nCurrent Dalcs: {karma}Đ"
    )

@app.on_message(filters.command("dalcstat") & filters.group)
async def karma(_, message):
    # chat_id = message.chat.id
    if not message.reply_to_message:
        m = await message.reply_text("Matte! Anya will ask chichi for wallets of this chat...")
        # karma = await get_karmas(chat_id)
        # if not karma:
        #     await m.edit("Anya is Sad. No Dalcs in DB for this chat.")
        #     return
        msg = f"Dalc list of {message.chat.title}:- \n"
        limit = 0
        karma_dicc = {}
        for i in karma:
            user_id = await alpha_to_int(i)
            user_karma = karma[i]["karma"]
            karma_dicc[str(user_id)] = user_karma
            karma_arranged = dict(
                sorted(karma_dicc.items(), key=lambda item: item[1], reverse=True)
            )
        if not karma_dicc:
            await m.edit("Anya is Sad. No Dalcs in DB for this chat.")
            return
        for user_idd, karma_count in karma_arranged.items():
            if limit > 9:
                break
            try:
                user = await app.get_users(int(user_idd))
                await asyncio.sleep(0.8)
            except Exception:
                continue
            first_name = user.first_name
            if not first_name:
                continue
            username = user.username
            msg += f"{karma_count}  {(first_name[0:12] + '...') if len(first_name) > 12 else first_name}  {('@' + username) if username else user_idd}\n"
            limit += 1
        await m.edit(msg)
    else:
        user_id = message.reply_to_message.from_user.id
        karma = await get_karma(await int_to_alpha(user_id))
        karma = karma["karma"] if karma else 0
        await message.reply_text(f"Total Dalcs: {karma} Đ")

# @app.on_message(filters.command("dalcstat") & filters.group)
# async def mywallet(_, message):
#     chat_id = message.chat.id
#     user_id = message.reply_to_message.from_user.id
#     karma = await get_karma(chat_id, await int_to_alpha(user_id))
#     karma = karma["karma"] if karma else 0
#     await message.reply_text(f"Total Dalcs: {karma}Đ")

# KARMA_REGEX_HANDLER = DisableAbleMessageHandler(
#       filters.text
#     & filters.group
#     & filters.incoming
#     & filters.reply
#     & filters.regex(regex_downvote)
#     & ~filters.via_bot
#     & ~filters.bot,
#     group=karma_negative_group
# )

 # ❍ Reply to any meassage with (`+, +1, thx, thanx, thanks, pro, cool, good,pro, pero, op, nice, noice, best, uwu, owo, right, correct, peru, piro`, 👍) to increse karma of user.
 # ❍ Reply to any meassage with (`-, -1, 👎, noob, baka, idiot, chutiya, nub, noob, wrong, incorrect, chaprii, chapri, weak`) to decrease karma of user.

__mod_name__ = "Currency System"

__help__ = """
Currency System[Dalc(Đ)]
 ❍ `/dalc` : To enable / disable Currency system
 ❍ `/dalcstat`: Get stats of waller for your chat
 ❍ Reply message with (`+, +100) to add dalcs to there Wallet.
 ❍ Reply message with (`-, -100`) to snitch dalcs from there Wallet.
"""


import os
import ntpath
import refinery
import tkinter as tk

from pathlib import PureWindowsPath
from traceback import format_exc

from mozzarilla.widgets.directory_frame import HierarchyFrame
from refinery.constants import MAX_TAG_NAME_LEN, BAD_CLASSES,\
     H1_TAG_SUPERCLASSES
from refinery.util import int_to_fourcc, is_reserved_tag
from refinery.windows.actions_window import RefineryActionsWindow

from supyr_struct.defs.frozen_dict import FrozenDict

no_op = lambda *a, **kw: None

def _ensure_backslash_for_folder(folder_path):
    '''
    Directories must end with a backslash for them to be identified as
    directories in the ExplorerHierarchyTree.
    '''
    return str(folder_path).rstrip('\\') + '\\'

TREE_SORT_METHODS = FrozenDict(
    {0: "name", 4:"pointer", 5:"pointer", 6:"index_id"})

class ExplorerHierarchyTree(HierarchyFrame):
    active_map = None
    tags_tree = None
    valid_classes = None

    tree_id_to_index_ref = None

    queue_tree = None
    sibling_tree_frames = None
    sort_by = "name"
    reverse_sorted = False

    def __init__(self, *args, **kwargs):
        self.queue_tree = kwargs.pop('queue_tree', self.queue_tree)
        self.tree_id_to_index_ref = {}
        kwargs.setdefault('select_mode', 'extended')
        self.sibling_tree_frames = kwargs.pop('sibling_tree_frames', {})

        HierarchyFrame.__init__(self, *args, **kwargs)
        self.tags_tree.bind('<Return>', self.activate_item)
        self.tags_tree.bind('<Button-1>', self.set_sort_mode)

    def set_sort_mode(self, event):
        if self.tags_tree.identify_region(event.x, event.y) != "heading":
            return
        column = int(self.tags_tree.identify_column(event.x)[1:])
        new_sort = TREE_SORT_METHODS.get(column)
        if new_sort is None:
            return
        elif new_sort == self.sort_by:
            self.reverse_sorted = not self.reverse_sorted
        else:
            self.reverse_sorted = False

        self.sort_by = new_sort
        self.reload(self.active_map)

    def sort_index_refs(self, index_refs):
        if isinstance(index_refs, dict):
            index_refs = index_refs.keys()

        sortable_index_refs = []
        for b in index_refs:
            tag_path_key = self.get_tag_tree_key(b)
            if tag_path_key is not None:
                sortable_index_refs.append((tag_path_key, b))

        new_sorting = {}
        if self.sort_by == "index_id":
            for index_ref in sortable_index_refs:
                new_sorting.setdefault(
                    index_ref[1].id & 0xFFff, []).append(index_ref)
        elif self.sort_by == "pointer":
            for index_ref in sortable_index_refs:
                new_sorting.setdefault(
                    index_ref[1].meta_offset, []).append(index_ref)
        else:
            # default to sorting by name
            for index_ref in sortable_index_refs:
                new_sorting.setdefault(
                    index_ref[0], []).append(index_ref)

        sorted_index_refs = []
        for key in sorted(new_sorting):
            for index_ref in new_sorting[key]:
                sorted_index_refs.append(index_ref)

        if self.reverse_sorted:
            return list(reversed(sorted_index_refs))

        return sorted_index_refs

    def setup_columns(self):
        tags_tree = self.tags_tree
        if not tags_tree['columns']:
            # dont want to do this more than once
            tags_tree['columns'] = ('class1', 'class2', 'class3',
                                    'magic', 'pointer', 'index_id')
            tags_tree.heading("#0", text='name')
            tags_tree.heading("class1", text='class 1')
            tags_tree.heading("class2", text='class 2')
            tags_tree.heading("class3", text='class 3')
            tags_tree.heading("magic",  text='pointer(MEM)')
            tags_tree.heading("pointer", text='pointer(FILE)')
            tags_tree.heading("index_id",  text='index id')

            tags_tree.column("#0", minwidth=100, width=200)
            tags_tree.column("class1", minwidth=5, width=45, stretch=False)
            tags_tree.column("class2", minwidth=5, width=10, stretch=False)
            tags_tree.column("class3", minwidth=5, width=10, stretch=False)
            tags_tree.column("magic",  minwidth=5, width=12, stretch=False)
            tags_tree.column("pointer", minwidth=5, width=70, stretch=False)
            tags_tree.column("index_id", minwidth=5, width=50, stretch=False)

    def reload(self, active_map=None):
        self.active_map = active_map
        tags_tree = self.tags_tree
        tree_id_to_index_ref = self.tree_id_to_index_ref
        self.setup_columns()

        # remove any currently existing children
        for child in tags_tree.get_children():
            tags_tree.delete(child)
            tree_id_to_index_ref.pop(child, None)

        if active_map is not None:
            # generate the hierarchy
            # TODO: Do a profile of this to determine where the bottleneck
            #       is, as it's taking much longer to reload now.
            self.add_tag_index_refs(active_map.tag_index.tag_index)

    def _compile_list_of_selected(self, parent, selected=None):
        if selected is None:
            selected = []

        tags_tree = self.tags_tree
        tree_id_to_index_ref = self.tree_id_to_index_ref
        for iid in tags_tree.get_children(parent):
            if len(tags_tree.item(iid, 'values')):
                # tag_index_ref
                selected.append(tree_id_to_index_ref[int(iid)])
            else:
                # directory
                self._compile_list_of_selected(iid, selected)

        return selected

    def activate_all(self, e=None):
        tags_tree = self.tags_tree
        if self.active_map is None:
            return

        if self.queue_tree is None:
            return
        elif ("halo2" in self.active_map.engine and
              self.active_map.engine != "halo2vista"):
            print("Cannot interact with Halo 2 Xbox maps.")
            return

        def_settings = {}
        if self.app_root:
            def_settings = dict(self.app_root.tk_vars)
            if self.app_root.running:
                return

        map_name = self.active_map.map_header.map_name

        # ask for extraction settings
        settings, _, __ = self.show_actions_dialog(
            "", renamable=False, title=map_name, defaults=def_settings)

        if settings['accept_settings'].get():
            settings['tag_index_refs'] = self._compile_list_of_selected("")
            settings['title'] = map_name
            self.queue_tree.add_to_queue("%s: %s: %s" % (
                settings['extract_mode'].get(), self.active_map.engine,
                map_name), settings)

    def activate_item(self, e=None):
        tags_tree = self.tags_tree
        tree_id_to_index_ref = self.tree_id_to_index_ref
        if self.active_map is None or self.queue_tree is None:
            return
        elif ("halo2" in self.active_map.engine and
              self.active_map.engine != "halo2vista"):
            print("Cannot interact with Halo 2 Xbox maps.")
            return

        def_settings = {}
        if self.app_root:
            def_settings = dict(self.app_root.tk_vars)
            if self.app_root.running:
                return

        map_name = self.active_map.map_header.map_name
        # add selection to queue
        for iid in tags_tree.selection():
            if len(tags_tree.item(iid, 'values')):
                # tag_index_ref
                item_name = tags_tree.parent(iid) + tags_tree.item(iid, 'text')
                tag_index_ref = tree_id_to_index_ref[int(iid)]
                tag_index_refs = (tag_index_ref, )
            else:
                # directory
                item_name = iid
                tag_index_ref = None
                tag_index_refs = self._compile_list_of_selected(iid)

            # ask for extraction settings
            settings, original_name, title = self.show_actions_dialog(
                item_name, defaults=def_settings, tag_index_ref=tag_index_ref)

            if settings['accept_rename'].get():
                item_name = str(PureWindowsPath(
                    tags_tree.parent(iid),
                    tags_tree.item(iid, 'text')).with_suffix(""))

                self.rename_tag_index_refs(
                    tag_index_refs, original_name,
                    settings['rename_string'].get(),
                    settings['newtype_string'].get())
            elif settings['accept_settings'].get():
                settings['tag_index_refs'] = tag_index_refs
                settings['title'] = title
                self.queue_tree.add_to_queue(
                    "%s: map: %s: %s" % (
                        settings['extract_mode'].get(),
                        map_name, item_name), settings)

    def show_actions_dialog(self, item_name, **kwargs):
        defaults = kwargs.pop("defaults", {})

        kwargs.setdefault('title', item_name)

        settings_vars = dict(
            recursive=tk.IntVar(self), overwrite=tk.IntVar(self),
            do_printout=tk.IntVar(self), accept_rename=tk.IntVar(self),
            autoload_resources=tk.IntVar(self), decode_adpcm=tk.IntVar(self),
            bitmap_extract_keep_alpha=tk.IntVar(self),
            generate_comp_verts=tk.IntVar(self), generate_uncomp_verts=tk.IntVar(self),
            accept_settings=tk.IntVar(self), out_dir=tk.StringVar(self),
            extract_mode=tk.StringVar(self, "tags"), halo_map=self.active_map,
            rename_string=tk.StringVar(self), newtype_string=tk.StringVar(self),
            tagslist_path=tk.StringVar(self), allow_corrupt=tk.IntVar(self),
            skip_seen_tags_during_queue_processing=tk.IntVar(self),
            disable_safe_mode=tk.IntVar(self), disable_tag_cleaning=tk.IntVar(self),

            bitmap_extract_format=tk.StringVar(self),
            globals_overwrite_mode=tk.StringVar(self),
            )

        settings_vars['rename_string'].set(
            defaults.pop('name_string', item_name))

        for k in defaults:
            if k in settings_vars:
                settings_vars[k].set(defaults[k].get())

        dir_type = defaults.get("extract_mode").get() + "_dir"
        if dir_type in defaults:
            settings_vars["out_dir"].set(defaults[dir_type].get())

        w = RefineryActionsWindow(self, settings=settings_vars, **kwargs)
        original_name, title = str(w.original_name), w.title()

        # make the tree freeze until the settings ask window is done
        self.wait_window(w)

        return settings_vars, original_name, title

    def rename_tag_index_refs(self, index_refs, old_basename,
                              new_basename, new_cls, rename_other_trees=True):
        if self.active_map is None: return

        old_basename = old_basename.lower()
        new_basename = new_basename.lower()

        tags_tree = self.tags_tree
        map_magic = self.active_map.map_magic
        tree_id_to_index_ref = self.tree_id_to_index_ref

        child_items = []
        renamed_index_refs = []
        renaming_multiple = len(index_refs) > 1
        if renaming_multiple:
            new_cls = None

        if (old_basename == new_basename) and not new_cls:
            return

        for index_ref in index_refs:
            tag_cls_val = index_ref.class_1.data
            tag_id      = index_ref.id & 0xFFff
            if not map_magic:
                # resource cache tag
                tag_id = index_ref.id
            if new_cls:
                try:
                    tag_cls_val = index_ref.class_1.get_value(new_cls)
                except Exception:
                    new_cls = None

            # when renaming only one tag, the basenames COULD BE the full names
            old_name = str(PureWindowsPath(index_ref.path.lower()))
            new_name = old_name.replace(old_basename, new_basename, 1)
            if not old_name.startswith(old_basename):
                # tag_path doesnt have the base_name in it
                continue
            elif not tags_tree.exists(tag_id):
                # tag not in the tree
                continue
            elif not new_name:
                print("Cannot rename '%s' to an empty string." % old_name)
                continue
            elif index_ref.indexed:
                print("Cannot rename indexed tag: %s" % old_name)
                continue
            elif len(new_name) > MAX_TAG_NAME_LEN:
                print("'%s' is too long to use as a tagpath" % new_name)
                continue

            # make sure a tag with that name doesnt already exist
            already_exists = False
            for child_id in tags_tree.get_children(tags_tree.parent(tag_id)):
                try: child_id = int(child_id)
                except ValueError: continue

                sibling_index_ref = tree_id_to_index_ref.get(child_id)
                if not sibling_index_ref:
                    # sibling is being edited. no worry
                    continue
                elif sibling_index_ref is index_ref:
                    # this is the thing we're renaming. no worry
                    continue
                elif tag_cls_val != sibling_index_ref.class_1.data:
                    # classes are different. no worry
                    continue
                elif sibling_index_ref.path != new_name:
                    # names are different. no worry
                    continue
                already_exists = True
                break

            if already_exists:
                print("'%s' already exists in map. Cannot rename." % new_name)
                continue

            if rename_other_trees:
                index_ref.path = new_name
                try:
                    old_cls = index_ref.class_1.enum_name
                except Exception:
                    old_cls = None

                if new_cls and new_cls != old_cls:
                    index_ref.class_1.set_to(new_cls)
                    cls_2, cls_3 = H1_TAG_SUPERCLASSES.get(new_cls, ("NONE", "NONE"))
                    index_ref.class_2.set_to(cls_2)
                    index_ref.class_3.set_to(cls_3)

            # add this child to the list to be removed
            child_items.append(tag_id)
            tree_id_to_index_ref.pop(tag_id, None)
            renamed_index_refs.append(index_ref)

        # remove the highest parent with only 1 child from the tree.
        for child in child_items:
            while len(tags_tree.get_children(tags_tree.parent(child))) <= 1:
                # only one or less children. can be deleted
                child = tags_tree.parent(child)
            tags_tree.delete(child)

        # add the newly named tags back to the tree
        self.add_tag_index_refs(renamed_index_refs)

        if not rename_other_trees:
            return

        for tree in self.sibling_tree_frames.values():
            if tree is not self and hasattr(tree, 'rename_tag_index_refs'):
                tree.rename_tag_index_refs(renamed_index_refs, old_basename,
                                           new_basename, new_cls, False)

    def get_tag_tree_key(self, tag_index_ref):
        if (hasattr(self.valid_classes, "__iter__") and
            int_to_fourcc(tag_index_ref.class_1.data) not in self.valid_classes):
            return None

        if tag_index_ref.class_1.enum_name not in BAD_CLASSES:
            ext = ".%s" % tag_index_ref.class_1.enum_name
        else:
            ext = ".INVALID"

        return str(PureWindowsPath(tag_index_ref.path.lower())) + ext

    def add_tag_index_refs(self, index_refs):
        if self.active_map is None:
            return

        sorted_index_refs = self.sort_index_refs(index_refs)

        # add all the directories before files
        # put the directories in sorted by name
        indices_by_dirpath = {
            ntpath.dirname(block[0]): i
            for i, block in enumerate(sorted_index_refs)
            }
        for dir_path in sorted(indices_by_dirpath):
            b = sorted_index_refs[indices_by_dirpath[dir_path]][1]
            if not is_reserved_tag(b):
                self.add_folder_path(PureWindowsPath(dir_path).parts)

        for tag_path, tag_index_ref in sorted_index_refs:
            if is_reserved_tag(tag_index_ref):
                continue

            tag_path = PureWindowsPath(tag_path)
            self.add_tag_index_ref(
                tag_path.parent.parts, tag_path.name, tag_index_ref)

    def add_tag_index_ref(self, parent_dir_parts, tag_path, tag_index_ref):
        tag_id = tag_index_ref.id & 0xFFff
        if not self.active_map.map_magic:
            # resource cache tag
            tag_id = tag_index_ref.id

        pointer_converter = self.active_map.map_pointer_converter
        if hasattr(self.active_map, "bsp_pointer_converters"):
            pointer_converter = self.active_map.bsp_pointer_converters.get(
                tag_id, pointer_converter)

        is_h1_rsrc_map = (self.active_map.is_resource and
                          self.active_map.engine in (
                              "halo1pcdemo", "halo1pc",
                              "halo1ce", "halo1yelo"))

        if tag_index_ref.indexed and pointer_converter and not is_h1_rsrc_map:
            pointer = "not in map"
        elif pointer_converter is not None:
            pointer = '%08X' % pointer_converter.v_ptr_to_f_ptr(
                tag_index_ref.meta_offset)
        else:
            pointer = 0

        meta_offset = '%08X' % tag_index_ref.meta_offset

        try:
            cls1 = cls2 = cls3 = ""
            if tag_index_ref.class_1.enum_name not in BAD_CLASSES:
                cls1 = int_to_fourcc(tag_index_ref.class_1.data)
            if tag_index_ref.class_2.enum_name not in BAD_CLASSES:
                cls2 = int_to_fourcc(tag_index_ref.class_2.data)
            if tag_index_ref.class_3.enum_name not in BAD_CLASSES:
                cls3 = int_to_fourcc(tag_index_ref.class_3.data)

            parent_iid = self.add_folder_path(parent_dir_parts)
            self.tags_tree.insert(
                # NEED TO DO str OR ELSE THE SCENARIO TAG'S ID WILL
                # BE INTERPRETED AS NOTHING AND BE CHANGED TO 'I001'
                parent_iid, 'end', iid=str(tag_id),
                tags=("item", ), text=tag_path,
                values=(cls1, cls2, cls3,
                        meta_offset, pointer, '%04X' % tag_id))
            self.tree_id_to_index_ref[tag_id] = tag_index_ref
        except Exception:
            print(format_exc())

    def add_folder_path(self, dir_parts):
        abs_dir_path = str(PureWindowsPath(*dir_parts))
        if abs_dir_path:
            abs_dir_path = _ensure_backslash_for_folder(abs_dir_path)

        if self.tags_tree.exists(abs_dir_path):
            return abs_dir_path

        return self._add_folder_path(list(dir_parts), '')

    def _add_folder_path(self, dir_parts, parent_dir):
        if not dir_parts:
            return parent_dir

        this_dir = dir_parts.pop(0)
        if not this_dir:
            return parent_dir

        abs_dir_path = parent_dir + this_dir
        if abs_dir_path:
            abs_dir_path = _ensure_backslash_for_folder(abs_dir_path)

        if not self.tags_tree.exists(abs_dir_path):
            # add the directory to the treeview
            self.tags_tree.insert(
                parent_dir, 'end', iid=abs_dir_path,
                tags=("item", ), text=this_dir)

        return self._add_folder_path(dir_parts, abs_dir_path)

    open_selected = close_selected = no_op

    set_root_dir = add_root_dir = insert_root_dir = del_root_dir = no_op

    destroy_subitems = no_op

    get_item_tags_dir = highlight_tags_dir = no_op


import xmlrpc.client
import sys
from multiprocessing import Pool
from time import sleep
from hashlib import sha1
from random import randint

NUM_PROCESSES = 6
# MAX_SEED = abs(~(1 << 31))
MAX_SEED = 2147483647

def getTransactionID(proxy: xmlrpc.client.ServerProxy, _: int) -> int:
    transactionID = proxy.getTransactionID()
    print(f"\nTransação atual: {transactionID}")
    return transactionID

def getChallenge(proxy: xmlrpc.client.ServerProxy, transactionID: int) -> int:
    challenge = proxy.getChallenge(transactionID)
    print(f"\nChallenge da transação {transactionID}: {challenge}")
    return challenge

def getTransactionStatus(proxy: xmlrpc.client.ServerProxy, transactionID: int):
    challenge = proxy.getChallenge(transactionID)
    print(f"\nStatus da transação {transactionID}: {challenge}")
    return challenge

def getWinner(proxy: xmlrpc.client.ServerProxy, transactionID: int):
    winner = proxy.getWinner(transactionID)
    print(f"\nVencedor da transação {transactionID}: {winner}")
    return winner

def getSeed(proxy: xmlrpc.client.ServerProxy, transactionID: int) -> tuple[int, int, int]:
    seed = proxy.getSeed(transactionID)
    if not seed[0]:
        print(f"\nA transação {transactionID} tem status {seed[0]}, seed {seed[1]} e challenge {seed[2]}\n")
    else:
        print(f"\nA transação {transactionID} ainda não foi resolvida")

    return seed

def check_seed(seed: int, challenge: int) -> int:
    byte_seed = seed.to_bytes(8, "little")
    sha1_bytes = sha1(byte_seed).hexdigest()
    target_bits = challenge
    solution_bits = int(sha1_bytes, 16) >> (160-target_bits)

    return int(solution_bits == 0)

def solve_challenge(challenge: int) -> int:
    while True:
        seed = randint(0, MAX_SEED)
        if check_seed(seed, challenge):
            return seed

def minerar(proxy: xmlrpc.client.ServerProxy, _: int) -> None:
    curr_trans = getTransactionID(proxy, _)
    challenge = getChallenge(proxy, curr_trans)

    # Challenges menores que 20 são mais rápidos que o overhead do paralelismo
    if challenge < 20:
        solution = solve_challenge(challenge)
    else:
        with Pool(processes=NUM_PROCESSES) as pool:
            processes = []
            for _ in range(NUM_PROCESSES):
                proc = pool.apply_async(solve_challenge, args=(challenge,))
                processes.append(proc)

            # processes = [
            #     pool.apply_async(solve_challenge, args=(challenge,))
            #     for _ in range(NUM_PROCESSES)
            # ]

            solved = False
            while not solved:
                sleep(1)
                for proc in processes:
                    if proc.ready():
                        solution = proc.get()
                        solved = True
                        break

    print(f"Seed encontrada que resolve o challenge: {solution}")
    pong = proxy.submitChallenge(curr_trans, 666, solution)

    if   pong ==  1: print(f"A seed {solution} resolveu o challenge!")
    elif pong ==  0: print(f"A seed {solution} não resolve o challenge")
    elif pong == -1: print(f"A TransactionID {curr_trans} é inválida")
    elif pong ==  2: print(f"A TransactionID {curr_trans} já fora resolvida")
    else:            print(f"Algo de errado definitivamente não está certo")

if __name__ == "__main__":
    # Nº de argumentos
    n = len(sys.argv)
    assert n==3, f"Uso correto: {sys.argv[0]} <host> <port>"

    # Conexão com o servidor
    rpcServerAddr = f"http://{sys.argv[1]}:{sys.argv[2]}/"
    proxy = xmlrpc.client.ServerProxy(rpcServerAddr)

    function_table = {
        1: minerar,
        2: getTransactionID,
        3: getChallenge,
        4: getTransactionStatus,
        5: getWinner,
        6: getSeed
    }

    menu_str = (
        "\nMENU\n"
        "Escolha o número equivalente a função que você quer rodar:\n\n"
        "1 - Minerar\n"
        "2 - getTransactionID\n"
        "3 - getChallenge\n"
        "4 - getTransactionStatus\n"
        "5 - getWinner\n"
        "6 - getSeed\n"
        "> "
    )

    input_tid = "Digite qual TransactionID você deseja buscar:\n> "

    tid = 0
    while True:
        opt = int(input(menu_str))
        assert (0 < opt < 7), "Opção inválida"

        if 2 < opt: tid = int(input(input_tid))

        function_table[opt](proxy, tid)


from django.http import HttpResponse, JsonResponse
from django.contrib.auth import get_user_model
from django.db.models import Sum
from django.shortcuts import render, redirect
from django.utils import timezone
import re
from .models import *
from users.models import Subscriber, Moderator
from posts.models import *

def index(request, subreddit_title):

    try:
        subreddit = Subreddit.objects.get(title=subreddit_title)
    except:
        return HttpResponse("Subreddit Does Not Exist")

    num_subscribers = subscribersCount(subreddit)
    moderators = getModerators(subreddit)
    ismoderator = request.user in moderators or request.user.is_staff
    assignedmod = request.user in moderators
    if request.user.is_authenticated():
        subscribed = checkSubscribed(request.user, subreddit)
        posts = feed(subreddit, request.user)
        events = getEvents(subreddit, request.user)
    else:
        posts = feed(subreddit)
        events = getEvents(subreddit)
        subscribed = False

    return render(request, "subreddit.html", {"subreddit" : subreddit, "posts" : posts,
                                              "num_subscribers" : num_subscribers, "subscribed" : subscribed,
                                              "moderators" : moderators, "ismoderator" : ismoderator,
                                              "assignedmod" : assignedmod, "events" : events})

def popularSubreddits(num=5, user = None):

    subreddits = list(Subreddit.objects.all())
    if(user != None):
        subreddits = [subreddit for subreddit in subreddits if not checkSubscribed(user,subreddit)]
    return sorted(subreddits, key = lambda s: subscribersCount(s), reverse=True)[:num]

def feed(subreddit, user = None):

    posts = []

    for p in LinkPost.objects.filter(posted_in = subreddit, deleted=False).extra(select={'num_votes' : 0, 'num_comments' : 0, 'type' : '%s', 'vote' : 0},
                                    select_params=('link',)):
        posts.append(updatePostFeatures(p, user))

    for p in TextPost.objects.filter(posted_in = subreddit, deleted=False).extra(select = {'num_votes' : 0, 'num_comments' : 0, 'type' : '%s', 'vote' : 0},
                                    select_params = ('text',)):
        posts.append(updatePostFeatures(p, user))

    return sorted(posts, key = lambda p: p.num_votes, reverse=True)

def getEvents(subreddit, user=None):

    events = []

    for e in Event.objects.filter(posted_in=subreddit):
        if timezone.now() < e.time and not e.deleted:
            events.append(updatePostFeatures(e, user))

    return sorted(events, key=lambda e: e.time)

def subscribersCount(subreddit):

    return Subscriber.objects.filter(subreddit=subreddit).count()

def getModerators(subreddit):

    qs = Moderator.objects.filter(subreddit=subreddit)
    mods = []
    for m in qs:
        mods.append(m.redditer)
    return mods

def checkSubscribed(user, subreddit):
    if Subscriber.objects.filter(redditer=user, subreddit=subreddit).exists():
        return True
    else:
        return False

def addSubredditForm(request):
    if request.user.is_authenticated():
        return render(request, "newsubreddit.html")
    else:
        return HttpResponse("Login to post!")

def addSubreddit(request):

    if request.method == 'GET':
        return redirect('index')
    subreddit_title = request.POST['title']
    if not validate_title(subreddit_title):
        return JsonResponse({'success' : False, 'Error' : "Subreddit Title should contain only A-Za-z0-9_"})

    description = request.POST['description']

    if not request.user.is_authenticated() :
        return HttpResponse("Login to add a new subreddit!")

    # some conditions for allowing to make a new subreddit

    if Subreddit.objects.filter(title=subreddit_title).exists():
        return JsonResponse({'success' : False, 'Error' : "Subreddit Already Exists"})

    subreddit = Subreddit(title=subreddit_title, description=description)
    subreddit.save()

    mod = Moderator(redditer=request.user, subreddit=subreddit)
    mod.save()

    return JsonResponse({'success' : True, 'Message' : "Added Subreddit", "title" : subreddit.title})

def subscribe(request):

    if request.method == 'GET':
        return redirect('index')

    subreddit_title = request.POST['subreddit']

    if not request.user.is_authenticated():
        return HttpResponse("Login to subscribe!")

    try:
        subreddit = Subreddit.objects.get(title=subreddit_title)
    except:
        return JsonResponse({'success' : False, 'Error' : "Subreddit Does not exist"})

    qs = Subscriber.objects.filter(redditer = request.user, subreddit=subreddit)

    if qs.count() == 0:
        subs = Subscriber(redditer=request.user, subreddit=subreddit)
        subs.save()

    return JsonResponse({'success' : True})

def unsubscribe(request):

    if request.method == 'GET':
        return redirect('index')
    subreddit_title = request.POST['subreddit']
    if not request.user.is_authenticated():
        return JsonResponse({'success' : False, 'Error' : "Login to subscribe!"})

    try:
        subreddit = Subreddit.objects.get(title=subreddit_title)
    except:
        return JsonResponse({'success' : False, 'Error' : "Subreddit Does not exist"})

    qs = Subscriber.objects.filter(redditer = request.user, subreddit=subreddit)

    if qs.count() > 0:
        qs.delete()

    return JsonResponse({'success' : True})

def addModerator(request):
    if request.method == 'GET':
        return redirect('index')

    subreddit_title = request.POST['subreddit']
    newmod_username = request.POST['username']

    try:
        newmod = get_user_model().objects.get(username=newmod_username)
    except:
        return JsonResponse({'success' : False, 'Error' : "User does not exist"})

    try:
        subreddit = Subreddit.objects.get(title=subreddit_title)
    except:
        return JsonResponse({'success' : False, 'Error' : "Subreddit Does not exist"})

    moderators = getModerators(subreddit)

    if not request.user.is_authenticated():
        return JsonResponse({'success' : False, 'Error' : "Login to add!"})
    elif not request.user in moderators and not request.user.is_staff:
        return JsonResponse({'success' : False, 'Error' : "Only current mods can add a new mod!"})
    elif newmod in moderators:
        return JsonResponse({'success' : False, 'Error' : "Already a mod!"})

    m = Moderator(redditer=newmod, subreddit=subreddit)
    m.save()

    return JsonResponse({'success' : True})

def delModerator(request):
    if request.method == 'GET':
        return redirect('index')

    subreddit_title = request.POST['subreddit']

    try:
        subreddit = Subreddit.objects.get(title=subreddit_title)
    except:
        return JsonResponse({'success' : False, 'Error' : "Subreddit Does not exist"})

    moderators = getModerators(subreddit)

    if not request.user.is_authenticated():
        return JsonResponse({'success' : False, 'Error' : "Login to add!"})
    elif not request.user in moderators:
        return JsonResponse({'success' : False, 'Error' : "Not a Mod!"})

    if len(moderators) == 1:
        if(not assignNewModerator(subreddit, request.user)):
            return JsonResponse({'success': False, 'Error': "Only Subscriber can't leave!"})

    qs = Moderator.objects.get(redditer=request.user, subreddit=subreddit)
    qs.delete()

    return JsonResponse({'success' : True})

def getPostKarma(user, userPosts):
    karma = 0
    for p in userPosts:
        karma += p.num_votes
    return karma

def assignNewModerator(subreddit, resign_user):
    subscribers = Subscriber.objects.filter(subreddit=subreddit)
    subredditPosts = feed(subreddit)
    maxKarma = 0
    newmod = None
    for subs in subscribers:
        if subs.redditer != resign_user:
            userPosts = [p for p in subredditPosts if p.posted_by == subs.redditer]
            karma = getPostKarma(subs.redditer,userPosts)
            if(maxKarma < karma):
                newmod = subs.redditer
                maxKarma = karma
            if newmod is None:
                newmod = subs.redditer

    if newmod is None:
        return False
    else:
        m = Moderator(redditer=newmod, subreddit=subreddit)
        m.save()
    return True

def validate_title(username):
    return re.compile('[A-Za-z0-9_]+$').match(username)

def updatePostFeatures(post, user=None):

    post.num_votes = Vote.objects.filter(voted_on__id = post.id).aggregate(votes = Sum('value')).get('votes')

    post.num_comments = numComments(post)

    if post.num_votes == None:
        post.num_votes = 0

    if user is not None:

        qs = Vote.objects.filter(voted_on__id = post.id, voted_by = user)
        if len(qs) > 0:
            post.vote = qs[0].value

    return post

def numComments(post):

    num = 0
    qs = Comment.objects.filter(commented_on = post)
    num += qs.count()
    for c in qs:
        num += numComments(c)
    return num


from django.shortcuts import render
from django.shortcuts import get_object_or_404 #çok basit ve tatlı obje varsa objeye götürüyor yoksa 404 sayfasına
from django.http import Http404 # hata olunca   kullanmak için Http404 hatasını import ediyoruz
from .models import Brainstrom
from django.contrib import messages
# Create your views here.

def index(request):
    if request.user.is_authenticated: #sonuna parantez koymayınca çalıştı

        if request.method == 'POST':
            #usernamesinialır şşuanki kullanıcnın
            #print(User.get_username())
            #https://stackoverflow.com/questions/16906515/how-can-i-get-the-username-of-the-logged-in-user-in-django
            #burdan buldum alltakini
            """
            def my_view(request):
                username = None
                if request.user.is_authenticated(): #parantezler olmayınca daha iyi çalıştı
                    username = request.user.username
            """
            username2 = request.user.username#ŞU ANKİ KULLANICININ İSMİNİ ALMA İŞLEMİ

            description2 = request.POST['description']

            Brainstrom.objects.create(name = username2 ,description= description2)

        brainstrom = Brainstrom.objects.filter( baglanti = None)
        brainstrom =brainstrom[::-1] #bu şekilde en son yazan en son geliyor listeyi ters çevirdim işte
        context = {
            'brainstrom' : brainstrom
        }
        return render(request,'brainstrom/brainstrom.html',context)

    else:
        messages.add_message(request , messages.WARNING ,'Bu sayfayı görebilmek için giriş yapmalısınız.Giriş yapabilmek için ise kayıt olmalısınız.')

        return render(request,'user/register.html')

def rush(request,rush_id): #burda rush id yi belirttim pk yi rush_id ye eşitledm

#BURDA ÇOK PROBLEM YAŞADIM PROBLEMİM  BU YANIT YAZMAK İÇİN OLAN YERDE form action için bir id yollamıyor olmam

    if request.user.is_authenticated:

        if request.method == 'POST':

            username3 = request.user.username
            description3 = request.POST['descriptionRush']
            Brainstrom.objects.create(name = username3 ,description = description3 , baglanti = rush_id )
        else:
            if  Brainstrom.objects.filter( baglanti = rush_id).exists() == False:
                username3 = 'else'
                description3 = 'else'
                Brainstrom.objects.create(name = username3 ,description = description3 , baglanti = rush_id )
        brainstrom = get_object_or_404(Brainstrom , pk = rush_id)

        rush = Brainstrom.objects.filter( baglanti = rush_id)
        rush = rush[::-1]

        context = {'rush': rush,
        'brainstrom' : brainstrom,
                    }
        return render(request,'brainstrom/rush.html',context)

    else:
        messages.add_message(request , messages.WARNING ,'Bu sayfayı görebilmek için giriş yapmalısınız.Giriş yapabilmek için ise kayıt olmalısınız.')

        return render(request,'user/register.html')

def search(request):
    return render(request,'brainstrom/search.html')


#!/usr/bin/env/python
import os
import glob
import logging

import numpy as np
import pandas as pd
import cv2
import yaml

import _utils as ikea_utils
from mathtools import utils, transformations

AXIS_LEN_WORLD = 0.1  # m

RGB = ((255, 0, 0),
       (0, 255, 0),
       (0, 0, 255))
CYM = ((0, 255, 255),
       (255, 0, 255),
       (255, 255, 0))

logger = logging.getLogger(__name__)

def readFrameFns(fn, names_as_int=False):
    frame_fns = pd.read_csv(fn, header=None).iloc[:, 0].tolist()

    if names_as_int:
        frame_fns = np.array([int(fn.strip('.png').strip('frame')) for fn in frame_fns])

    return frame_fns

def drawAxes(img, origin, axis_endpoints, axis_colors=None, label=None):
    if axis_colors is None:
        axis_colors = (
            (255, 0, 0),
            (0, 255, 0),
            (0, 0, 255)
        )

    for i, endpoint in enumerate(axis_endpoints):
        img = cv2.line(img, tuple(origin.ravel()), tuple(endpoint.ravel()), axis_colors[i], 5)

    if label is not None:
        bottom_left_corner = (origin - np.array([-10, 10])).ravel()
        font_scale = 1
        white = (255, 255, 255)
        thickness = 1
        cv2.putText(
            img, label, tuple(bottom_left_corner),
            cv2.FONT_HERSHEY_DUPLEX, font_scale, white, thickness
        )

    return img

def markerFrameToWorldFrame(marker_position, marker_orientation_quat, marker_points=None):
    if marker_points is None:
        marker_points = np.array(
            [[0, 0, 0],
             [1, 0, 0],
             [0, 1, 0],
             [0, 0, 1]],
            dtype=float
        ) * AXIS_LEN_WORLD

    # quaternion_matrix returns a matrix in homogeneous coordinates
    marker_orientation_mat = transformations.quaternion_matrix(marker_orientation_quat)[:3, :3]

    # orientation_world operates on column vectors, so transpose when we apply
    # it to an array of row vectors
    world_points = np.dot(marker_points, marker_orientation_mat.T) + marker_position

    return world_points

def quantizePoints(points, image_shape):
    quantized = points.astype(int)

    image_height, image_width = image_shape
    quantized[quantized < 0] = 0
    quantized[quantized[:, 0] > image_height, 0] = image_height
    quantized[quantized[:, 1] > image_width, 1] = image_width

    return quantized

def cameraParamsToCv2(camera_params):
    intrinsics = camera_params['intrinsics']
    cv2_intrinsics = {
        'K': np.array(intrinsics['K']),
        'D': np.array(intrinsics['D']),
        'image_shape': (int(intrinsics['height']), int(intrinsics['width']))
    }

    extrinsics = camera_params['extrinsics']
    r_mat = transformations.quaternion_matrix(extrinsics['orientation'])[:3, :3]
    cv2_extrinsics = {
        't_vec': np.array(extrinsics['position']),
        'r_vec': cv2.Rodrigues(r_mat)[0]
    }

    cv2_params = {'intrinsics': cv2_intrinsics, 'extrinsics': cv2_extrinsics}
    return cv2_params

def getFrameFns(sample_frame_idxs, camera_frame_fns):
    camera_frame_index = {}
    for camera_name, cur_frame_index in sample_frame_idxs.iteritems():
        stored_frame_index = camera_frame_index.get(camera_name, None)
        if stored_frame_index is None:
            camera_frame_index[camera_name] = cur_frame_index
        elif stored_frame_index != cur_frame_index:
            raise AssertionError()

    camera_frame_fns = {
        camera_name: camera_frame_fns[camera_name][frame_index]
        for camera_name, frame_index in camera_frame_index.items()
    }

    return camera_frame_fns

def loadFrames(camera_frame_fns, frames_dir, video_id):
    def loadFrame(camera_name, frame_fn):
        cur_video_dir = os.path.join(frames_dir, "{0}_{1}_cam".format(video_id, camera_name))
        frame = cv2.imread(os.path.join(cur_video_dir, frame_fn))
        if frame is None:
            raise AssertionError()
        return frame

    camera_frames = {
        camera_name: loadFrame(camera_name, frame_fn)
        for camera_name, frame_fn in camera_frame_fns.items()
    }

    return camera_frames

def projectAxes(marker_position, marker_orientation, intrinsics, extrinsics):
    # Make origin and axis endpoints from p, q
    axis_points_world = markerFrameToWorldFrame(marker_position, marker_orientation)
    axis_points_px, _ = cv2.projectPoints(
        axis_points_world,
        extrinsics['r_vec'], extrinsics['t_vec'],
        intrinsics['K'], intrinsics['D']
    )
    # FIXME: I don't know why projectPoints returns an array with dimensions
    #   (num_points, 1, num_img_dims(==2)) --- maybe to represent
    #   each coord explicitly as a row vector?
    axis_points_px = axis_points_px.squeeze()

    # Cast to int and project into image dims
    axis_points_px = quantizePoints(axis_points_px, intrinsics['image_shape'])

    origin_px = axis_points_px[0, :]
    axis_endpoints_px = axis_points_px[1:, :]

    return origin_px, axis_endpoints_px

def main(out_dir=None, data_dir=None, frames_dir=None, metadata_parent_dir=None, start_from=None):
    data_dir = os.path.expanduser(data_dir)
    frames_dir = os.path.expanduser(frames_dir)
    out_dir = os.path.expanduser(out_dir)
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)

    if metadata_parent_dir is not None:
        metadata_parent_dir = os.path.join(metadata_parent_dir)

    logger = utils.setupRootLogger(filename=os.path.join(out_dir, 'log.txt'))

    pose_dir = os.path.join(data_dir, 'poses')
    sample_frame_idx_dir = os.path.join(data_dir, 'frame-indices')

    for i, video_dir in enumerate(glob.glob(os.path.join(pose_dir, '*'))):
        if start_from is not None and i < start_from:
            continue

        video_id = os.path.basename(os.path.normpath(video_dir))

        logger.info("VISUALIZING VIDEO {0}: {1}".format(i, video_id))

        out_video_dir = os.path.join(out_dir, 'images', video_id)
        if not os.path.exists(out_video_dir):
            os.makedirs(out_video_dir)

        if metadata_parent_dir is None:
            metadata_dir = os.path.join(video_dir, 'metadata')
        else:
            metadata_dir = os.path.join(metadata_parent_dir, video_id, 'metadata')

        camera_params, bundle_topics, camera_frame_fns = ikea_utils.readMetadata(metadata_dir)

        sample_frame_idxs = pd.read_csv(
            os.path.join(sample_frame_idx_dir, f"{video_id}.csv")
        ).astype(int)

        camera_params = {
            camera_name: cameraParamsToCv2(params)
            for camera_name, params in camera_params.items()
        }

        # First, load all the marker poses into memory
        prev_shape = None
        camera_marker_poses = {}
        for file_path in glob.glob(os.path.join(video_dir, '*.csv')):
            part_name = ikea_utils.basename(file_path)
            pose_seq = pd.read_csv(file_path).to_numpy()
            camera_marker_poses[part_name] = pose_seq

            # Make sure all pose sequences have the same shape
            if prev_shape is not None and pose_seq.shape != prev_shape:
                warn_fmt_str = 'Pose shapes differ: {0} != {1} (truncating to shortest)'
                logger.warning(warn_fmt_str.format(pose_seq.shape, prev_shape))
            if prev_shape is None or pose_seq.shape[0] < prev_shape[0]:
                prev_shape = pose_seq.shape

        num_pose_samples = prev_shape[0]
        camera_marker_poses = {
            key: pose_seq[:num_pose_samples, :]
            for key, pose_seq in camera_marker_poses.items()
        }

        for sample_index in range(num_pose_samples):
            frame_idxs = sample_frame_idxs.iloc[sample_index, :]
            sample_frame_fns = getFrameFns(frame_idxs, camera_frame_fns)
            try:
                sample_frames = loadFrames(sample_frame_fns, frames_dir, video_id)
            except AssertionError:
                continue

            marker_samples = {
                key: pose_seq[sample_index, :]
                for key, pose_seq in camera_marker_poses.items()
            }
            for part_name, sample in marker_samples.items():
                if np.isnan(sample).any():
                    continue

                # Draw each marker's pose to every frame
                for camera_name in sample_frames.keys():
                    intrinsics = camera_params[camera_name]['intrinsics']
                    extrinsics = camera_params[camera_name]['extrinsics']

                    marker_position = sample[:3]
                    marker_orientation = sample[3:]
                    origin_px, axis_endpoints_px = projectAxes(
                        marker_position, marker_orientation,
                        intrinsics, extrinsics
                    )
                    sample_frames[camera_name] = drawAxes(
                        sample_frames[camera_name], origin_px, axis_endpoints_px,
                        axis_colors=RGB, label=part_name
                    )

            output_frame_fn = "{0:06d}.png".format(sample_index)
            output_frame = np.vstack(tuple(sample_frames.values()))
            cv2.imwrite(os.path.join(out_video_dir, output_frame_fn), output_frame)

if __name__ == '__main__':
    cl_args = utils.parse_args(main)
    config, config_fn = utils.parse_config(cl_args, script_name=__file__)

    # Create output directory, instantiate log file and write config options
    out_dir = os.path.expanduser(config['out_dir'])
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)
    with open(os.path.join(out_dir, config_fn), 'w') as outfile:
        yaml.dump(config, outfile)
    utils.copyFile(__file__, out_dir)

    main(**config)


import cv2
import numpy as np

cap = cv2.VideoCapture(1)
image = cv2.imread("bk.jpg")

while True:
    ret, frames = cap.read()

    frames = cv2.resize(frames, (640, 480))
    image = cv2.resize(image, (640, 480))

    u_black = np.array([104, 153, 70])
    l_black = np.array([30, 30, 0])

    mask = cv2.inRange(frames, l_black, u_black)
    res = cv2.bitwise_and(frames,frames, mask = mask)

    f = frames - res
    f = np.where(f == 0, image, f)

    cv2.imshow("video", frames)
    cv2.imshow("mask", f)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()


"""
By: Severi Friman
severi.friman@gmail.com

Accelerometer data analysis.
Reads accelerometer data from a file and plots the data.
Later some analysis will be implemented.

The test data was recorded with Nokia 5.3 accelerometer with 50 Hz sampling rate.
The app usd for recording is given in the project.
The signal is 3-axis accelerometer data of chest seismography.

"""

import csv
from matplotlib import pyplot as plt
import numpy as np

def main():

    # These will contain the sensor data
    Acc_X = []
    Acc_Y = []
    Acc_Z = []
    fs = 50 # Hz

    # Lets open, read and save the data to the initialized vectors
    with open("sensors_Test1.csv", newline='') as csvfile:

        reader = csv.reader(csvfile, delimiter=',')

        for row in reader:
            if (row[0]== "X"):
                pass
            else:
                Acc_X.append(float(row[0]))
                Acc_Y.append(float(row[1]))
                Acc_Z.append(float(row[2]))

    samples_amount = len(Acc_X)
    seconds = samples_amount/fs
    increment = 1/50
    time_vector = np.arange(0,seconds,increment)

    print("############################################")
    print("#                 Messages                 #")
    print("############################################\n")

    print("Amount of samples per channel: ", samples_amount)
    print("sampling rate: ", fs ," Hz")
    print("Recording time: ", seconds , " seconds")

    plt.figure()
    ax1 = plt.subplot(3,1,1)
    plt.plot(time_vector,Acc_X)
    plt.title("X")
    plt.ylabel("Acceleration (m/s2)")
    plt.subplot(3,1,2, sharex=ax1)
    plt.plot(time_vector,Acc_Y)
    plt.title("Y")
    plt.ylabel("Acceleration (m/s2)")
    plt.subplot(3, 1, 3, sharex=ax1)
    plt.plot(time_vector, Acc_Z)
    plt.title("Z")
    plt.xlabel("Time (s)")
    plt.ylabel("Acceleration (m/s2)")
    plt.show()

main()


from functools import partial
from models.vit import VisionTransformer, interpolate_pos_embed
from models.xbert import BertConfig, BertForMaskedLM, BertModel
from models.transformer import TransformerEncoder
from models.tokenization_bert import BertTokenizer

import torch
import torch.nn.functional as F
from torch import nn

import numpy as np
import random

class SMF(nn.Module):
    def __init__(self,
                 text_encoder = None,
                 tokenizer = None,
                 fusion_encoder = None,
                 config = None,
                 temp = 0.07,
                 init_deit = True
                 ):
        super().__init__()

        self.tokenizer = tokenizer
        self.mlm_probability = config['mlm_probability']
        embed_dim = config['embed_dim']
        self.batch_size= config['batch_size']
        self.embed_dim= config['embed_dim']

        self.visual_encoder = VisionTransformer(
            img_size=config['image_res'], patch_size=16, embed_dim=768, depth=12, num_heads=12,
            mlp_ratio=4, qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6))

        if init_deit:
            checkpoint = torch.hub.load_state_dict_from_url(
                url="https://dl.fbaipublicfiles.com/deit/deit_base_patch16_224-b5f2ef4d.pth",
                map_location="cpu", check_hash=True) #检查点
            state_dict = checkpoint["model"]
            pos_embed_reshaped = interpolate_pos_embed(state_dict['pos_embed'], self.visual_encoder)
            state_dict['pos_embed'] = pos_embed_reshaped
            msg = self.visual_encoder.load_state_dict(state_dict,strict=False)
            print(msg)

        vision_width = config['vision_width']
        bert_config = BertConfig.from_json_file(config['bert_config'])
        # lou
        fusion_bert_config = BertConfig.from_json_file(config['fusion_bert_config'])

        self.text_encoder = BertModel.from_pretrained(text_encoder, config=bert_config, add_pooling_layer=False)
        self.fusion_encoder = BertForMaskedLM.from_pretrained(fusion_encoder, config=fusion_bert_config)

        text_width = self.text_encoder.config.hidden_size
        self.vision_proj = nn.Linear(vision_width, embed_dim)
        self.text_proj = nn.Linear(text_width, embed_dim)

        self.temp = nn.Parameter(torch.ones([]) * config['temp'])
        self.queue_size = config['queue_size']
        self.momentum = config['momentum']
        self.itm_head = nn.Linear(embed_dim, 2)

        # create the queue
        self.register_buffer("image_queue", torch.randn(embed_dim, self.queue_size))
        self.register_buffer("text_queue", torch.randn(embed_dim, self.queue_size))
        self.register_buffer("queue_ptr", torch.zeros(1, dtype=torch.long))

        self.image_queue = nn.functional.normalize(self.image_queue, dim=0)
        self.text_queue = nn.functional.normalize(self.text_queue, dim=0)

        self.conv1d_t = nn.Conv1d(text_width, self.embed_dim, kernel_size=1, padding=0, bias=False)
        self.conv1d_i = nn.Conv1d(vision_width, self.embed_dim, kernel_size=1, padding=0, bias=False)

        self.conv1d_t_m = nn.Conv1d(text_width, self.embed_dim, kernel_size=1, padding=0, bias=False)
        self.conv1d_i_m = nn.Conv1d(vision_width, self.embed_dim, kernel_size=1, padding=0, bias=False)

        num_heads = 16
        attn_dropout = 0.1
        relu_dropout = 0.1
        res_dropout = 0.1
        embed_dropout = 0.1
        attn_mask = 'store_false'
        layers = 4

        self.trans_iichange = TransformerEncoder(embed_dim=embed_dim,
                                                 num_heads=num_heads,
                                                 layers=layers,
                                                 attn_dropout=attn_dropout,
                                                 relu_dropout=relu_dropout,
                                                 res_dropout=res_dropout,
                                                 embed_dropout=embed_dropout,
                                                 attn_mask=attn_mask)
        self.trans_ttchange = TransformerEncoder(embed_dim=embed_dim,
                                                 num_heads=num_heads,
                                                 layers=layers,
                                                 attn_dropout=attn_dropout,
                                                 relu_dropout=relu_dropout,
                                                 res_dropout=res_dropout,
                                                 embed_dropout=embed_dropout,
                                                 attn_mask=attn_mask)
        self.ii_proj = nn.Linear(embed_dim, embed_dim)
        self.tt_proj = nn.Linear(embed_dim, embed_dim)

        # create momentum models
        self.visual_encoder_m = VisionTransformer(
            img_size=config['image_res'], patch_size=16, embed_dim=768, depth=12, num_heads=12,
            mlp_ratio=4, qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6))
        self.vision_proj_m = nn.Linear(vision_width, embed_dim)
        self.text_encoder_m = BertForMaskedLM.from_pretrained(text_encoder, config=bert_config)
        self.text_proj_m = nn.Linear(text_width, embed_dim)

        self.trans_iichange_m = TransformerEncoder(embed_dim=embed_dim,
                                                 num_heads=num_heads,
                                                 layers=layers,
                                                 attn_dropout=attn_dropout,
                                                 relu_dropout=relu_dropout,
                                                 res_dropout=res_dropout,
                                                 embed_dropout=embed_dropout,
                                                 attn_mask=attn_mask)
        self.trans_ttchange_m = TransformerEncoder(embed_dim=embed_dim,
                                                 num_heads=num_heads,
                                                 layers=layers,
                                                 attn_dropout=attn_dropout,
                                                 relu_dropout=relu_dropout,
                                                 res_dropout=res_dropout,
                                                 embed_dropout=embed_dropout,
                                                 attn_mask=attn_mask)
        self.ii_proj_m = nn.Linear(embed_dim, embed_dim)
        self.tt_proj_m = nn.Linear(embed_dim, embed_dim)

        self.trans_itchange = TransformerEncoder(embed_dim=embed_dim,
                                                 num_heads=num_heads,
                                                 layers=layers,
                                                 attn_dropout=attn_dropout,
                                                 relu_dropout=relu_dropout,
                                                 res_dropout=res_dropout,
                                                 embed_dropout=embed_dropout,
                                                 attn_mask=attn_mask)
        self.trans_tichange = TransformerEncoder(embed_dim=embed_dim,
                                                 num_heads=num_heads,
                                                 layers=layers,
                                                 attn_dropout=attn_dropout,
                                                 relu_dropout=relu_dropout,
                                                 res_dropout=res_dropout,
                                                 embed_dropout=embed_dropout,
                                                 attn_mask=attn_mask)
        self.it_proj = nn.Linear(embed_dim, embed_dim)
        self.ti_proj = nn.Linear(embed_dim, embed_dim)
        self.model_pairs = [[self.trans_iichange,self.trans_iichange_m],
                            [self.trans_ttchange,self.trans_ttchange_m],
                            [self.ii_proj,self.ii_proj_m],
                            [self.tt_proj,self.tt_proj_m],
                            [self.visual_encoder,self.visual_encoder_m],
                            [self.text_encoder,self.text_encoder_m],
                            [self.conv1d_t, self.conv1d_t_m],
                            [self.conv1d_i, self.conv1d_i_m]
                           ]

        self.copy_params()

    def forward(self, image, text, alpha=0):
        with torch.no_grad():
            self.temp.clamp_(0.001,0.5)

        image_embeds_old = self.visual_encoder(image)
        image_atts = torch.ones(image_embeds_old.size()[:-1],dtype=torch.long).to(image.device)

        text_output = self.text_encoder(text.input_ids, attention_mask = text.attention_mask, return_dict = True, mode = 'text')
        text_embeds_old = text_output.last_hidden_state

        # self-attention

        m_text_feat_tran = text_embeds_old.clone().transpose(1, 2)
        m_image_feat_tran = image_embeds_old.clone().transpose(1, 2)

        m_text_feat = self.conv1d_t(m_text_feat_tran).permute(2, 0, 1)
        m_image_feat = self.conv1d_i(m_image_feat_tran).permute(2, 0, 1)

        tt_embeds = self.trans_ttchange(m_text_feat, m_text_feat, m_text_feat).permute(1, 0, 2)
        ii_embeds = self.trans_iichange(m_image_feat, m_image_feat, m_image_feat).permute(1, 0, 2)
        text_feat = F.normalize(self.tt_proj(tt_embeds[:,0,:]),dim=-1)
        image_feat = F.normalize(self.ii_proj(ii_embeds[:,0,:]),dim=-1)

        i2t_embeds = self.trans_itchange(m_text_feat, m_image_feat, m_image_feat).permute(1, 0, 2)
        t2i_embeds = self.trans_tichange(m_image_feat, m_text_feat, m_text_feat).permute(1, 0, 2)
        i2t_feat = F.normalize(self.it_proj(i2t_embeds[:,0,:]),dim=-1)
        t2i_feat = F.normalize(self.ti_proj(t2i_embeds[:,0,:]),dim=-1)

        text_embeds = torch.cat((tt_embeds,t2i_embeds), 1)
        image_embeds = torch.cat((ii_embeds,i2t_embeds), 1)

        with torch.no_grad():
            self._momentum_update()

            image_embeds_m_old = self.visual_encoder_m(image)
            text_output_m = self.text_encoder_m.bert(text.input_ids, attention_mask = text.attention_mask,
                                                return_dict = True, mode = 'text')
            text_embeds_m_old = text_output_m.last_hidden_state

            m_text_feat_tran_m = text_embeds_m_old.clone().transpose(1, 2)
            m_image_feat_tran_m = image_embeds_m_old.clone().transpose(1, 2)

            m_text_feat_m = self.conv1d_t(m_text_feat_tran_m).permute(2, 0, 1)
            m_image_feat_m = self.conv1d_i(m_image_feat_tran_m).permute(2, 0, 1)

            # cross-modal attention
            image_embeds_m = self.trans_iichange_m(m_image_feat_m, m_image_feat_m, m_image_feat_m).permute(1, 0, 2)
            text_embeds_m = self.trans_ttchange_m(m_text_feat_m, m_text_feat_m, m_text_feat_m).permute(1, 0, 2)
            image_feat_m = F.normalize(self.ii_proj_m(image_embeds_m[:,0,:]),dim=-1)
            text_feat_m = F.normalize(self.tt_proj_m(text_embeds_m[:,0,:]),dim=-1)
            image_feat_all = torch.cat([image_feat_m .t(),self.image_queue.clone().detach()],dim=1)
            text_feat_all = torch.cat([text_feat_m.t(),self.text_queue.clone().detach()],dim=1)

            sim_i2t_m = image_feat_m @ text_feat_all / self.temp #p i2t
            sim_t2i_m = text_feat_m @ image_feat_all / self.temp #p t2i

            sim_targets = torch.zeros(sim_i2t_m.size()).to(image.device)
            sim_targets.fill_diagonal_(1)

            sim_i2t_targets = alpha * F.softmax(sim_i2t_m, dim=1) + (1 - alpha) * sim_targets
            sim_t2i_targets = alpha * F.softmax(sim_t2i_m, dim=1) + (1 - alpha) * sim_targets

        sim_i2t = image_feat @ text_feat_all / self.temp
        sim_t2i = text_feat @ image_feat_all / self.temp

        loss_i2t = -torch.sum(F.log_softmax(sim_i2t, dim=1)*sim_i2t_targets,dim=1).mean()
        loss_t2i = -torch.sum(F.log_softmax(sim_t2i, dim=1)*sim_t2i_targets,dim=1).mean()

        loss_ita = (loss_i2t+loss_t2i)/2 #L ita

        sim_i2t_c = i2t_feat @ text_feat_all / self.temp #p c
        sim_t2i_c = t2i_feat @ image_feat_all / self.temp #p c
        sim_targets_itc = torch.arange(0, self.batch_size).to(image.device)
        loss_i2t_c = F.cross_entropy(sim_i2t_c, sim_targets_itc)
        loss_t2i_c = F.cross_entropy(sim_t2i_c, sim_targets_itc)

        loss_itc = (loss_i2t_c+loss_t2i_c)/2 #L itc

        self._dequeue_and_enqueue(image_feat_m, text_feat_m)

        text_atts = torch.ones(text_embeds.size()[:-1],dtype=torch.long).to(image.device)
        image_atts = torch.ones(image_embeds.size()[:-1],dtype=torch.long).to(image.device)
        output_pos = self.fusion_encoder.bert(encoder_embeds = text_embeds,
                                       attention_mask = text_atts,
                                       encoder_hidden_states = image_embeds,
                                       encoder_attention_mask = image_atts,
                                       return_dict = True,
                                       mode = 'fusion',
                                      )

        with torch.no_grad():
            bs = image.size(0)
            weights_i2t = F.softmax(sim_i2t_m[:,:bs],dim=1)
            weights_t2i = F.softmax(sim_t2i_m[:,:bs],dim=1)
            weights_i2t.fill_diagonal_(0)
            weights_t2i.fill_diagonal_(0)

        image_embeds_neg = []
        for b in range(bs):
            neg_idx = torch.multinomial(weights_t2i[b], 1).item()
            image_embeds_neg.append(image_embeds[neg_idx])
        image_embeds_neg = torch.stack(image_embeds_neg,dim=0)

        text_embeds_neg = []
        text_atts_neg = []
        for b in range(bs):
            neg_idx = torch.multinomial(weights_i2t[b], 1).item()
            text_embeds_neg.append(text_embeds[neg_idx])
            text_atts_neg.append(text_atts[neg_idx])
        text_embeds_neg = torch.stack(text_embeds_neg,dim=0)
        text_atts_neg = torch.stack(text_atts_neg,dim=0)

        text_embeds_all = torch.cat([text_embeds, text_embeds_neg],dim=0)
        text_atts_all = torch.cat([text_atts, text_atts_neg],dim=0)

        image_embeds_all = torch.cat([image_embeds_neg,image_embeds],dim=0)
        image_atts_all = torch.cat([image_atts,image_atts],dim=0)

        output_neg = self.fusion_encoder.bert(encoder_embeds = text_embeds_all,
                                        attention_mask = text_atts_all,
                                        encoder_hidden_states = image_embeds_all,
                                        encoder_attention_mask = image_atts_all,
                                        return_dict = True,
                                        mode = 'fusion',
                                       )

        vl_embeddings = torch.cat([output_pos.last_hidden_state[:,0,:], output_neg.last_hidden_state[:,0,:]],dim=0)
        vl_output = self.itm_head(vl_embeddings)

        itm_labels = torch.cat([torch.ones(bs,dtype=torch.long),torch.zeros(2*bs,dtype=torch.long)],
                               dim=0).to(image.device)
        loss_itm = F.cross_entropy(vl_output, itm_labels)

        #MLM
        input_ids = text.input_ids.clone()
        labels = input_ids.clone()

        probability_matrix = torch.full(labels.shape, self.mlm_probability)
        input_ids, labels = self.mask(input_ids, self.fusion_encoder.config.vocab_size, image.device, targets=labels,
                                      probability_matrix = probability_matrix)

        with torch.no_grad():
            image_atts_m = torch.ones(image_embeds_m.size()[:-1],dtype=torch.long).to(image.device)
            logits_m = self.fusion_encoder(input_ids,
                                           attention_mask = text.attention_mask,
                                           encoder_hidden_states = image_embeds_m,
                                           encoder_attention_mask = image_atts_m,
                                           return_dict = True,
                                           return_logits = True,
                                          )
        logits_m = torch.clamp(logits_m, min=1e-7, max=1 - 1e-7)
        mlm_output = self.fusion_encoder(input_ids,
                                       attention_mask = text.attention_mask,
                                       encoder_hidden_states = image_embeds,
                                       encoder_attention_mask = image_atts,
                                       return_dict = True,
                                       labels = labels,
                                       soft_labels = F.softmax(logits_m,dim=-1),
                                       alpha = alpha
                                      )
        loss_mlm = mlm_output.loss

        ita_t = 1
        loss_ita = loss_ita * ita_t
        itc_t = 1
        loss_itc = loss_itc * itc_t

        te = torch.cat((text_feat,t2i_feat), 1)
        ie = torch.cat((image_feat,i2t_feat), 1)

        return loss_mlm, loss_ita, loss_itc, loss_itm,te,ie

    @torch.no_grad()
    def copy_params(self):
        for model_pair in self.model_pairs:
            for param, param_m in zip(model_pair[0].parameters(), model_pair[1].parameters()):
                param_m.data.copy_(param.data)  # initialize
                param_m.requires_grad = False  # not update by gradient

    @torch.no_grad()
    def _momentum_update(self):
        for model_pair in self.model_pairs:
            for param, param_m in zip(model_pair[0].parameters(), model_pair[1].parameters()):
                param_m.data = param_m.data * self.momentum + param.data * (1. - self.momentum)

    @torch.no_grad()
    def _dequeue_and_enqueue(self, image_feat, text_feat):
        # gather keys before updating queue
        image_feats = concat_all_gather(image_feat)
        text_feats = concat_all_gather(text_feat)

        batch_size = image_feats.shape[0]

        ptr = int(self.queue_ptr)
        assert self.queue_size % batch_size == 0  # for simplicity

        # replace the keys at ptr (dequeue and enqueue)
        self.image_queue[:, ptr:ptr + batch_size] = image_feats.T
        self.text_queue[:, ptr:ptr + batch_size] = text_feats.T
        ptr = (ptr + batch_size) % self.queue_size  # move pointer

        self.queue_ptr[0] = ptr

    def mask(self, input_ids, vocab_size, device, targets=None, masked_indices=None, probability_matrix=None):
        if masked_indices is None:
            masked_indices = torch.bernoulli(probability_matrix).bool()

        masked_indices[input_ids == self.tokenizer.pad_token_id] = False
        masked_indices[input_ids == self.tokenizer.cls_token_id] = False

        if targets is not None:
            targets[~masked_indices] = -100 # We only compute loss on masked tokens

        # 80% of the time, we replace masked input tokens with tokenizer.mask_token ([MASK])
        indices_replaced = torch.bernoulli(torch.full(input_ids.shape, 0.8)).bool() & masked_indices
        input_ids[indices_replaced] = self.tokenizer.mask_token_id

        # 10% of the time, we replace masked input tokens with random word
        indices_random = torch.bernoulli(torch.full(input_ids.shape, 0.5)).bool() & masked_indices & ~indices_replaced
        random_words = torch.randint(vocab_size, input_ids.shape, dtype=torch.long).to(device)
        input_ids[indices_random] = random_words[indices_random]
        # The rest of the time (10% of the time) we keep the masked input tokens unchanged

        if targets is not None:
            return input_ids, targets
        else:
            return input_ids

@torch.no_grad()
def concat_all_gather(tensor):
    """
    Performs all_gather operation on the provided tensors.
    *** Warning ***: torch.distributed.all_gather has no gradient.
    """
    tensors_gather = [torch.ones_like(tensor)
        for _ in range(torch.distributed.get_world_size())]
    torch.distributed.all_gather(tensors_gather, tensor, async_op=False)

    output = torch.cat(tensors_gather, dim=0)
    return output


import heapq
from collections import defaultdict

def solution(n, start, end, roads, traps):
    graph = defaultdict(dict)
    rgraph = defaultdict(dict)
    for i, j, s in roads:
        graph[i][j] = s
        rgraph[j][i] = s

    min_plan = {node: float('inf') for node in range(1, n+1)}
    min_plan[start] = 0
    queue = []
    heapq.heappush(queue, (min_plan[start], start, 1))

    while queue:
        s, curr, status = heapq.heappop(queue)

        if s > min_plan[curr]:
            continue

        if curr == end:
            break

        if status == 1:
            _graph = graph
        else:
            _graph = rgraph

        for node, w in _graph[curr].items():
            acc = s+w

            if acc < min_plan[node]:
                min_plan[node] = acc
                item = (acc, node, status) if node not in traps else (acc, node, -status)
                heapq.heappush(queue, item)

    return min_plan[end]


import sys
from matplotlib import pyplot as pl

logFile = sys.argv[1]

# - Round 200 (global_step=199, learning_rate=0.001) -
def parseRoundHeader(l):
  parts = l.split(' ')
  trainRound = int(parts[2]) # '' 'Round' '200'
  return trainRound

# Greedy (best)  0.8790  (matched 0.8550, longerDer 0.0020, shorterDer: 0.0030, betterScore: 0.0190)
def parseEvalLine(l):
  # "best)  0.8790  "
  parts = l.split("matched")
  leftParts = parts[0][:-1].strip().split(" ")
  totalText = leftParts[-1]

  detailParts = parts[1][:-1].split(' ')
  betterText = detailParts[-1][:-1]

  return float(totalText), float(betterText)

def parseLog(logPath):
  taskName=None
  X = []
  bestY = []
  bestBetterY = []
  stopY = []
  stopBetterY = []

  incBetterX = [] # only track improvements for incumbent
  incBetterY = []

  lastIncumbent=0.0
  trainRound=None
  for l in open(logPath, 'r'):
    if l.startswith("- Round "):
      trainRound = parseRoundHeader(l)
      X.append(trainRound)
    elif "(best)" in l:
      if trainRound is None:
        print("Missed round header!!!")
        raise SystemExit
      # total, match, longerDer, shortedDer, betterScore = parseEvalLine(l)
      bestTotal, bestBetter = parseEvalLine(l)
      bestY.append(bestTotal)
      bestBetterY.append(bestBetter)
    elif "(STOP)" in l:
      if trainRound is None:
        print("Missed round header!!!")
        raise SystemExit
      # total, match, longerDer, shortedDer, betterScore = parseEvalLine(l)
      stopTotal, stopBetter = parseEvalLine(l)
      stopY.append(stopTotal)
      stopBetterY.append(stopBetter)
    elif "Incumbent" in l:
      if trainRound is None:
        print("Missed round header!!!")
        raise SystemExit
      # total, match, longerDer, shortedDer, betterScore = parseEvalLine(l)

      incTotal, incBetter = parseEvalLine(l)
      if incBetter <= lastIncumbent:
        continue

      lastIncumbent=incBetter
      incBetterX.append(trainRound)
      incBetterY.append(incBetter)
    elif l.startswith("name ="):
      taskName = l.split(" ")[2].strip()

  return taskName, X, bestY, bestBetterY, stopY, stopBetterY, incBetterX, incBetterY

# parse data
taskName, X, bestY, bestBetterY, stopY, stopBetterY, incBetterX, incBetterY = parseLog(sys.argv[1])

# build an artificial performance score
def buildPerfIndex(bestY, bestBetterY):
  return [best + better for best, better in zip(bestY, bestBetterY)]

def filterImprovements(X,Y):
  outX = [X[0]]
  outY = [Y[0]]
  bestY= outY[0]
  for x,y in zip(X,Y):
    if y > bestY:
      outX.append(x)
      outY.append(y)
      bestY = y
  return outX, outY

indexY = buildPerfIndex(bestY, bestBetterY)

### plot data ###
bestX=X[:len(bestY)]

# filter new incumbents
topX, topY = filterImprovements(bestX, bestY)

bestBetterX = X[:len(bestBetterY)]
topBetterX, topBetterY = filterImprovements(bestBetterX, bestBetterY)

stopBetterX = X[:len(stopBetterY)]
topStopX, topStopY = filterImprovements(stopBetterX, stopBetterY)

# plot training performance index
pl.plot(X[:len(indexY)], indexY, 'k:',label="perf. index")

# plot data

def plotAnnotated(rawX, Y, color, label):
  X = rawX[:len(Y)]
  topX, topY = filterImprovements(X, Y)
  pl.plot(topX, topY, '{}o'.format(color)) # best seen solution
  pl.plot(X, Y, color, label=label)

# current hit rate
plotAnnotated(X, bestY, "b", "opt: bestP")
plotAnnotated(X, stopY, "g", "opt: P@stop")

# fraction of improved programs
pl.plot(incBetterX[:len(incBetterY)], incBetterY, 'k.:',label="> ref (ceil)")

plotAnnotated(X, bestBetterY, "c", label="> ref (best P)")
plotAnnotated(X, stopBetterY, "m", label="> ref (P@stop)")

# extend incBetter line
if len(incBetterY) > 0:
  # append line w/o dot
  lastValue = incBetterY[-1]
  lastUpdateRound = incBetterX[-1]
  lastRound = X[-1]
  if lastUpdateRound != lastRound:
    pl.plot([lastUpdateRound, lastRound], [lastValue] * 2, 'k:')

# geknaupte axis
pl.plot([0, X[-1]], [1.0, 1.0], "k-")

pl.title("training on {} task".format(taskName))

### grid ###
# pl.rc('grid', linestyle=":", color='gray')
# pl.grid(True)

# axis
pl.xlabel("global step")
pl.ylabel("% of hold-out samples")
pl.legend()
pl.show()


import os
import json
import requests
import tempfile

from .api import AbstractApi

class Api(AbstractApi):

    def __get_sort_keys(self, sort_key="-date"):
        key = "acquisitionDate"
        order = "1"
        if sort_key and len(sort_key):
            if sort_key[0] == "-":
                order = "0"
                sort_key = sort_key[1:]
            if sort_key == "date":
                key = "acquisitionDate"
            elif sort_key == "cloud_rate":
                key = "cloudCover"

        return "{},,{}".format(key, order)

    def get_api_url(self):
        """
        Void method to get url for geostore API search

        Default url https://search.federated.geoapi-airbusds.com/api/v1/search
        """

        return "https://search.federated.geoapi-airbusds.com/api/v1/search"

    def get_payload(
        self,
        bbox=[],
        constellation=[],
        acquisition_date_range=[],
        polarisation_channels=[],
        product_type=[],
        resolution=None,
        geometry=None,
        cloud_cover=None,
        snow_cover=None,
        incidence_angle=None,
        sensor_type=None,
        antenna_look_direction=None,
        orbit_direction=None,
        count=20,
        start_page=1,
        sort_key='-date',
    ):
        """
        Payload data object with user parameters

        Arguments:
            * bbox (list): list containing bbox data
            * constellation (list): list of constellation
            * acquisition_date_range (list): acquisition dates
            * polarisation_channels (list): list of polarisation channels
            * product_type (list): list of product types
            * geometry (list): WKT Geometry. Bbox and geometry
                could not be equals.
            * resolution (list): maximum resolution filter
            * cloud_cover (list): maximum cloud cover
            * snow_cover (list):  maximum snow cover
            * incidence_angle (list): list of image incidence angle
            * sensor_type (list): list of sensors
            * antenna_look_direction (list): list of antenna look direction
            * orbit_direction (list): list of orbit direction
            * count (int): data count per request
            * start_page (int): which data response page will start

        Returns:
            * payload (object): json object containing payload data
        """
        payload = {}
        payload["count"] = count
        payload["startPage"] = 1
        payload["sortKeys"] = self.__get_sort_keys(sort_key)

        if geometry:
            payload["geometry"] = geometry

        if bbox:
            payload["bbox"] = bbox

        if constellation:
            payload["constellation"] = constellation

        if acquisition_date_range:
            dates = self._get_included_values(acquisition_date_range)
            payload["acquisitionDate"] = dates

        if polarisation_channels:
            payload["polarisationChannels"] = polarisation_channels

        if product_type:
            payload["productType"] = product_type

        if resolution:
            payload["resolution"] = self._get_less_than_or_equals(resolution)

        if cloud_cover:
            payload["cloudCover"] = self._get_less_than_or_equals(cloud_cover)

        if snow_cover:
            payload["snowCover"] = self._get_less_than_or_equals(snow_cover)

        if incidence_angle:
            incidence_angle = self._get_less_than_or_equals(incidence_angle)
            payload["incidenceAngle"] = incidence_angle

        if sensor_type:
            payload["sensorType"] = sensor_type

        if antenna_look_direction:
            payload["antennaLookDirection"] = antenna_look_direction

        if orbit_direction:
            payload["orbitDirection"] = orbit_direction

        if count:
            payload["count"] = count

        if start_page:
            payload["startPage"] = start_page

        return payload

    def get_response_data(self, payload):
        """
        *Get data from geostore url*

        Requests data from GeoStore API using authentication from
        geoapi_airbus.Authentication. Uses filters from payload data request
        returning requests response object

        Arguments:
            * payload (dict): payload data for filtered request

        Returns:
            * response (requests.response): a requests response data
        """

        headers = self._get_authenticated_headers()
        payload = json.dumps(payload)
        response = requests.post(
            self.get_api_url(),
            data=payload,
            headers=headers
        )

        if response.ok:
            return response

        return None

    def get_image_data(self, preview_url, img_size="LARGE"):
        """
        *Get image data blob from feature image_url*

        Arguments:
            * preview_url (str): preview url for request
            * img_size (str): image size.
                Could be: 'SMALL', 'MEDIUM', 'LARGE'

        Returns:
            * response (requests.response): a requests response data
        """

        headers = self._get_authenticated_headers_image()
        payload = {"size": img_size}
        response = requests.get(
            preview_url,
            headers=headers,
            params=json.dumps(payload)
        )

        return response

    def get_image_path(
        self,
        feature=None,
        preview_url=None,
        img_size="LARGE"
    ):
        """
        *Get image path from feature image_url or preview_url*

        Arguments:
            * feature (dict): geojson feature data
            * preview_url (str): preview url data
            * img_size (str): image size.
                Could be: 'SMALL', 'MEDIUM', 'LARGE'

        Returns:
            * path (str): path to image
        """

        error_msg = "Both feature and preview_url is not allowed"

        if feature and preview_url:
            raise ValueError(error_msg)

        if feature:
            thumbnails = filter(
                lambda x: x.get("size") == img_size,
                feature.get("quicklooks")
            )
            thumbnails = next(thumbnails).get('image')
            response = self.get_image_data(
                preview_url=thumbnails, img_size=img_size)
        else:
            response = self.get_image_data(
                preview_url=preview_url, img_size=img_size)

        if response and response.ok:
            temp_path = os.path.join(
                tempfile._get_default_tempdir(),
                next(tempfile._get_candidate_names()) + ".jpg"
            )
            try:
                with open(temp_path, "wb") as f:
                    f.write(response.content)
                    f.close()
                return temp_path
            except Exception as exc:
                raise ValueError("Error while writing image: {}".format(exc))

        return None


#!/usr/bin/python3
""" Place Module for HBNB project """
from sqlalchemy.sql.schema import Column, ForeignKey
from sqlalchemy.sql.sqltypes import String, Integer, Float
from sqlalchemy.sql.schema import Table
from models.base_model import BaseModel, Base
from os import getenv

class Place(BaseModel, Base):
    """ A place to stay """
    __tablename__ = 'places'

    if getenv('HBNB_TYPE_STORAGE', '') == 'db':
        city_id = Column(String(128), ForeignKey('cities.id'), nullable=False)
        user_id = Column(String(128), ForeignKey('users.id'), nullable=False)
        name = Column(String(128), nullable=False)
        description = Column(String(1024), nullable=True)
        number_rooms = Column(Integer, nullable=False, default=0)
        number_bathrooms = Column(Integer, nullable=False, default=0)
        max_guest = Column(Integer, nullable=False, default=0)
        price_by_night = Column(Integer, nullable=False, default=0)
        latitude = Column(Float, nullable=True)
        longitude = Column(Float, nullable=True)
        place_amenity = Table('place_amenity', Base.metadata,
                            Column('place_id', String(60),
                            ForeignKey('places.id'),
                            primary_key=True, nullable=False),
                            Column('amenity_id', String(60),
                            ForeignKey('amenities.id'),
                            primary_key=True, nullable=False))
    else:
        city_id = ''
        user_id = ''
        name = ''
        description = ''
        number_rooms = 0
        number_bathrooms = 0
        max_guest = 0
        price_by_night = 0
        latitude = 0.0
        longitude = 0.0
    amenity_ids = []


import os
import torch
import itertools
import numpy as np
from collections import OrderedDict

from bc.agent.image import ImageAgent
from bc.agent import utils
from bc.dataset import Actions
from bc.model import utils as bc_utils

class RLAgent(ImageAgent):
    def __init__(self, path, epoch, max_steps, device='cpu', env=None, real_robot_mode=False,
                 timescales_list=None, **kwargs):
        super(RLAgent, self).__init__(path, epoch, max_steps, device)
        self.model, self.rl_args, self.obs_running_stats = self._load_model()
        self.model.args = self.rl_args.bc_args
        self.real_robot_mode = real_robot_mode
        if not self.real_robot_mode:
            self.set_augmentation(self.rl_args.augmentation)
        else:
            self.set_augmentation('')
        self._max_steps = max_steps

        # skills timescales
        if timescales_list is None:
            if isinstance(self.rl_args.timescale, list):
                self._skills_timescales = self.rl_args.timescale
            else:
                assert isinstance(self.rl_args.timescale, int)
                self._skills_timescales = []
                for _ in range(self.rl_args.num_skills):
                    self._skills_timescales.append(self.rl_args.timescale)
        else:
            assert isinstance(timescales_list, list)
            self._skills_timescales = timescales_list

        # memory
        self._action_memory = self.rl_args.action_memory
        if self._action_memory > 0:
            last_skills_tensor = -torch.ones(self._action_memory).float()
            self._last_skills = {0: last_skills_tensor.to(torch.device(device))}
        else:
            self._last_skills = None

        # full state specific stuff
        self._env = env
        self.action_keys = Actions.action_space_to_keys(
            self.rl_args.bc_args['action_space'])[0]

        self.reset()

    def reset(self):
        super(RLAgent, self).reset()
        self._skill = None
        self._need_master_action = True
        self._prev_script, self._prev_action_chain = None, None

    def _load_model(self):
        load_path = os.path.join(
            self._path, 'model_{}.pth'.format(self._epoch))
        device = self._device
        if device == 'cpu':
            loaded_dict = torch.load(
                load_path, map_location=lambda storage, loc: storage)
        else:
            loaded_dict = torch.load(load_path)
        policy = loaded_dict['policy']
        if hasattr(policy.base, 'resnet'):
            # set the batch norm to eval mode
            policy.base.resnet.eval()
        policy.to(torch.device(device))
        return policy, loaded_dict['args'], loaded_dict['obs_running_stats']

    def get_action(self, obs):
        if self._max_steps > -1 and self._count_steps > self._max_steps:
            return None
        self._count_steps += 1

        if 'Cam' in self.rl_args.env_name:
            self._stack_frames, self._stack_signals = self.update_stacks(
                obs, self._stack_frames, self._stack_signals)
            obs_dict = {0: self._stack_frames.float()[None, :].to(self._device)[0]}
        else:
            obs_dict = {0: self._process_full_state_obs(obs)}

        if self._skill is None or self._need_master_action:
            with torch.no_grad():
                _, skill_dict, _ = self.model.act(
                    obs_dict, self._last_skills, deterministic=True)
            self._skill = skill_dict[0][None]
            if self._last_skills is not None:
                self._last_skills = {
                    0: utils.add_to_stack(self._skill, self._last_skills[0])}
            self._step_new_skill = self._count_steps
            if self.real_robot_mode:
                print('New master action (skill) is {}'.format(self._skill.item()))

        if not self.rl_args.use_expert_scripts:
            with torch.no_grad():
                action_dict, _ = self.model.get_worker_action({0: self._skill}, obs_dict)
                action = action_dict[0]
            skill_val = self._skill.item()
            self._need_master_action = (
                (self._count_steps - self._step_new_skill + 1) == self._skills_timescales[skill_val])
        else:
            action = self._get_script_action(self._skill.item())
        return action

    def _get_script_action(self, skill):
        # copy-paste from ppo.envs.mime
        if self._prev_script != skill:
            self._prev_script = skill
            self._prev_action_chain = self._env.unwrapped.scene.script_subtask(skill)
        action_chain = itertools.chain(*self._prev_action_chain)
        action_applied = Actions.get_dict_null_action(self.action_keys)
        action_update = next(action_chain, None)
        if action_update is None:
            self._need_master_action = True
        else:
            self._need_master_action = False
            action_applied.update(
                Actions.filter_action(action_update, self.action_keys))
        return action_applied

    def _process_full_state_obs(self, obs_dict):
        observation = np.array([])
        obs_sorted = OrderedDict(sorted(obs_dict.items(), key=lambda t: t[0]))
        cam_obs_keys = ['rgb0', 'depth0', 'mask0']
        for obs_key, obs_value in obs_sorted.items():
            if obs_key != 'skill' and obs_key not in cam_obs_keys:
                if isinstance(obs_value, (int, float)):
                    obs_value = [obs_value]
                elif isinstance(obs_value, np.ndarray):
                    obs_value = obs_value.flatten()
                elif isinstance(obs_value, list) and isinstance(
                        obs_value[0], np.ndarray):
                    obs_value = np.concatenate(obs_value)
                observation = np.concatenate((observation, obs_value))
        observation = torch.tensor(observation).float()
        obs_mean = torch.tensor(
            self.obs_running_stats.mean).type_as(observation)
        obs_var = torch.tensor(self.obs_running_stats.var).type_as(observation)
        observation = np.clip(
            (observation - obs_mean) / np.sqrt(obs_var + 1e-8), -10., 10.)
        return observation.to(torch.device(self._device))