import os
import sys
import glob

from PySide2.QtCore import QUrl, QCoreApplication, QTranslator, QLocale, QFile
from PySide2.QtGui import Qt, QDesktopServices, QFont, QIcon, QPixmap, QFontDatabase
from PySide2.QtWidgets import QMainWindow, QMessageBox, QApplication, QListWidgetItem, QMenu, QAction, QFileDialog, \
    QDialog, QDialogButtonBox

from ui_appvar_text_editor import Ui_MainWindow
from ui_change_font_dialog import Ui_Dialog as Ui_ChangeFontDialog
from ui_select_character import Ui_Dialog as Ui_SelectCharacterDialog

from icon import setupActionsIcons, get_app_icon, get_icon
from const_strings import *

import export

def tr(text: str):  # internal translation
    return QCoreApplication.translate("@default", text, None)

class ChangeFontDialog(QDialog, Ui_ChangeFontDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.setWindowIcon(get_icon("characters"))

class SelectCharacterDialog(QDialog, Ui_SelectCharacterDialog):
    def __init__(self, parent=None, font=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.setWindowIcon(get_icon("font_add"))
        tmp_text = r""
        for i_ in range(1, 256):
            tmp_text = tmp_text + chr(i_)  # fill in with characters from 0x01 to 0xFF
        # fix some characters (which cannot be printed, such as 9,10,13,14)
        l = [9, 10, 13, 14]
        x = 256
        final_text = ""
        for c in tmp_text:  # not really optimized, but here we don't care
            for i in l:
                if c == chr(i):
                    c = chr(x)
                    x += 1
            final_text += c

        self.plainTextEdit.setPlainText(final_text)
        self.plainTextEdit.setFont(font)

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        id = QFontDatabase.addApplicationFont(":/font/CEfont.ttf")  # add custom font
        family = QFontDatabase.applicationFontFamilies(id)[0]
        CEfont = QFont(family, 8)
        QMainWindow.__init__(self)
        self.setupUi(self)
        self.plainTextEdit.setFont(CEfont)
        setupActionsIcons(self)
        self.saved_path = None
        self.last_opened = None
        self.actionAbout_Qt.triggered.connect(app.aboutQt)
        self.pushButton_2.clicked.connect(self.add_string)
        self.pushButton_3.clicked.connect(self.remove_string)
        self.listWidget.currentItemChanged.connect(self.selection_changed)
        self.plainTextEdit.textChanged.connect(self.editChanged)
        self.pushButton.clicked.connect(lambda: SelectCharacterDialog(self, CEfont).exec_())
        self.actionAbout.triggered.connect(self.about)
        self.update_status_bar()
        self.setWindowIcon(get_app_icon())
        self.plainTextEdit.cursorPositionChanged.connect(self.update_status_bar)
        self.actionView_GitHub_page.triggered.connect(lambda: QDesktopServices.openUrl(QUrl("https://github.com/SiniKra"
                                                                                "ft/AppvarTextEditor/")))
        self.actionContribute.triggered.connect(lambda: QDesktopServices.openUrl(QUrl("https://github.com/SiniKraft/App"
                                                                                "varTextEditor/issues/")))
        self.actionNew.triggered.connect(self._new)
        self.actionSave.triggered.connect(self.save)
        self.actionSave_As.triggered.connect(self.save_as)
        self.actionOpen.triggered.connect(self.open)
        self.actionChange_Font.triggered.connect(self.change_font)
        self.actionEnglish.triggered.connect(lambda: self.change_language("en"))
        self.actionExport.triggered.connect(self.export_as_appvar)

        self.menuMore_Actions = QMenu(self)
        self.actionDelete_All = QAction(get_icon("error"), tr("Delete All"), parent=self.menuMore_Actions)
        self.menuMore_Actions.addAction(self.actionDelete_All)
        self.toolButton_4.setMenu(self.menuMore_Actions)
        self.actionDelete_All.triggered.connect(self.listWidget.clear)
        self.load_languages()

    def load_languages(self):
        for directory in glob.glob("translations/*"):
            lang_name = directory.replace("/", "").replace("translations", "").replace("\\", "").replace("(", "")
            # last is security to ensure no arbitrary code is run
            tmp_locale = QLocale(lang_name)
            if not tmp_locale.nativeLanguageName() == "":  # null check
                tmp_icon = QIcon()  # adding all actions to change langs generated on folder content at runtime
                tmp_icon.addPixmap(QPixmap((directory + "/%s_16.png" % lang_name).replace("\\", "/")))
                tmp_icon.addPixmap(QPixmap((directory + "/%s_32.png" % lang_name).replace("\\", "/")))
                tmp_action = QAction(self)
                tmp_action.setObjectName(u"action" + lang_name)
                tmp_action.setText(tmp_locale.languageToString(tmp_locale.language()))
                tmp_action.setIcon(tmp_icon)
                eval('tmp_action.triggered.connect(lambda: win.change_language("%s"))' % lang_name)
                self.menuChange_Language.addAction(tmp_action)
        self.menuChange_Language.addSeparator()
        self.menuChange_Language.addAction(self.actionContribute)

    def add_string(self):
        if self.listWidget.count() != 254:
            __qlistwidgetitem = QListWidgetItem(self.listWidget)
            __qlistwidgetitem.setFlags(
                Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            __qlistwidgetitem.setText(tr("New String"))
            __qlistwidgetitem.setSelected(True)
            self.listWidget.setItemSelected(__qlistwidgetitem, True)
            self.listWidget.setCurrentItem(__qlistwidgetitem)
            self.plainTextEdit.setFocus()
            self.selection_changed()

        else:
            showerror(tr("You cannot have more than 254 strings !"),
                      self, tr("Too many strings !"))

    def remove_string(self):
        if self.listWidget.selectedItems():  # check if list is not empty
            _row = self.listWidget.row(self.listWidget.selectedItems()[0])
            self.listWidget.takeItem(_row)  # selecting first element (only one can be selected)
            self.listWidget.setItemSelected(self.listWidget.item(_row - 1), True)
            self.selection_changed()
        else:
            showerror(tr("Select a string first !"), self, tr("No string selected"))

    def update_status_bar(self):
        _str = ""
        if self.listWidget.selectedItems():
            _str = tr(
                "  -  Current string index: {0}  -  Current string length: {1}/254  -  Current char index: {2}").format(
                str(self.listWidget.currentIndex().row()), str(len(self.plainTextEdit.toPlainText())),
                str(self.plainTextEdit.textCursor().position()))
        self.statusBar.showMessage(tr("Number of strings: {0}/254{1}").format(str(self.listWidget.count()), _str))

    def selection_changed(self):
        if self.listWidget.selectedItems():
            try:
                self.plainTextEdit.setPlainText(self.listWidget.currentItem().text())
                self.plainTextEdit.setFocus()
                __qtextcursor = self.plainTextEdit.textCursor()
                __qtextcursor.setPosition(len(self.plainTextEdit.toPlainText()))
                self.plainTextEdit.setTextCursor(__qtextcursor)
            except AttributeError:
                pass
        self.update_status_bar()

    def about(self):
        msg = QMessageBox(self)
        msg.setWindowIcon(get_icon("info"))
        msg.setWindowTitle(tr("About Appvar Text Editor ..."))
        msg.setIcon(QMessageBox.Information)
        msg.setText(tr(about_text))
        msg.setStandardButtons(QMessageBox.Ok)
        msg.exec_()

    def editChanged(self):
        if len(self.plainTextEdit.toPlainText()) == 255:
            self.plainTextEdit.setPlainText(self.plainTextEdit.toPlainText()[:254])
        if self.listWidget.currentItem() is not None:
            self.listWidget.currentItem().setText(self.plainTextEdit.toPlainText())
        self.update_status_bar()

    def unsaved_change(self):
        pass

    def _new(self):  # clear the window
        self.unsaved_change()
        self.listWidget.clear()
        self.lineEdit.clear()
        self.plainTextEdit.clear()

    def save(self):
        if self.saved_path is not None:
            try:
                export.export_as_ate(self, self.saved_path)
            except Exception as e:
                showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))
        else:
            dg = QFileDialog(self)
            dg.setFileMode(QFileDialog.AnyFile)
            dg.setNameFilter(tr("ATE files (*.ate)"))
            dg.setAcceptMode(QFileDialog.AcceptSave)
            dg.setDefaultSuffix("ate")
            if dg.exec_():
                path = dg.selectedFiles()
                self.last_opened = path[0]
                try:
                    export.export_as_ate(self, path[0])
                    self.saved_path = path[0]
                except Exception as e:
                    showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))

    def save_as(self):
        dg = QFileDialog(self)
        dg.setFileMode(QFileDialog.AnyFile)
        dg.setNameFilter(tr("ATE files (*.ate);;Text files (*.txt);;JSON files (*.json)"))
        dg.setAcceptMode(QFileDialog.AcceptSave)
        dg.setDefaultSuffix("ate")
        if dg.exec_():
            path = dg.selectedFiles()
            self.last_opened = path[0]
            if path[0][-3:] == "ate":  # check extension input by user
                try:
                    export.export_as_ate(self, path[0])
                except Exception as e:
                    showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))
            elif path[0][-3:] == "txt":
                mode = "plain"
                msg = QMessageBox(parent=self)
                msg.setIcon(QMessageBox.Question)
                msg.setText(tr("Choose your mode : comma separated or plain text ?"))
                msg.setWindowTitle(tr("Choose Text Mode"))
                msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
                msg.button(QMessageBox.Yes).setText(tr("Plain Text"))
                msg.button(QMessageBox.Cancel).setText(tr("Comma Separated Values"))
                msg.exec_()
                if msg.clickedButton() == msg.button(QMessageBox.Cancel):
                    mode = "comma"
                try:
                    export.export_as_txt(self, path[0], mode)
                except Exception as e:
                    showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))
            elif path[0][-3:] == "son":
                try:
                    export.export_as_json(self, path[0])
                except Exception as e:
                    showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))
            else:
                raise NotImplementedError  # if the extension is invalid or unsupported

    def open(self, arg_1=None, _path=None):  # arg_1 is already given by QT system
        if _path is None:
            path = None
            dg = QFileDialog(self)
            dg.setFileMode(QFileDialog.ExistingFile)
            dg.setNameFilter(
                tr("All supported types of files (*.ate; *.txt; *.json);;ATE files (*.ate);;Text files (*.txt);;JSON files (*.json)"))
            dg.setAcceptMode(QFileDialog.AcceptOpen)
            if dg.exec_():
                path = dg.selectedFiles()
                self.last_opened = path[0]
        else:
            path = [_path]
        if path is not None:
            if path[0][-3:] == "ate":
                try:
                    export.import_from_ate(self, path[0])
                except Exception as e:
                    showerror(tr("Failed to open :\n{0}").format(str(e)), self, tr("I/O Error"))
            elif path[0][-3:] == "txt":
                try:
                    export.import_from_txt(self, path[0])
                except Exception as e:
                    showerror(tr("Failed to open :\n{0}").format(str(e)), self, tr("I/O Error"))
            elif path[0][-3:] == "son":
                try:
                    export.import_from_json(self, path[0])
                except Exception as e:
                    showerror(tr("Failed to open :\n{0}").format(str(e)), self, tr("I/O Error"))
            else:
                raise NotImplementedError

    def change_font(self):
        dg = ChangeFontDialog(self)
        dg.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(lambda: self.restore_defaults_font(dg))
        if dg.exec_():
            self.setFont(dg.fontComboBox.currentFont())

    def change_language(self, lang_initial: str):
        try:
            with open("lang", "w", encoding='utf-8') as file:
                file.write(lang_initial)
                file.close()
            msg = QMessageBox(parent=self)
            msg.setIcon(QMessageBox.Information)
            msg.setWindowIcon(get_icon("info"))
            msg.setText(tr("Please restart in order to change language."))
            msg.setWindowTitle(tr("Restart needed !"))
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
        except Exception as e:
            showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))

    def restore_defaults_font(self, dg):
        dg.fontComboBox.setFont(QFont("MS Shell Dlg 2"))
        dg.fontComboBox.update()

    def closeEvent(self, event):  # when window closed, save the path of the currently edited file
        if self.last_opened is not None:
            try:
                with open("last_opened", "w", encoding='utf-8') as file:
                    file.write(self.last_opened)
                    file.close()
            except Exception as e:
                showerror(tr("Failed to save :\n{0}").format(str(e)), self, tr("I/O Error"))
        event.accept()

    def ask_to_reopen(self):
        if os.path.isfile("last_opened"):
            msg = QMessageBox(parent=self)
            msg.setIcon(QMessageBox.Question)
            msg.setText(tr("Do you want to reopen last opened file ?"))
            msg.setWindowTitle(tr("Reopen closed file ?"))
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg.exec_()
            if msg.clickedButton() == msg.button(QMessageBox.Yes):
                try:
                    with open("last_opened", "r", encoding='utf-8') as file:
                        path_ = file.read()
                        file.close()
                    self.open(None, path_)
                except Exception as e:
                    showerror(tr("Failed to open :\n{0}").format(str(e)), self, tr("I/O Error"))
            else:
                try:
                    os.remove("last_opened")
                except Exception as e:
                    print(e)

    def export_as_appvar(self):
        dg = QFileDialog(self)
        dg.setFileMode(QFileDialog.AnyFile)
        dg.setNameFilter(tr("AppVar files (*.8xv)"))
        dg.setAcceptMode(QFileDialog.AcceptSave)
        dg.setDefaultSuffix("8xv")
        if dg.exec_():
            path = dg.selectedFiles()
            export.export_as_appvar(self, path[0])

def showerror(_msg, _win=None, title=tr("An error occurred")):
    msg = QMessageBox(win)
    msg.setWindowIcon(get_icon("error"))
    msg.setWindowTitle(title)
    msg.setIcon(QMessageBox.Critical)
    msg.setText(_msg)
    msg.setStandardButtons(QMessageBox.Ok)
    msg.exec_()

def load_language(application: QApplication):  # if the 'lang' file exists, try getting QLocale from it
    if os.path.isfile("lang"):
        try:
            with open("lang", "r", encoding='utf-8') as file:
                lang = file.read()
                file.close()
            tmp_locale = QLocale(lang)
            if not tmp_locale.nativeLanguageName() == "":
                for s in ["{0}.qm", "qt_{0}.qm", "qtbase_{0}.qm"]:
                    t = QTranslator(application)
                    t.load(("translations/{0}/" + s).format(lang))
                    application.installTranslator(t)
            else:
                raise Exception("Failed to load lang file")
        except Exception as e:
            print(e)
    else:
        try:
            with open("lang", "w", encoding='utf-8') as file:
                file.write(str(QLocale().system().uiLanguages()[0][:2]))  # First item is preferred language,
                # and get 2 first character of this language e.g. 'en' in 'en_US' (ignoring country-specific locales)
                file.close()
            load_language(application)  # danger: check for recursive calls
        except Exception as e:
            print(e)

if __name__ == "__main__":
    args = sys.argv
    args.append("--enable-smooth-scrolling")  # useful only if using QWebEngineViews
    app = QApplication(args)
    app.setAttribute(Qt.AA_DisableWindowContextHelpButton)  # disable useless help button in dialogs
    load_language(app)
    win = MainWindow()
    win.show()
    win.ask_to_reopen()
    sys.exit(app.exec_())


import random

class Card:
    def __init__(self, suit, value):
        self.suit = suit
        self.value = value

    def __repr__(self):
        return f"{self.value} of {self.suit}"

class Deck:
    def __init__(self):
        self.cards = [Card(s, v) for s in ["Spades", "Clubs", "Hearts", "Diamonds"] for v in range(1, 14)]

    def shuffle(self):
        if len(self.cards) > 1:
            random.shuffle(self.cards)

    def deal(self):
        if len(self.cards) > 1:
            return self.cards.pop(0)

class Hand:
    def __init__(self):
        self.cards = []

    def add_card(self, card):
        self.cards.append(card)

    def get_value(self):
        value = 0
        has_ace = False
        for card in self.cards:
            if card.value > 10:
                value += 10
            elif card.value == 1:
                has_ace = True
                value += 11
            else:
                value += card.value

        if has_ace and value > 21:
            value -= 10

        return value

    def __repr__(self):
        return str(self.cards)

class Blackjack:
    def __init__(self):
        self.deck = Deck()
        self.deck.shuffle()
        self.player_hand = Hand()
        self.dealer_hand = Hand()

    def deal_initial_cards(self):
        self.player_hand.add_card(self.deck.deal())
        self.dealer_hand.add_card(self.deck.deal())
        self.player_hand.add_card(self.deck.deal())
        self.dealer_hand.add_card(self.deck.deal())

    def player_turn(self):
        while self.player_hand.get_value() < 21:
            action = input("Do you want to hit or stand? ")
            if action == "hit":
                self.player_hand.add_card(self.deck.deal())
                print(f"Your hand: {self.player_hand}")
            elif action == "stand":
                break
            else:
                print("Invalid action. Please try again.")
                continue

    def dealer_turn(self):
        while self.dealer_hand.get_value() < 17:
            self.dealer_hand.add_card(self.deck.deal())
            print(f"Dealer's hand: {self.dealer_hand}")

    def determine_winner(self):
        player_value = self.player_hand.get_value()
        dealer_value = self.dealer_hand.get_value()

        if player_value > 21:
            return "Dealer wins! You went over 21."
        elif dealer_value > 21:
            return "You win! Dealer went over 21."
        elif player_value > dealer_value:
            return "You win!"
        elif dealer_value > player_value:
            return "Dealer wins!"
        else:
            return "It's a tie!"

    def play(self):
        self.deal_initial_cards()
        print(f"Your hand: {self.player_hand}")
        print(f"Dealer's up card: {self.dealer_hand.cards[1]}")
        self.player_turn()
        self.dealer_turn()
        print(self.determine_winner())

game = Blackjack()
game.play()


import os
import warnings

from fireworks import FireTaskBase, explicit_serialize
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from matminer.utils.io import load_dataframe_from_json

from automatminer.featurization import AutoFeaturizer
from automatminer.preprocessing import DataCleaner, FeatureReducer
from automatminer.automl.adaptors import TPOTAdaptor, SinglePipelineAdaptor
from automatminer.pipeline import MatPipe

@explicit_serialize
class RunSingleFit(FireTaskBase):
    _fw_name = "RunSinglePipe"

    def run_task(self, fw_spec):
        # Read data from fw_spec
        pipe_config_dict = fw_spec["pipe_config"]
        target = fw_spec["target"]
        data_file = fw_spec["data_file"]
        learner_name = pipe_config_dict["learner_name"]
        learner_kwargs = pipe_config_dict["learner_kwargs"]
        reducer_kwargs = pipe_config_dict["reducer_kwargs"]
        cleaner_kwargs = pipe_config_dict["cleaner_kwargs"]
        autofeaturizer_kwargs = pipe_config_dict["autofeaturizer_kwargs"]

        # Modify data_file based on computing resource
        data_dir = os.environ["AMM_DATASET_DIR"]
        data_file = os.path.join(data_dir, data_file)

        # Modify save_dir based on computing resource
        bench_dir = os.environ["AMM_SINGLE_FIT_DIR"]
        base_save_dir = fw_spec["base_save_dir"]
        base_save_dir = os.path.join(bench_dir, base_save_dir)

        if not os.path.exists(base_save_dir):
            os.makedirs(base_save_dir)

        # Set up pipeline config
        if learner_name == "TPOTAdaptor":
            learner = TPOTAdaptor(**learner_kwargs)
        elif learner_name == "rf":
            warnings.warn(
                "Learner kwargs passed into RF regressor/classifiers bc. rf being used."
            )
            learner = SinglePipelineAdaptor(
                regressor=RandomForestRegressor(**learner_kwargs),
                classifier=RandomForestClassifier(**learner_kwargs),
            )
        else:
            raise ValueError("{} not supported yet!" "".format(learner_name))
        pipe_config = {
            "learner": learner,
            "reducer": FeatureReducer(**reducer_kwargs),
            "cleaner": DataCleaner(**cleaner_kwargs),
            "autofeaturizer": AutoFeaturizer(**autofeaturizer_kwargs),
        }
        pipe = MatPipe(**pipe_config)

        # Set up dataset
        # Dataset should already be set up correctly as json beforehand.
        # this includes targets being converted to classification, removing
        # extra columns, having the names of featurization cols set to the
        # same as the matpipe config, etc.
        df = load_dataframe_from_json(data_file)

        pipe.fit(df, target)
        pipe.save(os.path.join(base_save_dir, "pipe.p"))


directions = {
    1: [(-1, 0), (1, 0), (0, -1), (0, 1)],    # 상 하 좌 우
    2: [(-1, 0), (1, 0)],    # 상 하
    3: [(0, -1), (0, 1)],    # 좌 우
    4: [(-1, 0), (0, 1)],    # 상 우
    5: [(1, 0), (0, 1)],    # 하 우
    6: [(1, 0), (0, -1)],    # 하 좌
    7: [(-1, 0), (0, -1)]    # 상 좌
}
T = int(input())

def dfs(y, x, cnt):
    if cnt == L:
        return
    for d in directions[underground[y][x]]:
        nx = x + d[1]
        ny = y + d[0]
        if 0 <= nx < M and 0 <= ny < N and not visited[ny][nx] and underground[ny][nx]:
            if tuple([-1 * pos for pos in d]) in directions[underground[ny][nx]]:
                visited[ny][nx] = 1
                dfs(ny, nx, cnt + 1)
                visited[ny][nx] = 0
                places.add((ny, nx))

for tc in range(1, T + 1):
    N, M, R, C, L = map(int, input().split())
    underground = [list(map(int, input().split())) for _ in range(N)]
    visited = [[0] * M for _ in range(N)]
    visited[R][C] = 1
    places = set()
    places.add((R, C))
    dfs(R, C, 1)
    ans = len(places)
    print(f'#{tc} {ans}')


class Grafo:
    def __init__(self):
        self.nodos = {}
        self.aristas = {}

    def agregar_nodo(self, price_clp=None,price_uf=None,price_usd=None,comuna=None,ubicacion=None,dorms=None,baths=None,built_area=None,total_area=None,parking=None,id=None,realtor=None, desc=None):   #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
        self.nodos[id] = {
            'id':id,
            'price_clp': price_clp,
            'price_uf': price_uf,
            'price_usd': price_usd,
            'comuna': comuna,
            'ubicacion': ubicacion,
            'dorms': dorms,
            'baths':baths,
            'built_area':built_area,
            'total_area':total_area,
            'parking':parking,
            'realtor':realtor,
            'desc':desc                                                                                #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        }
        self.aristas[id] = {}

    def agregar_arista(self, id_origen, id_destino, peso):
        self.aristas[id_origen][id_destino] = peso
        self.aristas[id_destino][id_origen] = peso

    def obtener_nodos(self):
        return self.nodos.keys()

    def obtener_aristas(self):
        aristas = []
        for id_origen in self.aristas:
            for id_destino in self.aristas[id_origen]:
                if (id_destino, id_origen) not in aristas:
                    aristas.append((id_origen, id_destino, self.aristas[id_origen][id_destino]))
        return aristas

    def __str__(self):
        nodos_str = ""
        for nodo_id in self.obtener_nodos():
            for destino, peso in self.aristas[nodo_id].items():
                nodos_str += f"Nodo {nodo_id} -> Nodo {destino} = Peso {peso}\n"
        return nodos_str


#minimum cost of the subsequence
#not solved to be continue

def solve(k,a):
    z=list()
    b=sorted(a)
    b=b[:k]
    b=set(b)
    counter=0
    for i in a:
        if(i in b and counter<k):
            counter+=1
            z.append(i)
    odd=-9999999999
    even=-99999999999
    print(z)
    for i in range(k):
        if(i%2==0):
            odd=max(odd,z[i])
        else:
            even=max(even,z[i])
    return(min(odd,even))

if __name__=="__main__":
    n,k=map(int,input().split())
    a=[int(i) for i in input().split()]
    print(solve(k,a))


import tensorflow as tf
import model3 as M
from tensorflow.keras.layers import GRU, Bidirectional, LSTMCell, GRUCell
import time

class HighwayNet(M.Model):
	def initialize(self, size):
		self.fc1 = M.Dense(size, activation=M.PARAM_RELU)
		self.fc2 = M.Dense(size, activation=M.PARAM_SIGMOID)
	def forward(self, x):
		# self-attention
		x1 = self.fc1(x)
		g = self.fc2(x)
		y = g * x1 + (1 - g) * x
		return y

class PreNet(M.Model):
	def initialize(self, out1=256, out2=128, dropout=0.5):
		self.fc1 = M.Dense(out1, activation=M.PARAM_RELU)
		self.fc2 = M.Dense(out2, activation=M.PARAM_RELU)
		self.dropout = dropout
	def forward(self, x):
		x = self.fc1(x)
		if tf.keras.backend.learning_phase():
			x = tf.nn.dropout(x, self.dropout)
		x = self.fc2(x)
		if tf.keras.backend.learning_phase():
			x = tf.nn.dropout(x, self.dropout)
		return x

class CBHG(M.Model):
	def initialize(self, K, channels, proj_chn, num_highway):
		self.kernels = [i for i in range(1, K+1)]
		self.conv1d_bank = []
		for k in self.kernels:
			conv = M.ConvLayer1D(k, channels, batch_norm=True, usebias=False, activation=M.PARAM_RELU)
			self.conv1d_bank.append(conv)
		self.maxpool = M.MaxPool(2, 1) # implement this later

		self.conv_proj1 = M.ConvLayer1D(3, proj_chn[0], batch_norm=True, usebias=False, activation=M.PARAM_RELU)
		self.conv_proj2 = M.ConvLayer1D(3, proj_chn[1], batch_norm=True, usebias=False)

		if proj_chn[-1] != channels:
			self.pre_highway = M.ConvLayer1D(1, channels, usebias=False)

		self.highways = []
		for i in range(num_highway):
			hw = HighwayNet(channels)
			self.highways.append(hw)

		self.rnn = Bidirectional(GRU(channels,return_sequences=True)) # implement this later
		# self.last_proj = M.Dense(channels*2)

	def forward(self, x):
		residual = x
		seqlen = x.shape[1]
		convbank = []
		for conv in self.conv1d_bank:
			c = conv(x)
			convbank.append(c[:,:seqlen])
		x = tf.concat(convbank, axis=-1)

		x = self.maxpool(x)[:,:seqlen]

		x = self.conv_proj1(x)
		x = self.conv_proj2(x)

		x = x + residual

		if hasattr(self, 'pre_highway'):
			x = self.pre_highway(x)
		for hw in self.highways:
			x = hw(x)

		x = self.rnn(x)
		# x = self.last_proj(x)
		return x

class Attention(M.Model):
	def initialize(self, dim):
		self.W = M.Dense(dim, usebias=False)
		self.v = M.Dense(1, usebias=False)
	def forward(self, enc_seq, query, t):
		q_proj = tf.expand_dims(self.W(query),axis = 1)
		u = self.v(tf.tanh(q_proj + enc_seq))
		scr = tf.nn.softmax(u, axis=1)
		return scr

class LSA(M.Model):
	def initialize(self, att_dim, kszie=31, filters=32):
		self.conv = M.ConvLayer1D(kszie, filters)
		self.L = M.Dense(att_dim)
		self.W = M.Dense(att_dim)
		self.v = M.Dense(1, usebias=False)
		self.cumulate = None
		self.att = None

	def init_att(self, enc_seq):
		b, t, c = enc_seq.shape
		self.cumulate = tf.zeros([b,t])
		self.att = tf.zeros([b,t])

	def forward(self, enc_seq, query, t):
		if t==0:
			self.init_att(enc_seq)
		q_proj = self.W(query)
		q_proj = tf.expand_dims(q_proj, axis=1)
		loc = tf.stack([self.cumulate, self.att], axis=-1)
		loc_proj = self.L(self.conv(loc))
		u = self.v(tf.tanh(q_proj + loc_proj + enc_seq))
		u = tf.squeeze(u, axis=-1)
		scr = tf.sigmoid(u)
		scr = u / tf.reduce_sum(u, axis=1, keepdims=True)
		self.att = scr
		self.cumulate = self.cumulate + scr
		scr = tf.expand_dims(scr, axis=-1)
		return scr

class Encoder(M.Model):
	def initialize(self, embed_dim, num_chars, cbhg_chn, K, num_highway, dropout):
		self.num_chars = num_chars
		self.embedding = M.Dense(embed_dim)
		self.prenet = PreNet()
		self.cbhg = CBHG(K=K, channels=cbhg_chn, proj_chn=[cbhg_chn, cbhg_chn], num_highway=num_highway)

	def forward(self, x):
		x = self.embedding(x)
		x = self.prenet(x)
		x = self.cbhg(x)
		return x

class Decoder(M.Model):
	def initialize(self, n_mels, dec_dim, lstm_dim):
		self.max_r = 20
		self.r = None
		self.n_mels = n_mels
		self.prenet = PreNet()
		self.att_net = LSA(dec_dim)
		self.att_rnn = GRUCell(dec_dim)
		self.rnn_inp = M.Dense(lstm_dim)
		self.res_rnn1 = LSTMCell(lstm_dim)
		self.res_rnn2 = LSTMCell(lstm_dim)
		self.mel_proj = M.Dense(n_mels * self.max_r, usebias=False)

	def zoneout(self, prev, curr, rate=0.1):
		mask = tf.random.uniform(prev.shape) + 1 - rate
		mask = tf.floor(mask)
		return prev * mask + (1 - mask) * curr

	def forward(self, enc_seq, enc_seq_proj, prenet_in, hid_states, cell_states, context_vec, t):
		t1 = time.time()
		enc_shape = enc_seq.shape
		attn_hid, rnn1_hid, rnn2_hid = hid_states
		rnn1_cell, rnn2_cell = cell_states
		pre_out = self.prenet(prenet_in)
		attn_rnn_in = tf.concat([context_vec, pre_out], axis=-1)

		# next attention hidden state
		attn_hid = self.att_rnn(attn_rnn_in, [attn_hid])[0]

		scrs = self.att_net(enc_seq_proj, attn_hid, t)

		context_vec = tf.transpose(scrs, [0,2,1]) @ enc_seq
		context_vec = tf.squeeze(context_vec, axis=1)

		x = tf.concat([context_vec, attn_hid], axis=1)
		x = self.rnn_inp(x)

		_, (rnn1_hid2, rnn1_cell) = self.res_rnn1(x, (rnn1_hid, rnn1_cell))

		if tf.keras.backend.learning_phase():
			rnn1_hid = self.zoneout(rnn1_hid, rnn1_hid2)
		else:
			rnn1_hid = rnn1_hid2
		x = x + rnn1_hid

		_, (rnn2_hid2, rnn2_cell) = self.res_rnn2(x, (rnn2_hid, rnn2_cell))
		if tf.keras.backend.learning_phase():
			rnn2_hid = self.zoneout(rnn2_hid, rnn2_hid2)
		else:
			rnn2_hid = rnn2_hid2
		x = x + rnn2_hid

		mels = self.mel_proj(x)
		mels = tf.reshape(mels, [enc_shape[0], self.n_mels, self.max_r])[:,:,:self.r]

		hid_states = (attn_hid, rnn1_hid, rnn2_hid)
		cell_states = (rnn1_cell, rnn2_cell)
		# print('DECODER LOOP', time.time() - t1)
		return mels, scrs, hid_states, cell_states, context_vec

class Tacotron(M.Model):
	def initialize(self, embed_dim, num_chars, enc_dim, dec_dim, n_mels, fft_bins, postnet_dim,
					enc_K, lstm_dim, postnet_K, num_highway, dropout):
		self.n_mels = n_mels
		self.lstm_dim = lstm_dim
		self.dec_dim = dec_dim
		self.encoder = Encoder(embed_dim, num_chars, enc_dim, enc_K, num_highway, dropout)
		self.enc_proj = M.Dense(dec_dim, usebias=False)
		self.decoder = Decoder(n_mels, dec_dim, lstm_dim)
		self.postnet = CBHG(postnet_K, postnet_dim, [256, 80], num_highway)
		self.post_proj = M.Dense(fft_bins, usebias=False)

	def set_r(self, r):
		print('SET R:',r)
		self.decoder.r = r
		self.r = r

	def forward(self, x, m):
		m = tf.convert_to_tensor(m)
		bsize, _, step = m.shape

		attn_hid = tf.zeros([bsize, self.dec_dim])
		rnn1_hid = tf.zeros([bsize, self.lstm_dim])
		rnn2_hid = tf.zeros([bsize, self.lstm_dim])
		hid_states = (attn_hid, rnn1_hid, rnn2_hid)
		rnn1_cell = tf.zeros([bsize, self.lstm_dim])
		rnn2_cell = tf.zeros([bsize, self.lstm_dim])
		cell_states = (rnn1_cell, rnn2_cell)

		go_frame = tf.zeros([bsize, self.n_mels]) # starter

		context_vec = tf.zeros([bsize, self.dec_dim])

		t1 = time.time()
		enc_seq = self.encoder(x)
		t2 = time.time()
		enc_seq_proj = self.enc_proj(enc_seq)

		mel_outs, attn_scrs = [] , []
		t3 = time.time()
		for t in range(0, step, self.r):
			prenet_in = m[:,:,t-1] if t>0 else go_frame
			mels, scrs, hid_states, cell_states, context_vec = self.decoder(enc_seq, enc_seq_proj,
																			prenet_in, hid_states, cell_states, context_vec, t)
			mel_outs.append(mels)
			attn_scrs.append(scrs)
		t4 = time.time()
		mel_outs = tf.concat(mel_outs, axis=2)
		mel_outs_t = tf.transpose(mel_outs, [0,2,1])

		post_out = self.postnet(mel_outs_t)
		linear = self.post_proj(post_out)
		linear = tf.transpose(linear, [0,2,1])
		t5 = time.time()

		# print('T', t2-t1, t3-t2, t4-t3, t5-t4)

		# useless for me
		attn_scrs = tf.concat(attn_scrs, axis=1)

		return mel_outs, linear, attn_scrs

	def generate(self, x, steps=20000):
		tf.keras.backend.set_learning_phase(False)
		x = tf.convert_to_tensor(x)
		bsize = 1
		x = tf.expand_dims(x, axis=0)
		attn_hid = tf.zeros([bsize, self.dec_dim])
		rnn1_hid = tf.zeros([bsize, self.lstm_dim])
		rnn2_hid = tf.zeros([bsize, self.lstm_dim])
		hid_states = (attn_hid, rnn1_hid, rnn2_hid)
		rnn1_cell = tf.zeros([bsize, self.lstm_dim])
		rnn2_cell = tf.zeros([bsize, self.lstm_dim])
		cell_states = (rnn1_cell, rnn2_cell)

		go_frame = tf.zeros([bsize, self.n_mels]) # starter

		context_vec = tf.zeros([bsize, self.dec_dim])

		enc_seq = self.encoder(x)
		enc_seq_proj = self.enc_proj(enc_seq)

		mel_outs, attn_scrs = [] , []
		for t in range(0, step, self.r):
			prenet_in = mel_outs[-1][:,:,-1] if t>0 else go_frame
			mels, scrs, hid_states, cell_states, context_vec = self.decoder(enc_seq, enc_seq_proj,
																			prenet_in, hid_states, hid_states, cell_states, context_vec, t)
			mel_outs.append(mels)
			attn_scrs.append(scrs)
			if (mels < -3.8).all() and t > 10: break
		mel_outs = tf.concat(mel_outs, axis=2)

		post_out = self.postnet(mel_outs)
		linear = self.post_proj(post_out)
		linear = tf.transpose(linear, [0,2,1])

		return mel_outs, linear, None


from typing import List, Tuple

white = (1.0, 1.0, 1.0)
black = (0.0, 0.0, 0.0)
dark_gray = (0.25, 0.25, 0.25)
light_purple = (0.788, 0.580, 1.0)
lime = (0.746, 1.0, 0.0)
red = (1.0, 0.0, 0.0)
green = (0.0, 1.0, 0.0)
blue = (0.0, 0.0, 1.0)
orange = (1.0, 0.5, 0.0)
light_cyan = (0.796, 1.0, 1.0)
light_pink = (1.0, 0.796, 1.0)
light_yellow = (1.0, 1.0, 0.796)
light_teal = (0.757, 1.0, 0.949)
gray = (0.5, 0.5, 0.5)
soft_blue = (0.721, 0.90, 1.0)
soft_red = (1.0, 0.0, 0.085)
lime_green = (0.519, 0.819, 0.0)
purple = (0.667, 0.0, 0.429)
gold = (1.0, 0.804, 0.0)

def color_wheel():
    """ Returns:
        (list) a list of all colors defined in the color module.
        Each entry is a tuple of 3 floats (RGB values).
    """
    return [
        white, black, dark_gray, light_purple, lime, red, green, blue, orange, light_cyan, light_pink,
        light_yellow, light_teal, gray, soft_blue, soft_red, lime_green, purple, gold
    ]

def colors_generator(skip_colors: List = None) -> Tuple[float, float, float]:
    """ Generates the next color in the color wheel on each invocation.
        This generator repeats the color wheel cyclically when exhausted.

    Args:
        skip_colors
    """
    if skip_colors is None:
        skip_colors = []
    while True:
        for color in color_wheel():
            if color in skip_colors:
                continue
            yield color


from imports import *

load = True
err = False

clear_output(wait=True)
display(inputs)

hdf5Load = path.expanduser(hdf5Infile.value)
tagmapLoad = path.expanduser(tagmapInfile.value)

if(not path.isfile(hdf5Load)):
    print("File \"{}\" not found".format(hdf5Load))
    err = True
    sys.exit()

if(not re.search('\.hdf5$', hdf5Load)):
    print("File \"{}\" is not a HDF5 file".format(hdf5Load))
    err = True
    sys.exit()

if(not path.isfile(tagmapLoad)):
    print("File \"{}\" not found".format(tagmapLoad))
    err = True
    sys.exit()

if(not re.search('\.csv$', tagmapLoad)):
    print("File \"{}\" is not a csv file".format(tagmapLoad))
    err = True
    sys.exit()

# Right now, we can't load files correctly because we don't store the cache info anywhere,
# so for now we will pull from the widget textboxes until it is added to tag_map
CACHE_SIZE = cache.value
NUM_LINES = lines.value
BLOCK_SIZE = block.value

if(CACHE_SIZE < 0 or NUM_LINES < 0 or BLOCK_SIZE < 0):
    print("Cache Lines, Lines to Output, and Block Size must be positive integers")
    err = True
    sys.exit()


"""Parser for Rust dependency files."""

from typing import List

import toml

from readmeai.parsers.base_parser import FileParser

TOM_DECODE_ERROR = "Error decoding TOML content: {0}"

class CargoTomlParser(FileParser):
    """
    Parser for Rust cargo.toml dependency files.
    """

    def parse(self, content: str) -> List[str]:
        """Extract packages names from Rust TOML files."""
        try:
            data = toml.loads(content)
            dependencies = []
            if "dependencies" in data:
                dependencies.extend(data.get("dependencies", {}).keys())
            if "dev-dependencies" in data:
                dependencies.extend(data.get("dev-dependencies", {}).keys())
            return dependencies

        except toml.TomlDecodeError as error:
            self.log_error(TOM_DECODE_ERROR.format(error))
            return dependencies


#
# @lc app=leetcode id=406 lang=python3
#
# [406] Queue Reconstruction by Height
#

# @lc code=start
class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        people.sort(key = lambda x:(-x[0], x[1]))
        queue = []
        for x in people:
            queue.insert(x[1], x)
        return queue

# @lc code=end


from clifford.g3 import *  # Import 3D geometric algebra functions
import numpy as np

# Spin-1/2 particle properties
mu = 1.0  # Magnetic moment (arbitrary units)
B = e3  # Magnetic field along the z-axis

# Initial state of the spin particle (aligned with the x-axis)
psi = e1

# Time evolution
t_values = np.linspace(0, 10, 100)
spin_evolution = []

for t in t_values:
    # Compute the evolution operator
    U = np.exp(-0.5 * mu * B * t)

    # Apply the evolution operator to the initial state
    psi_t = U * psi * ~U
    spin_evolution.append([float(psi_t[e1]), float(psi_t[e2]), float(psi_t[e3])])

# Visualization
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

spin_evolution = np.array(spin_evolution)
ax.quiver(0, 0, 0, spin_evolution[:, 0], spin_evolution[:, 1], spin_evolution[:, 2], length=0.1, normalize=True, color='g', linewidth=2.5)

ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])
ax.set_title("Evolution of Spin-1/2 Particle in Magnetic Field")
plt.show()


import pytest

@pytest.mark.asyncio
@pytest.mark.parametrize(
    "name, expected_status",
    [
        ('John Doe', 201),
        (None, 400),
    ]
)
async def test_create_sample_resource(
    test_client, mongo_client, name: str, expected_status: int
):
    req_json = {}
    if None is not name:
        req_json["name"] = name

    resp = test_client.post(
        '/api/sample-resource-app/v1/sample-resource',
        json=req_json
    )
    assert resp.status_code == expected_status

    if 201 == expected_status:
        assert 'id' in resp.json()
        resource_id = resp.json().get('id')
        resource_db = await mongo_client.get_sample_resource(resource_id)
        assert resource_db.get('name') == name
        assert False is resource_db.get('deleted')


"""This is the main training interface using heatmap trick

Author: You-Yi Jau, Rui Zhu
Date: 2019/12/12
"""

import numpy as np
import torch
# from torch.autograd import Variable
# import torch.backends.cudnn as cudnn
import torch.optim
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data
# from tqdm import tqdm
# from utils.loader import dataLoader, modelLoader, pretrainedLoader
import logging

from utils.tools import dict_update

# from utils.utils import labels2Dto3D, flattenDetection, labels2Dto3D_flattened
# from utils.utils import pltImshow, saveImg
from utils.utils import precisionRecall_torch
# from utils.utils import save_checkpoint

from pathlib import Path
from Train_model_frontend import Train_model_frontend

def thd_img(img, thd=0.015):
    img[img < thd] = 0
    img[img >= thd] = 1
    return img

def toNumpy(tensor):
    return tensor.detach().cpu().numpy()

def img_overlap(img_r, img_g, img_gray):  # img_b repeat
    img = np.concatenate((img_gray, img_gray, img_gray), axis=0)
    img[0, :, :] += img_r[0, :, :]
    img[1, :, :] += img_g[0, :, :]
    img[img > 1] = 1
    img[img < 0] = 0
    return img

class Train_model_heatmap(Train_model_frontend):
    """ Wrapper around pytorch net to help with pre and post image processing. """

    """
    * SuperPointFrontend_torch:
    ** note: the input, output is different from that of SuperPointFrontend
    heatmap: torch (batch_size, H, W, 1)
    dense_desc: torch (batch_size, H, W, 256)
    pts: [batch_size, np (N, 3)]
    desc: [batch_size, np(256, N)]
    """
    default_config = {
        "train_iter": 170000,
        "save_interval": 2000,
        "tensorboard_interval": 200,
        "model": {"subpixel": {"enable": False}},
        "data": {"gaussian_label": {"enable": False}},
    }

    def __init__(self, config, save_path=Path("."), device="cpu", verbose=False):
        # config
        # Update config
        print("Load Train_model_heatmap!!")

        self.config = self.default_config
        self.config = dict_update(self.config, config)
        print("check config!!", self.config)

        # init parameters
        self.device = device
        self.save_path = save_path
        self._train = True
        self._eval = True
        self.cell_size = 8
        self.subpixel = False

        self.max_iter = config["train_iter"]

        self.gaussian = False
        if self.config["data"]["gaussian_label"]["enable"]:
            self.gaussian = True

        if self.config["model"]["dense_loss"]["enable"]:
            print("use dense_loss!")
            from utils.utils import descriptor_loss
            self.desc_params = self.config["model"]["dense_loss"]["params"]
            self.descriptor_loss = descriptor_loss
            self.desc_loss_type = "dense"
        elif self.config["model"]["sparse_loss"]["enable"]:
            print("use sparse_loss!")
            self.desc_params = self.config["model"]["sparse_loss"]["params"]
            from utils.loss_functions.sparse_loss import batch_descriptor_loss_sparse

            self.descriptor_loss = batch_descriptor_loss_sparse
            self.desc_loss_type = "sparse"

        # load model
        # self.net = self.loadModel(*config['model'])
        self.printImportantConfig()
        pass

    ### loadModel inherited from Train_model_frontend
    # def loadModel(self):
    #     """
    #     load model from name and params
    #     init or load optimizer
    #     :return:
    #     """
    #     model = self.config["model"]["name"]
    #     params = self.config["model"]["params"]
    #     print("model: ", model)
    #     net = modelLoader(model=model, **params).to(self.device)
    #     logging.info("=> setting adam solver")
    #     optimizer = self.adamOptim(net, lr=self.config["model"]["learning_rate"])
    #
    #     n_iter = 0
    #     ## new model or load pretrained
    #     if self.config["retrain"] == True:
    #         logging.info("New model")
    #         pass
    #     else:
    #         path = self.config["pretrained"]
    #         mode = "" if path[:-3] == ".pth" else "full"
    #         logging.info("load pretrained model from: %s", path)
    #         net, optimizer, n_iter = pretrainedLoader(
    #             net, optimizer, n_iter, path, mode=mode, full_path=True
    #         )
    #         logging.info("successfully load pretrained model from: %s", path)
    #
    #     def setIter(n_iter):
    #         if self.config["reset_iter"]:
    #             logging.info("reset iterations to 0")
    #             n_iter = 0
    #         return n_iter
    #
    #     self.net = net
    #     self.optimizer = optimizer
    #     self.n_iter = setIter(n_iter)
    #     pass

    def detector_loss(self, input, target, mask=None, loss_type="softmax"):
        """
        # apply loss on detectors, default is softmax
        :param input: prediction
            tensor [batch_size, 65, Hc, Wc]
        :param target: constructed from labels
            tensor [batch_size, 65, Hc, Wc]
        :param mask: valid region in an image
            tensor [batch_size, 1, Hc, Wc]
        :param loss_type:
            str (l2 or softmax)
            softmax is used in original paper
        :return: normalized loss
            tensor
        """
        if loss_type == "l2":
            loss_func = nn.MSELoss(reduction="mean")
            loss = loss_func(input, target)
        elif loss_type == "softmax":
            loss_func_BCE = nn.BCELoss(reduction='none').cuda()
            loss = loss_func_BCE(nn.functional.softmax(input, dim=1), target)
            loss = (loss.sum(dim=1) * mask).sum()
            loss = loss / (mask.sum() + 1e-10)
        return loss

    def train_val_sample(self, sample, n_iter=0, train=False):
        """
        # key function
        :param sample:
        :param n_iter:
        :param train:
        :return:
        """
        to_floatTensor = lambda x: torch.tensor(x).type(torch.FloatTensor)

        task = "train" if train else "val"
        tb_interval = self.config["tensorboard_interval"]
        if_warp = self.config['data']['warped_pair']['enable']

        self.scalar_dict, self.images_dict, self.hist_dict = {}, {}, {}
        ## get the inputs
        # logging.info('get input img and label')
        img, labels_2D, mask_2D = (
            sample["image"],
            sample["labels_2D"],
            sample["valid_mask"],
        )
        # img, labels = img.to(self.device), labels_2D.to(self.device)

        # variables
        batch_size, H, W = img.shape[0], img.shape[2], img.shape[3]
        self.batch_size = batch_size
        det_loss_type = self.config["model"]["detector_loss"]["loss_type"]
        # print("batch_size: ", batch_size)
        Hc = H // self.cell_size
        Wc = W // self.cell_size

        # warped images
        # img_warp, labels_warp_2D, mask_warp_2D = sample['warped_img'].to(self.device), \
        #     sample['warped_labels'].to(self.device), \
        #     sample['warped_valid_mask'].to(self.device)
        if if_warp:
            img_warp, labels_warp_2D, mask_warp_2D = (
                sample["warped_img"],
                sample["warped_labels"],
                sample["warped_valid_mask"],
            )

        # homographies
        # mat_H, mat_H_inv = \
        # sample['homographies'].to(self.device), sample['inv_homographies'].to(self.device)
        if if_warp:
            mat_H, mat_H_inv = sample["homographies"], sample["inv_homographies"]

        # zero the parameter gradients
        self.optimizer.zero_grad()

        # forward + backward + optimize
        if train:
            # print("img: ", img.shape, ", img_warp: ", img_warp.shape)
            outs = self.net(img.to(self.device))
            semi, coarse_desc = outs["semi"], outs["desc"]
            if if_warp:
                outs_warp = self.net(img_warp.to(self.device))
                semi_warp, coarse_desc_warp = outs_warp["semi"], outs_warp["desc"]
        else:
            with torch.no_grad():
                outs = self.net(img.to(self.device))
                semi, coarse_desc = outs["semi"], outs["desc"]
                if if_warp:
                    outs_warp = self.net(img_warp.to(self.device))
                    semi_warp, coarse_desc_warp = outs_warp["semi"], outs_warp["desc"]
                pass

        # detector loss
        from utils.utils import labels2Dto3D

        if self.gaussian:
            labels_2D = sample["labels_2D_gaussian"]
            if if_warp:
                warped_labels = sample["warped_labels_gaussian"]
        else:
            labels_2D = sample["labels_2D"]
            if if_warp:
                warped_labels = sample["warped_labels"]

        add_dustbin = False
        if det_loss_type == "l2":
            add_dustbin = False
        elif det_loss_type == "softmax":
            add_dustbin = True

        labels_3D = labels2Dto3D(
            labels_2D.to(self.device), cell_size=self.cell_size, add_dustbin=add_dustbin
        ).float()
        mask_3D_flattened = self.getMasks(mask_2D, self.cell_size, device=self.device)
        loss_det = self.detector_loss(
            input=outs["semi"],
            target=labels_3D.to(self.device),
            mask=mask_3D_flattened,
            loss_type=det_loss_type,
        )
        # warp
        if if_warp:
            labels_3D = labels2Dto3D(
                warped_labels.to(self.device),
                cell_size=self.cell_size,
                add_dustbin=add_dustbin,
            ).float()
            mask_3D_flattened = self.getMasks(
                mask_warp_2D, self.cell_size, device=self.device
            )
            loss_det_warp = self.detector_loss(
                input=outs_warp["semi"],
                target=labels_3D.to(self.device),
                mask=mask_3D_flattened,
                loss_type=det_loss_type,
            )
        else:
            loss_det_warp = torch.tensor([0]).float().to(self.device)

        ## get labels, masks, loss for detection
        # labels3D_in_loss = self.getLabels(labels_2D, self.cell_size, device=self.device)
        # mask_3D_flattened = self.getMasks(mask_2D, self.cell_size, device=self.device)
        # loss_det = self.get_loss(semi, labels3D_in_loss, mask_3D_flattened, device=self.device)

        ## warping
        # labels3D_in_loss = self.getLabels(labels_warp_2D, self.cell_size, device=self.device)
        # mask_3D_flattened = self.getMasks(mask_warp_2D, self.cell_size, device=self.device)
        # loss_det_warp = self.get_loss(semi_warp, labels3D_in_loss, mask_3D_flattened, device=self.device)

        mask_desc = mask_3D_flattened.unsqueeze(1)
        lambda_loss = self.config["model"]["lambda_loss"]
        # print("mask_desc: ", mask_desc.shape)
        # print("mask_warp_2D: ", mask_warp_2D.shape)

        # descriptor loss
        if lambda_loss > 0:
            assert if_warp == True, "need a pair of images"
            loss_desc, mask, positive_dist, negative_dist = self.descriptor_loss(
                coarse_desc,
                coarse_desc_warp,
                mat_H,
                mask_valid=mask_desc,
                device=self.device,
                **self.desc_params
            )
        else:
            ze = torch.tensor([0]).to(self.device)
            loss_desc, positive_dist, negative_dist = ze, ze, ze

        loss = loss_det + loss_det_warp
        if lambda_loss > 0:
            loss += lambda_loss * loss_desc

        ##### try to minimize the error ######
        add_res_loss = False
        if add_res_loss and n_iter % 10 == 0:
            print("add_res_loss!!!")
            heatmap_org = self.get_heatmap(semi, det_loss_type)  # tensor []
            heatmap_org_nms_batch = self.heatmap_to_nms(
                self.images_dict, heatmap_org, name="heatmap_org"
            )
            if if_warp:
                heatmap_warp = self.get_heatmap(semi_warp, det_loss_type)
                heatmap_warp_nms_batch = self.heatmap_to_nms(
                    self.images_dict, heatmap_warp, name="heatmap_warp"
                )

            # original: pred
            ## check the loss on given labels!
            outs_res = self.get_residual_loss(
                sample["labels_2D"]
                * to_floatTensor(heatmap_org_nms_batch).unsqueeze(1),
                heatmap_org,
                sample["labels_res"],
                name="original_pred",
            )
            loss_res_ori = (outs_res["loss"] ** 2).mean()
            # warped: pred
            if if_warp:
                outs_res_warp = self.get_residual_loss(
                    sample["warped_labels"]
                    * to_floatTensor(heatmap_warp_nms_batch).unsqueeze(1),
                    heatmap_warp,
                    sample["warped_res"],
                    name="warped_pred",
                )
                loss_res_warp = (outs_res_warp["loss"] ** 2).mean()
            else:
                loss_res_warp = torch.tensor([0]).to(self.device)
            loss_res = loss_res_ori + loss_res_warp
            # print("loss_res requires_grad: ", loss_res.requires_grad)
            loss += loss_res
            self.scalar_dict.update(
                {"loss_res_ori": loss_res_ori, "loss_res_warp": loss_res_warp}
            )

        #######################################

        self.loss = loss

        self.scalar_dict.update(
            {
                "loss": loss,
                "loss_det": loss_det,
                "loss_det_warp": loss_det_warp,
                "positive_dist": positive_dist,
                "negative_dist": negative_dist,
            }
        )

        self.input_to_imgDict(sample, self.images_dict)

        if train:
            loss.backward()
            self.optimizer.step()

        if n_iter % tb_interval == 0 or task == "val":
            logging.info(
                "current iteration: %d, tensorboard_interval: %d", n_iter, tb_interval
            )

            # add clean map to tensorboard
            ## semi_warp: flatten, to_numpy

            heatmap_org = self.get_heatmap(semi, det_loss_type)  # tensor []
            heatmap_org_nms_batch = self.heatmap_to_nms(
                self.images_dict, heatmap_org, name="heatmap_org"
            )
            if if_warp:
                heatmap_warp = self.get_heatmap(semi_warp, det_loss_type)
                heatmap_warp_nms_batch = self.heatmap_to_nms(
                    self.images_dict, heatmap_warp, name="heatmap_warp"
                )

            def update_overlap(
                images_dict, labels_warp_2D, heatmap_nms_batch, img_warp, name
            ):
                # image overlap
                from utils.draw import img_overlap

                # result_overlap = img_overlap(img_r, img_g, img_gray)
                # overlap label, nms, img
                nms_overlap = [
                    img_overlap(
                        toNumpy(labels_warp_2D[i]),
                        heatmap_nms_batch[i],
                        toNumpy(img_warp[i]),
                    )
                    for i in range(heatmap_nms_batch.shape[0])
                ]
                nms_overlap = np.stack(nms_overlap, axis=0)
                images_dict.update({name + "_nms_overlap": nms_overlap})

            from utils.var_dim import toNumpy
            update_overlap(
                self.images_dict,
                labels_2D,
                heatmap_org_nms_batch[np.newaxis, ...],
                img,
                "original",
            )

            update_overlap(
                self.images_dict,
                labels_2D,
                toNumpy(heatmap_org),
                img,
                "original_heatmap",
            )
            if if_warp:
                update_overlap(
                    self.images_dict,
                    labels_warp_2D,
                    heatmap_warp_nms_batch[np.newaxis, ...],
                    img_warp,
                    "warped",
                )
                update_overlap(
                    self.images_dict,
                    labels_warp_2D,
                    toNumpy(heatmap_warp),
                    img_warp,
                    "warped_heatmap",
                )
            # residuals
            from utils.losses import do_log

            if self.gaussian:
                # original: gt
                self.get_residual_loss(
                    sample["labels_2D"],
                    sample["labels_2D_gaussian"],
                    sample["labels_res"],
                    name="original_gt",
                )
                if if_warp:
                    # warped: gt
                    self.get_residual_loss(
                        sample["warped_labels"],
                        sample["warped_labels_gaussian"],
                        sample["warped_res"],
                        name="warped_gt",
                    )

            # from utils.losses import do_log
            # patches_log = do_log(patches)

            # original: pred
            ## check the loss on given labels!
            # self.get_residual_loss(
            #     sample["labels_2D"]
            #     * to_floatTensor(heatmap_org_nms_batch).unsqueeze(1),
            #     heatmap_org,
            #     sample["labels_res"],
            #     name="original_pred",
            # )
            # print("heatmap_org_nms_batch: ", heatmap_org_nms_batch.shape)
            # get_residual_loss(to_floatTensor(heatmap_org_nms_batch).unsqueeze(1), heatmap_org,
            # sample['labels_res'], name='original_pred')
            # warped: pred
            # self.get_residual_loss(
            #     sample["warped_labels"]
            #     * to_floatTensor(heatmap_warp_nms_batch).unsqueeze(1),
            #     heatmap_warp,
            #     sample["warped_res"],
            #     name="warped_pred",
            # )
            # get_residual_loss(to_floatTensor(heatmap_warp_nms_batch).unsqueeze(1), heatmap_warp,
            # sample['warped_res'], name='warped_pred')

            # precision, recall
            # pr_mean = self.batch_precision_recall(
            #     to_floatTensor(heatmap_warp_nms_batch[:, np.newaxis, ...]),
            #     sample["warped_labels"],
            # )
            pr_mean = self.batch_precision_recall(
                to_floatTensor(heatmap_org_nms_batch[:, np.newaxis, ...]),
                sample["labels_2D"],
            )
            print("pr_mean")
            self.scalar_dict.update(pr_mean)

            self.printLosses(self.scalar_dict, task)
            self.tb_images_dict(task, self.images_dict, max_img=2)
            self.tb_hist_dict(task, self.hist_dict)

        self.tb_scalar_dict(self.scalar_dict, task)

        return loss.item()

    def heatmap_to_nms(self, images_dict, heatmap, name):
        """
        return:
            heatmap_nms_batch: np [batch, H, W]
        """
        from utils.var_dim import toNumpy

        heatmap_np = toNumpy(heatmap)
        ## heatmap_nms
        heatmap_nms_batch = [self.heatmap_nms(h) for h in heatmap_np]  # [batch, H, W]
        heatmap_nms_batch = np.stack(heatmap_nms_batch, axis=0)
        # images_dict.update({name + '_nms_batch': heatmap_nms_batch})
        images_dict.update({name + "_nms_batch": heatmap_nms_batch[:, np.newaxis, ...]})
        return heatmap_nms_batch

    def get_residual_loss(self, labels_2D, heatmap, labels_res, name=""):
        if abs(labels_2D).sum() == 0:
            return
        outs_res = self.pred_soft_argmax(
            labels_2D, heatmap, labels_res, patch_size=5, device=self.device
        )
        self.hist_dict[name + "_resi_loss_x"] = outs_res["loss"][:, 0]
        self.hist_dict[name + "_resi_loss_y"] = outs_res["loss"][:, 1]
        err = abs(outs_res["loss"]).mean(dim=0)
        # print("err[0]: ", err[0])
        var = abs(outs_res["loss"]).std(dim=0)
        self.scalar_dict[name + "_resi_loss_x"] = err[0]
        self.scalar_dict[name + "_resi_loss_y"] = err[1]
        self.scalar_dict[name + "_resi_var_x"] = var[0]
        self.scalar_dict[name + "_resi_var_y"] = var[1]
        self.images_dict[name + "_patches"] = outs_res["patches"]
        return outs_res

    # tb_images_dict.update({'image': sample['image'], 'valid_mask': sample['valid_mask'],
    #     'labels_2D': sample['labels_2D'], 'warped_img': sample['warped_img'],
    #     'warped_valid_mask': sample['warped_valid_mask']})
    # if self.gaussian:
    #     tb_images_dict.update({'labels_2D_gaussian': sample['labels_2D_gaussian'],
    #     'labels_2D_gaussian': sample['labels_2D_gaussian']})

    ######## static methods ########
    @staticmethod
    def batch_precision_recall(batch_pred, batch_labels):
        precision_recall_list = []
        for i in range(batch_labels.shape[0]):
            precision_recall = precisionRecall_torch(batch_pred[i], batch_labels[i])
            precision_recall_list.append(precision_recall)
        precision = np.mean(
            [
                precision_recall["precision"]
                for precision_recall in precision_recall_list
            ]
        )
        recall = np.mean(
            [precision_recall["recall"] for precision_recall in precision_recall_list]
        )
        return {"precision": precision, "recall": recall}

    @staticmethod
    def pred_soft_argmax(labels_2D, heatmap, labels_res, patch_size=5, device="cuda"):
        """

        return:
            dict {'loss': mean of difference btw pred and res}
        """
        from utils.losses import norm_patches

        outs = {}
        # extract patches
        from utils.losses import extract_patches
        from utils.losses import soft_argmax_2d

        label_idx = labels_2D[...].nonzero().long()

        # patch_size = self.config['params']['patch_size']
        patches = extract_patches(
            label_idx.to(device), heatmap.to(device), patch_size=patch_size
        )
        # norm patches
        patches = norm_patches(patches)

        # predict offsets
        from utils.losses import do_log

        patches_log = do_log(patches)
        # soft_argmax
        dxdy = soft_argmax_2d(
            patches_log, normalized_coordinates=False
        )  # tensor [B, N, patch, patch]
        dxdy = dxdy.squeeze(1)  # tensor [N, 2]
        dxdy = dxdy - patch_size // 2

        # extract residual
        def ext_from_points(labels_res, points):
            """
            input:
                labels_res: tensor [batch, channel, H, W]
                points: tensor [N, 4(pos0(batch), pos1(0), pos2(H), pos3(W) )]
            return:
                tensor [N, channel]
            """
            labels_res = labels_res.transpose(1, 2).transpose(2, 3).unsqueeze(1)
            points_res = labels_res[
                points[:, 0], points[:, 1], points[:, 2], points[:, 3], :
            ]  # tensor [N, 2]
            return points_res

        points_res = ext_from_points(labels_res, label_idx)

        # loss
        outs["pred"] = dxdy
        outs["points_res"] = points_res
        # ls = lambda x, y: dxdy.cpu() - points_res.cpu()
        # outs['loss'] = dxdy.cpu() - points_res.cpu()
        outs["loss"] = dxdy.to(device) - points_res.to(device)
        outs["patches"] = patches
        return outs

    @staticmethod
    def flatten_64to1(semi, cell_size=8):
        """
        input:
            semi: tensor[batch, cell_size*cell_size, Hc, Wc]
            (Hc = H/8)
        outpus:
            heatmap: tensor[batch, 1, H, W]
        """
        from utils.d2s import DepthToSpace

        depth2space = DepthToSpace(cell_size)
        heatmap = depth2space(semi)
        return heatmap

    @staticmethod
    def heatmap_nms(heatmap, nms_dist=4, conf_thresh=0.015):
        """
        input:
            heatmap: np [(1), H, W]
        """
        from utils.utils import getPtsFromHeatmap

        # nms_dist = self.config['model']['nms']
        # conf_thresh = self.config['model']['detection_threshold']
        heatmap = heatmap.squeeze()
        # print("heatmap: ", heatmap.shape)
        pts_nms = getPtsFromHeatmap(heatmap, conf_thresh, nms_dist)
        semi_thd_nms_sample = np.zeros_like(heatmap)
        semi_thd_nms_sample[
            pts_nms[1, :].astype(np.int), pts_nms[0, :].astype(np.int)
        ] = 1
        return semi_thd_nms_sample

if __name__ == "__main__":
    # load config
    filename = "configs/superpoint_coco_train_heatmap.yaml"
    import yaml

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    torch.set_default_tensor_type(torch.FloatTensor)
    with open(filename, "r") as f:
        config = yaml.load(f)

    from utils.loader import dataLoader as dataLoader

    # data = dataLoader(config, dataset='hpatches')
    task = config["data"]["dataset"]

    data = dataLoader(config, dataset=task, warp_input=True)
    # test_set, test_loader = data['test_set'], data['test_loader']
    train_loader, val_loader = data["train_loader"], data["val_loader"]

    # model_fe = Train_model_frontend(config)
    # print('==> Successfully loaded pre-trained network.')

    train_agent = Train_model_heatmap(config, device=device)

    train_agent.train_loader = train_loader
    # train_agent.val_loader = val_loader

    train_agent.loadModel()
    train_agent.dataParallel()
    train_agent.train()

    # epoch += 1
    try:
        model_fe.train()

    # catch exception
    except KeyboardInterrupt:
        logging.info("ctrl + c is pressed. save model")
    # is_best = True


from __future__ import print_function
import os.path
import json
import requests
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from pprint import pprint
from flask import jsonify
from flask import Flask
import json

app = Flask(__name__)

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

# The ID and range of a sample spreadsheet.
SAMPLE_SPREADSHEET_ID = '1OZuvbuA1sIAHRtdIeK80MLDmgqP_O-nVItIUXwJZJPM'
SAMPLE_RANGE_NAME = 'Pagina1!A1:K60'
CLIENT_SECRET_FILE = r'C:\Projetos\python\Projetos\CRIE\client_secret.json'
JSON_TASK = r'C:\Projetos\python\Projetos\CRIE_API\tasks.json'

# Busca registros na Tabela do Google Sheets
def buscareg():
    creds = None

    # Verifico se existe token no path do projeto
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)

    # Verifica se a autorização não está expirada
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                CLIENT_SECRET_FILE, SCOPES)
            creds = flow.run_local_server(port=0)

        # Salva a credencial para proximas requisições
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    # Conectando na planilha do google
    service = build('sheets', 'v4', credentials=creds)

    sheet = service.spreadsheets()
    result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
                                range=SAMPLE_RANGE_NAME).execute()
    values = result.get('values', [])

    valuesnew = []
    for a in range(1,len(values)):
        #Sobe na Plataforma?
        if values[a][10] == "Sim"  and a > 1:
            valuesnew.append(values[a])

    return valuesnew

data=buscareg()

# parse file
with open(JSON_TASK, 'w') as f:
    json.dump(data, f)

with open(JSON_TASK, 'r') as myfile:
    data=myfile.read()
# parse file
obj = json.loads(data)

# obj = json.loads(data)

@app.route('/todo/getall',methods=['GET'])
def getTasks():
    return jsonify(obj)

app.run(debug=True)


from flask import Flask, render_template, url_for, jsonify, request, redirect
from data import queries
import math
from dotenv import load_dotenv

load_dotenv()
app = Flask('codecool_series')

@app.route('/')
def index():
    shows = queries.get_shows()
    return render_template('index.html', shows=shows)

@app.route('/design')
def design():
    return render_template('design.html')

@app.route('/shows')
def shows():
    return redirect(url_for('most_rated'))

@app.route('/shows/most-rated')
def most_rated():
    return render_template('most_rated.html')

@app.route('/count-shows')
def count_shows():
    shows_count = len( queries.get_all_shows() )
    return jsonify({'count': shows_count})

@app.route('/get-shows', methods=['POST'])
def get_shows():
    offset = request.get_json()['offset']
    order_by = request.get_json()['order_by']
    order_direction = request.get_json()['order_direction']
    shows_a = queries.ez_nem_mukodik(str(offset), str(order_by), str(order_direction))
    print(shows_a)
    return jsonify(shows_a)

@app.route('/show/<show_id>')
def show_details(show_id):
    show = queries.get_show_details(show_id)

    runtime_total_min = int(show['runtime'])
    runtime_hours = runtime_total_min // 60
    runtime_min = runtime_total_min % 60

    if runtime_hours == 0:
        runtime = f'{runtime_min}min'
    else:
        if runtime_min == 0:
            runtime = f'{runtime_hours}h'
        else:
            runtime = f'{runtime_hours}h{runtime_min}min'

    if show['trailer'] is not None:
        trailer_id = show['trailer'][-11:]
        show['trailer'] = f'https://www.youtube.com/embed/{trailer_id}'

    seasons = queries.get_seasons(show_id)

    return render_template('show_details.html', show=show, runtime=runtime, seasons=seasons)

@app.route('/actors')
def actors():
    return render_template('actors.html')

@app.route('/get-actors')
def get_actors():
    actors_list = queries.get_actors()
    return jsonify(actors_list)

@app.route('/get-actors-shows', methods=['POST'])
def actors_show():
    actor_id = request.get_json()['actorId']
    shows_list = queries.get_actors_shows(actor_id)
    return jsonify(shows_list)

@app.route('/ratings')
def ratings():
    avg_rating = queries.avg_rating()['avg_rating']
    shows = queries.show_ratings()

    for show in shows:
        show['rating'] = show['rating']-avg_rating

    return render_template('ratings.html', avg_rating=avg_rating, shows=shows)

@app.route('/ordered-shows', methods= ['GET','POST'])
def ordered_shows():
    if request.method == 'GET':
        return render_template('ordered-shows.html')
    elif request.method == 'POST':
        order_direction = request.get_json()['order_dir']
        shows = queries.ordered_shows(order_direction)

        for show in shows:
            rating = int(round(float(show['rating']), 0))
            show['rating'] = ''
            for i in range(rating):
                print(i)
                show['rating'] += '*'

        return jsonify(shows)

@app.route('/filter-actors', methods=['GET', 'POST'])
def filter_actors():
    if request.method == 'GET':
        return render_template('filter-actors.html')
    elif request.method == 'POST':
        actor = request.get_json() ['actor']
        genre_id = request.get_json()['genreId']
        actors_list = queries.filter_actors(actor, genre_id)
        return jsonify(actors_list)

@app.route('/get-genres')
def get_genres():
    genres = queries.get_genres()
    return jsonify(genres)

def main():
    app.run(
        debug=True,
    )

if __name__ == '__main__':
    main()


import utils, configs
import argparse
import seaborn as sns
import pandas as pd
import numpy as np

# import plotly as py
# import plotly.graph_objs as go
import matplotlib.pyplot as plt

from tqdm.auto import tqdm

# from skimage import draw
from sklearn.metrics import roc_curve
from sklearn.metrics import average_precision_score
from sklearn.metrics import roc_auc_score, precision_recall_curve, auc
from sklearn.neighbors import NearestNeighbors, KernelDensity
from sklearn import svm

from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.decomposition import FastICA, PCA

def multi_df_stats(df, index):
    stats = pd.DataFrame(index=index, columns=["median", "mean", "std"], dtype=np.float32)
    stats["median"] = df.median(axis=1)
    stats["mean"] = df.mean(axis=1)
    stats["std"] = df.std(axis=1)

    return stats

def result_dict(train_score, test_score, ood_scores, metrics):
    return {
        "train_scores": train_score,
        "test_scores": test_score,
        "ood_scores": ood_scores,
        "metrics": metrics,
    }

def get_metrics(test_score, ood_scores, labels, **kwargs):
    metrics = {}
    for idx, _score in enumerate(ood_scores):
        ood_name = labels[idx + 2]
        metrics[ood_name] = ood_metrics(test_score, _score, names=(labels[1], ood_name))
    metrics_df = pd.DataFrame(metrics).T * 100  # Percentages
    return metrics_df

def auxiliary_model_analysis(
    X_train,
    X_test,
    outliers,
    labels,
    components_range=range(2, 21, 2),
    ica_range=range(2, 8, 2),
    flow_epochs=1000,
    verbose=True,
    pca_gmm=False,
    kde=False
):
    if verbose: print("=====" * 5 + " Training GMM " + "=====" * 5)
    best_gmm_clf = train_gmm(
        X_train, components_range=components_range, ica_range=ica_range, verbose=verbose
    )
    if verbose:
        print("---Likelihoods---")
        print("Training: {:.3f}".format(np.median(best_gmm_clf.score_samples(X_train))))
        print("{}: {:.3f}".format(labels[1], np.median(best_gmm_clf.score_samples(X_test))))

        for name, ood in zip(labels[2:], outliers):
            print("{}: {:.3f}".format(name, np.median(best_gmm_clf.score_samples(ood))))

    gmm_train_score = best_gmm_clf.score_samples(X_train)
    gmm_test_score = best_gmm_clf.score_samples(X_test)
    gmm_ood_scores = np.array([best_gmm_clf.score_samples(ood) for ood in outliers])
    gmm_metrics = get_metrics(-gmm_test_score, -gmm_ood_scores, labels)
    gmm_results = result_dict(
        gmm_train_score, gmm_test_score, gmm_ood_scores, gmm_metrics
    )

    pca_gmm_results=None
    if pca_gmm:
        best_gmm_clf = train_gmm(
            X_train, components_range=components_range, ica_range=ica_range, verbose=verbose, pca=True
        )

        gmm_train_score = best_gmm_clf.score_samples(X_train)
        gmm_test_score = best_gmm_clf.score_samples(X_test)
        gmm_ood_scores = np.array([best_gmm_clf.score_samples(ood) for ood in outliers])
        gmm_metrics = get_metrics(-gmm_test_score, -gmm_ood_scores, labels)
        pca_gmm_results = result_dict(
            gmm_train_score, gmm_test_score, gmm_ood_scores, gmm_metrics
        )

    kde_results=None
    if kde:
        if verbose: print("=====" * 5 + " Training KDE Model " + "=====" * 5)
        kde_model = train_kde(X_train, bandwidth_range=[0.5, 1.0, 1.5, 2.0, 2.5, 3.0], verbose=verbose)

        kde_train_score = kde_model.score_samples(X_train) ## Likelihoods
        kde_test_score  =  kde_model.score_samples(X_test)
        kde_ood_scores = np.array([kde_model.score_samples(ood) for ood in outliers])
        kde_metrics = get_metrics(-kde_test_score, -kde_ood_scores, labels)
        kde_results = result_dict(
            kde_train_score, kde_test_score, kde_ood_scores, kde_metrics
        )

    # if verbose: print("=====" * 5 + " Training OCSVM Model " + "=====" * 5)
    # ocsvm_model = svm.OneClassSVM(kernel="rbf",verbose=False, max_iter=10000,
    #                   tol=1e-6, nu=0.01, gamma="scale", shrinking=True).fit(X_train) #(kernel='exponential', bandwidth=0.5,

    # ocsvm_train_score = -ocsvm_model.decision_function(X_train) ## Likelihoods
    # ocsvm_test_score  =  -ocsvm_model.decision_function(X_test)
    # ocsvm_ood_scores = np.array([-ocsvm_model.decision_function(ood) for ood in outliers])
    # ocsvm_metrics = get_metrics(ocsvm_test_score, ocsvm_ood_scores, labels)
    # ocsvm_results = result_dict(
    #     ocsvm_train_score, ocsvm_test_score, ocsvm_ood_scores, ocsvm_metrics
    # )

    if verbose: print("=====" * 5 + " Training KD Tree " + "=====" * 5)
    kd_results = None
    N_NEIGHBOURS = 2
    nbrs = NearestNeighbors(n_neighbors=N_NEIGHBOURS, algorithm="kd_tree").fit(X_train)

    kd_train_score, indices = nbrs.kneighbors(X_train)
    kd_train_score = kd_train_score[..., -1]  # Distances to the kth neighbour
    kd_test_score, _ = nbrs.kneighbors(X_test)
    kd_test_score = kd_test_score[..., -1]
    kd_ood_scores = []
    for ood in outliers:
        dists, _ = nbrs.kneighbors(ood)
        kd_ood_scores.append(dists[..., -1])
    kd_metrics = get_metrics(kd_test_score, kd_ood_scores, labels)

    kd_results = result_dict(kd_train_score, kd_test_score, kd_ood_scores, kd_metrics)

    return {
        "PCA-GMM":pca_gmm_results,
        "GMM":gmm_results,
            "KDE":kde_results,
            "KD Tree":kd_results
           }

def train_gmm(
    X_train, components_range=range(2, 21, 2), ica_range=[2, 4, 8],
    verbose=False, pca=False
):
    from sklearn.mixture import GaussianMixture
    from sklearn.model_selection import GridSearchCV
    from sklearn.preprocessing import StandardScaler, MinMaxScaler
    from sklearn.pipeline import Pipeline
    from sklearn.decomposition import FastICA, PCA

    def scorer(gmm, X, y=None):
        return np.quantile(gmm.score_samples(X), 0.1)

#     def bic_scorer(model, X, y=None):
#         return -model["GMM"].bic(model["scaler"].transform(X))

#         return -model["GMM"].bic(model["ICA"].transform(X))

    gmm_clf = Pipeline(
        [
            # ("ICA", FastICA(n_components=10)),
            ("PCA", PCA(n_components=5)) if pca else ("scaler", StandardScaler()),
            ("GMM", GaussianMixture(
                init_params="kmeans",
                covariance_type="full",
                max_iter=100000)),
        ]
    )

    param_grid = dict(
#         ICA__n_components=ica_range,
        # ICA__max_iter=[10000],
#         ICA__tol=[1e-2],

        GMM__n_components=components_range,
#         GMM__covariance_type=["full"],
    )  # Full always performs best

    grid = GridSearchCV(
        estimator=gmm_clf,
        param_grid=param_grid,
        cv=5,
        n_jobs=1,
        verbose=verbose,
        scoring=scorer,
    )

    grid_result = grid.fit(X_train)

    if verbose:
        print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
        print("-----" * 15)
        means = grid_result.cv_results_["mean_test_score"]
        stds = grid_result.cv_results_["std_test_score"]
        params = grid_result.cv_results_["params"]
        for mean, stdev, param in zip(means, stds, params):
            print("%f (%f) with: %r" % (mean, stdev, param))

        plt.plot([p["GMM__n_components"] for p in params], means)
        plt.show()

    # best_gmm_clf = gmm_clf.set_params(**grid.best_params_)
    # best_gmm_clf.fit(X_train)
#     print(grid.best_estimator_["GMM"])
    return grid.best_estimator_

def train_kde(
    X_train, bandwidth_range=[1.0, 1.5, 2.0],
    verbose=False, pca=False
):

    def scorer(kde, X, y=None):
        return np.sum(kde.score_samples(X))
        # return np.quantile(kde.score_samples(X), 0.1)

    kde_clf = Pipeline(
        [
            # ("scaler", StandardScaler()),
            ("KDE", KernelDensity())
        ]
    )

    param_grid = dict(

        KDE__bandwidth=bandwidth_range,
        KDE__kernel=['gaussian','exponential'],
    )
    grid = GridSearchCV(
        estimator=kde_clf,
        param_grid=param_grid,
        cv=5,
        n_jobs=1,
        verbose=verbose,
        scoring=scorer,
    )

    grid_result = grid.fit(X_train)

    if verbose:
        print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
        print("-----" * 15)
        means = grid_result.cv_results_["mean_test_score"]
        stds = grid_result.cv_results_["std_test_score"]
        params = grid_result.cv_results_["params"]
        for mean, stdev, param in zip(means, stds, params):
            print("%f (%f) with: %r" % (mean, stdev, param))

        plt.plot([p["KDE__bandwidth"] for p in params], means)
        plt.show()

    return grid.best_estimator_

def plot_curves(inlier_score, outlier_score, label, axs=()):

    if len(axs) == 0:
        fig, axs = plt.subplots(1, 2, figsize=(16, 4))

    y_true = np.concatenate((np.zeros(len(inlier_score)), np.ones(len(outlier_score))))
    y_scores = np.concatenate((inlier_score, outlier_score))

    fpr, tpr, thresholds = roc_curve(y_true, y_scores, drop_intermediate=True)
    roc_auc = roc_auc = roc_auc_score(y_true, y_scores)

    prec_in, rec_in, _ = precision_recall_curve(y_true, y_scores)
    prec_out, rec_out, _ = precision_recall_curve((y_true == 0), -y_scores)
    pr_auc = auc(rec_in, prec_in)

    ticks = np.arange(0.0, 1.1, step=0.1)
    axs[0].plot(fpr, tpr, label="{}: {:.3f}".format(label, roc_auc))
    axs[0].set(
        xlabel="FPR",
        ylabel="TPR",
        title="ROC",
        ylim=(-0.05, 1.05),
        xticks=ticks,
        yticks=ticks,
    )

    axs[1].plot(rec_in, prec_in, label="{}: {:.3f}".format(label, pr_auc))
    # axs[1].plot(rec_out, prec_out, label="PR-Out")
    axs[1].set(
        xlabel="Recall",
        ylabel="Precision",
        title="Precision-Recall",
        ylim=(-0.05, 1.05),
        xticks=ticks,
        yticks=ticks,
    )

    axs[0].legend()
    axs[1].legend()

    if len(axs) == 0:
        fig.suptitle("{} vs {}".format(*labels), fontsize=20)
        plt.show()
        plt.close()

    return axs

def ood_metrics(
    inlier_score, outlier_score, plot=False, verbose=False, names=["Inlier", "Outlier"]
):
    import numpy as np
    import seaborn as sns

    y_true = np.concatenate((np.zeros(len(inlier_score)), np.ones(len(outlier_score))))
    y_scores = np.concatenate((inlier_score, outlier_score))

    prec_in, rec_in, _ = precision_recall_curve(y_true, y_scores)

    # Outliers are treated as "positive" class
    # i.e label 1 is now label 0
    prec_out, rec_out, _ = precision_recall_curve((y_true == 0), -y_scores)

    fpr, tpr, thresholds = roc_curve(y_true, y_scores, drop_intermediate=False)

    # rtol=1e-3 implies range of [0.949, 0.951]
    find_fpr = np.isclose(tpr, 0.95, rtol=1e-3, atol=1e-4).any()

    if find_fpr:
        tpr99_idx = np.where(np.isclose(tpr, 0.99, rtol=-1e-3, atol=1e-4))[0][0]
        tpr95_idx = np.where(np.isclose(tpr, 0.95, rtol=1e-3, atol=1e-4))[0][0]
        tpr80_idx = np.where(np.isclose(tpr, 0.8, rtol=1e-2, atol=1e-3))[0][0]
    else:
        # This is becasuse numpy bugs out when the scores are fully separable
        # OR fully unseparable :D
        tpr99_idx = np.where(np.isclose(tpr, 0.99, rtol=1e-2, atol=1e-2))[0][0]
        # print("Clipping 99 TPR to:", tpr[tpr99_idx])
        if np.isclose(tpr, 0.95, rtol=-1e-2, atol=3e-2).any():
            tpr95_idx = np.where(np.isclose(tpr, 0.95, rtol=-1e-2, atol=3e-2))[0][0]
        else:
            tpr95_idx = np.where(np.isclose(tpr, 0.95, rtol=2e-2, atol=3e-2))[0][0]
            print("Clipping 95 TPR to:", tpr[tpr95_idx])
#         tpr80_idx = np.where(np.isclose(tpr, 0.8, rtol=-5e-2, atol=5e-2))[0][0]
    #         tpr95_idx, tpr80_idx = 0,0 #tpr95_idx

#     print("Clipping 95 TPR to:", tpr[tpr95_idx])
#     print("Clipping 99 TPR to:", tpr[tpr99_idx])

    # Detection Error
    de = np.min(0.5 - tpr / 2 + fpr / 2)

    metrics = dict(
        true_tpr95=tpr[tpr95_idx],
        fpr_tpr99=fpr[tpr99_idx],
        fpr_tpr95=fpr[tpr95_idx],
        de=de,
        roc_auc=roc_auc_score(y_true, y_scores),
        pr_auc_in=auc(rec_in, prec_in),
        pr_auc_out=auc(rec_out, prec_out),
#         fpr_tpr80=fpr[tpr80_idx],
        ap=average_precision_score(y_true, y_scores),
    )

    if plot:

        fig, axs = plt.subplots(1, 2, figsize=(16, 4))
        fpr, tpr, thresholds = roc_curve(y_true, y_scores, drop_intermediate=True)
        ticks = np.arange(0.0, 1.1, step=0.1)

        axs[0].plot(fpr, tpr)
        axs[0].set(
            xlabel="FPR",
            ylabel="TPR",
            title="ROC",
            ylim=(-0.05, 1.05),
            xticks=ticks,
            yticks=ticks,
        )

        axs[1].plot(rec_in, prec_in, label="PR-In")
        axs[1].plot(rec_out, prec_out, label="PR-Out")
        axs[1].set(
            xlabel="Recall",
            ylabel="Precision",
            title="Precision-Recall",
            ylim=(-0.05, 1.05),
            xticks=ticks,
            yticks=ticks,
        )
        axs[1].legend()
        fig.suptitle("{} vs {}".format(*names), fontsize=20)
    #         plt.show()
    #         plt.close()

    if verbose:
        print("{} vs {}".format(*names))
        print("----------------")
        print("ROC-AUC: {:.4f}".format(metrics["roc_auc"] * 100))
        print(
            "PR-AUC (In/Out): {:.4f} / {:.4f}".format(
                metrics["pr_auc_in"] * 100, metrics["pr_auc_out"] * 100
            )
        )
        print("FPR (95% TPR): {:.2f}%".format(metrics["fpr_tpr95"] * 100))
        print("Detection Error: {:.2f}%".format(de * 100))
        print("FPR (99% TPR): {:.2f}%".format(metrics["fpr_tpr99"] * 100))

    return metrics

def evaluate_model(
    train_score, inlier_score, outlier_scores, labels, ylim=None, xlim=None, **kwargs
):
    rows = 1 + int(np.ceil(len(outlier_scores) / 2))
    fig, axs = plt.subplots(rows, 1, figsize=(12, rows * 4))
    axs = np.array(axs).reshape(-1)  # Makes axs into list even if row num is 1
    colors = sns.color_palette("bright") + sns.color_palette("dark")

    sns.histplot(train_score, color=colors[0], label=labels[0], ax=axs[0], **kwargs)
    sns.histplot(inlier_score, color=colors[1], label=labels[1], ax=axs[0], **kwargs)

    offset = 2
    for idx, _score in enumerate(outlier_scores):
        idx += offset
        sns.histplot(_score, color=colors[idx], label=labels[idx], ax=axs[0], **kwargs)

    # Plot in pairs
    if len(outlier_scores) > 0:
        offset = 0
        for row in range(1, axs.shape[0]):
            sns.histplot(
                inlier_score, color=colors[1], label=labels[1], ax=axs[row], **kwargs
            )

            #         for idx in range(offset, min(len(outlier_sc)offset+2)):
            for idx, _score in enumerate(outlier_scores[offset : offset + 2]):
                idx += offset + 2
                sns.histplot(
                    _score, color=colors[idx], label=labels[idx], ax=axs[row], **kwargs
                )
            offset = 2 * row

    for ax in axs:
        ax.legend()
        ax.set_ylim(top=ylim)
        ax.set_xlim(left=xlim, right=10 if xlim else None)

    #     plt.show()

    return axs


from dotenv import load_dotenv
from os import environ
from http import HTTPStatus

from errors.application_error import ApplicationError

class EnvironmentUtility:

    @classmethod
    def initialize_environment_utility(cls):
        load_dotenv()

    @classmethod
    def get_environment_variable_value(cls, key: str):
        # fetch value from environment
        value = environ.get(key)
        if value is None:
            # raise exception if value is not available
            raise ApplicationError(HTTPStatus.INTERNAL_SERVER_ERROR,
                                    f"invalid environment variable: {key}")
        else:
            # return environment variable value
            return value


import functools
import itertools
import os

import seqio
import tensorflow as tf

from lang_transfer import preprocessing

DEFAULT_BYTE_OUTPUT_FEATURES = {
    "inputs": seqio.Feature(vocabulary=seqio.ByteVocabulary(), required=False),
    "targets": seqio.Feature(vocabulary=seqio.ByteVocabulary()),
}

DEFAULT_PRE_PROCESSORS = [
    functools.partial(
        seqio.preprocessors.rekey, key_map={"inputs": None, "targets": "text"}
    ),
    seqio.preprocessors.tokenize,
    preprocessing.group_texts,
    seqio.preprocessors.append_eos_after_trim,
]

ALL_LANGUAGES = (
    "ar",
    "en",
    "es",
    "pt",
    "zh",
    "fi",
    "de",
    "ko",
    "id",
    "ja",
    "ru",
)

DATASET_SIZES = [
    "6M",
    "19M",
    "60M",
    "189M",
    "600M",
    "6B",
]

BUCKET_NAME=os.environ.get("BUCKET_NAME", "lang_agnostic_europe")

# ---------------- Language tasks -----------------

# ADD TRAIN datasets for all languages and sizes
print("Using Bucket", BUCKET_NAME, "as source of data.")

for lang, size_name in itertools.product(ALL_LANGUAGES, DATASET_SIZES):
    seqio.TaskRegistry.add(
        f"langagnostic.{lang}.{size_name}",
        source=seqio.TFExampleDataSource(
            {
                "train": f"gs://{BUCKET_NAME}/dataset/{lang}/mc4_{lang}_train_{size_name}.tfrecord",
            },
            feature_description={
                "text": tf.io.FixedLenFeature([], tf.string, default_value=""),
            },
        ),
        preprocessors=DEFAULT_PRE_PROCESSORS,
        output_features=DEFAULT_BYTE_OUTPUT_FEATURES,
        metric_fns=[],
    )

# ADD VALIDATION datasets for all languages
for lang in ALL_LANGUAGES:
    seqio.TaskRegistry.add(
        f"langagnostic.{lang}.validation",
        source=seqio.TFExampleDataSource(
            {
                "validation": f"gs://{BUCKET_NAME}/dataset/{lang}/mc4_{lang}_validation_6B-slice.tfrecord",
            },
            feature_description={
                "text": tf.io.FixedLenFeature([], tf.string, default_value=""),
            },
        ),
        preprocessors=DEFAULT_PRE_PROCESSORS,
        output_features=DEFAULT_BYTE_OUTPUT_FEATURES,
        metric_fns=[],
    )


from typing import Optional, List

class Rating:
    def __init__(self, rate: float, comment: Optional[str] = None):
        """This class is used to store a rating and everything it might
        contain with it.

        Notes:
            At the given time, ratings only support a value and an optional comment,
            but this has potential for expansion with images, for example.

        Args:
            rate: a value in range [0, 5], where 0 is the worse (disliked movie).
            comment: an optional comment to accompany/complement the numerical rating.
        """
        self.rate = rate
        self.comment = comment

    def __str__(self) -> str:
        if self.comment is None:
            return f"({self.rate:.1f}) '{self.comment}'"

        return f"({self.rate:.1f})"

class Movie:
    def __init__(self, identifier: int, name: str, filename: str, description: str, start_time: int, duration: int,
                 thumbnail: str = None, director: str = None, age_restricted: bool = False):
        """This class hosts a movie.

        Args:
            identifier: Movie object's unique ID
            name: movie's title
            filename: name of file containing movie's .mkv: files/films/<filename>
            description: movie's description
            start_time: time when movie will start playing in schedule (Unix).
            duration: movie's duration in seconds.
            thumbnail: name of file containing movie's thumbnail: files/films/<thumbnail>
            director: movie director's name
            age_restricted: true or false, indicating if movie has age restriction
        """
        self.identifier = identifier
        self.name = name
        self.filename = filename
        self.description = description
        self.start_time = start_time
        self.duration = duration
        self.thumbnail = thumbnail
        self.director = director
        self.age_restricted = age_restricted
        self.rating = 0.0
        self.__ratings = []

    def add_rating(self, rate: float, comment: Optional[str] = None) -> None:
        """Adds a new rating to the movie.

        Args:
            rate: a value in range [0, 5], where 0 is the worse (disliked movie).
            comment: an optional comment to accompany/complement the numerical rating.
        """

        if rate < 0 or rate > 5:
            raise ValueError("Rate should be in range [0, 5].")

        self.__ratings.append(Rating(rate, comment))
        rates = [o.rate for o in self.__ratings]

        self.rating = sum(rates) / len(rates)

    def get_rating(self) -> List[Rating]:
        """Get a list of all the ratings

        Returns:
            A list with every rate given to this movie.
        """
        return self.__ratings


import maya.cmds as mc

xyz = 'XYZ'
she = 'XY', 'XZ', 'YZ'

def TtoB():

	#create joint
	jnt = mc.ls(sl=True)
	tar = mc.listRelatives('{}'.format(jnt[0]))
	par = mc.listRelatives('{}'.format(jnt[0]), p=True)
	twi_trs = mc.getAttr('{}.translateX'.format(jnt[0]))
	jnt_trs = mc.getAttr('{}.worldMatrix[0]'.format(jnt[0]))
	par_trs = mc.getAttr('{}.worldMatrix[0]'.format(par[0]))
	jnt_orix = mc.getAttr('{}.jointOrientX'.format(jnt[0]))
	jnt_oriy = mc.getAttr('{}.jointOrientY'.format(jnt[0]))
	jnt_oriz = mc.getAttr('{}.jointOrientZ'.format(jnt[0]))
	twi_trs = twi_trs / 2
	jnt_rot = [-1 * jnt_orix, -1 * jnt_oriy, -1 * jnt_oriz]

	twi = mc.joint(n='{}_twist'.format(jnt[0]), rad=0.3, p=(par_trs[12],par_trs[13],par_trs[14]))
	ben = mc.joint(n='{}_bend'.format(jnt[0]), rad=0.3, p=(jnt_trs[12],jnt_trs[13],jnt_trs[14]))
	mc.parent('{}'.format(twi), '{}'.format(par[0]))
	mc.joint('{}'.format(twi), e=True, oj='xyz', sao='yup')
	mc.setAttr('{}.translateX'.format(twi), twi_trs)
	mc.setAttr('{}.translateX'.format(ben), twi_trs)
	mc.setAttr('{}.jointOrientX'.format(ben), jnt_orix)
	mc.setAttr('{}.jointOrientY'.format(ben), jnt_oriy)
	mc.setAttr('{}.jointOrientZ'.format(ben), jnt_oriz)

	#vectorCalculation
	co1 = mc.createNode('composeMatrix')
	co2 = mc.createNode('composeMatrix')
	inv = mc.createNode('inverseMatrix')
	mlt = mc.createNode('multMatrix')
	dec = mc.createNode('decomposeMatrix')
	trs = mc.createNode('transform')

	mc.connectAttr('{}.translate'.format(tar[0]), '{}.inputTranslate'.format(co1))
	mc.connectAttr('{}.scale'.format(tar[0]), '{}.inputScale'.format(co1))
	mc.connectAttr('{}.rotate'.format(tar[0]), '{}.inputRotate'.format(co1))
	mc.connectAttr('{}.shear'.format(tar[0]), '{}.inputShear'.format(co1))
	mc.connectAttr('{}.scale'.format(jnt[0]), '{}.inputScale'.format(co2))
	mc.connectAttr('{}.jointOrient'.format(jnt[0]), '{}.inputRotate'.format(co2))
	mc.connectAttr('{}.shear'.format(jnt[0]), '{}.inputShear'.format(co2))
	mc.connectAttr('{}.outputMatrix'.format(co2), '{}.inputMatrix'.format(inv))
	mc.connectAttr('{}.outputMatrix'.format(co1), '{}.matrixIn[0]'.format(mlt))
	mc.connectAttr('{}.outputMatrix'.format(inv), '{}.matrixIn[1]'.format(mlt))
	mc.connectAttr('{}.matrixSum'.format(mlt), '{}.inputMatrix'.format(dec))
	mc.connectAttr('{}.outputRotate'.format(dec), '{}.rotate'.format(trs))
	mc.connectAttr('{}.outputTranslate'.format(dec), '{}.translate'.format(trs))
	mc.connectAttr('{}.outputScale'.format(dec), '{}.scale'.format(trs))
	mc.connectAttr('{}.outputShear'.format(dec), '{}.shear'.format(trs))
	mc.parent('{}'.format(trs), '{}'.format(jnt[0]))
	mat = mc.getAttr('{}.matrix'.format(trs))
	mc.delete('{}'.format(co2), '{}'.format(inv), '{}'.format(mlt), '{}'.format(dec), '{}'.format(trs))

	#createNode
	aim = mc.createNode('aimConstraint', n='{}_beforeSplitTwistDriver'.format(tar[0]))
	mc.addAttr(ln='bend', nc=3, at='double3')
	mc.addAttr(ln='twist', nc=3, at='double3')
	for i in range(3):
		mc.addAttr(ln='bend{}'.format(xyz[i]), at='doubleAngle', p='bend')
		mc.addAttr(ln='twist{}'.format(xyz[i]), at='doubleAngle', p='twist')

	oc1 = mc.createNode('orientConstraint', n='{}_beforeSplitTwist'.format(jnt[0]))
	oc2 = mc.createNode('orientConstraint', n='{}_bendRot'.format(jnt[0]))
	oc3 = mc.createNode('orientConstraint', n='{}_twistRot'.format(jnt[0]))
	pb1 = mc.createNode('pairBlend', n='{}_weightedTwist'.format(jnt[0]))
	pb2 = mc.createNode('pairBlend', n='{}_bendRotSafeRot'.format(jnt[0]))
	pb3 = mc.createNode('pairBlend', n='{}_twistRotSafeRot'.format(jnt[0]))

	mc.parent('{}'.format(aim), '{}'.format(jnt[0]))
	mc.parent('{}'.format(oc1), '{}'.format(jnt[0]))
	mc.parent('{}'.format(oc2), '{}'.format(ben))
	mc.parent('{}'.format(oc3), '{}'.format(twi))

	#setAttr
	mc.setAttr('{}.worldUpType'.format(aim), 4)
	mc.setAttr('{}.rotateMode'.format(pb2), 2)
	mc.setAttr('{}.rotateMode'.format(pb3), 2)
	mc.setAttr('{}.rotInterpolation'.format(pb2), 1)
	mc.setAttr('{}.rotInterpolation'.format(pb3), 1)
	mc.setAttr('{}.scaleCompensate'.format(aim), False)
	for i in range(3):
		mc.setAttr('{0}.aimVector{1}'.format(aim, xyz[i]), mat[i])
		mc.setAttr('{0}.target[0].targetTranslate{1}'.format(aim, xyz[i]), mat[i])
		mc.setAttr('{0}.translate{1}'.format(aim, xyz[i]), 0)
		mc.setAttr('{0}.translate{1}'.format(oc1, xyz[i]), 0)
		mc.setAttr('{0}.translate{1}'.format(oc2, xyz[i]), 0)
		mc.setAttr('{0}.translate{1}'.format(oc3, xyz[i]), 0)
		mc.setAttr('{0}.target[0].targetRotate{1}'.format(oc3, xyz[i]), jnt_rot[i])
		mc.setAttr('{0}.constraintJointOrient{1}'.format(oc3, xyz[i]), jnt_rot[i])

	#connectAttr
	mc.connectAttr('{}.constraintRotate'.format(aim), '{}.bend'.format(aim))
	mc.connectAttr('{}.constraintRotate'.format(aim), '{}.constraintJointOrient'.format(oc1))
	mc.connectAttr('{}.matrix'.format(aim), '{}.target[0].targetParentMatrix'.format(aim))
	mc.connectAttr('{}.matrix'.format(aim), '{}.target[0].targetParentMatrix'.format(oc1))
	mc.connectAttr('{}.twist'.format(aim), '{}.inRotate2'.format(pb1))
	mc.connectAttr('{}.constraintRotate'.format(oc1), '{}.twist'.format(aim))
	mc.connectAttr('{}.constraintRotate'.format(oc2), '{}.inRotate2'.format(pb2))
	mc.connectAttr('{}.constraintRotate'.format(oc3), '{}.inRotate2'.format(pb3))
	mc.connectAttr('{}.outRotate'.format(pb1), '{}.constraintJointOrient'.format(oc2))
	mc.connectAttr('{}.outRotate'.format(pb1), '{}.target[0].targetJointOrient'.format(oc3))
	for i in range(3):
		mc.connectAttr('{0}.scale{1}'.format(jnt[0], xyz[i]), '{0}.scale{1}'.format(ben, xyz[i]))
		mc.connectAttr('{0}.shear{1}'.format(jnt[0], she[i]), '{0}.shear{1}'.format(ben, she[i]))
		mc.connectAttr('{0}.scale{1}'.format(par[0], xyz[i]), '{0}.scale{1}'.format(twi, xyz[i]))
		mc.connectAttr('{0}.shear{1}'.format(par[0], she[i]), '{0}.shear{1}'.format(twi, she[i]))
		mc.connectAttr('{0}.rotate{1}'.format(jnt[0], xyz[i]), '{0}.rotate{1}'.format(aim, xyz[i]))
		mc.connectAttr('{0}.rotate{1}'.format(jnt[0], xyz[i]), '{0}.target[0].targetRotate{1}'.format(oc2, xyz[i]))
		mc.connectAttr('{0}.outRotate{1}'.format(pb2, xyz[i]), '{0}.rotate{1}'.format(ben, xyz[i]))
		mc.connectAttr('{0}.outRotate{1}'.format(pb3, xyz[i]), '{0}.rotate{1}'.format(twi, xyz[i]))

win = mc.window(t='TtoBtest', widthHeight=(200,30))
mc.columnLayout()
mc.button(l='TtoB', c='TtoB()')
mc.showWindow(win)