#! /usr/bin/python
#! -*-coding:utf-8-*-
import sys, os, subprocess, traceback
import requests
import lxml, time, platform
from lxml import html
from bs4 import BeautifulSoup
from selenium import webdriver

from time import sleep
# Графика для приложения
# import PyQt5 QtCore and QtGui modules
from PyQt5 import uic
from PyQt5.QtCore import QByteArray, QBuffer, QSettings, QFile, QIODevice, QVariant, QTimer
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from PyQtX import QtCore

# Библиотеки для взаимодействия с БД/
import mysql.connector
from mysql.connector import Error
from mysql.connector.constants import ClientFlag

from threading import Thread

#------------------------------------------| ThreadSites |-----------------------------------------#
class ThreadSite(QThread):
    def __init__(self, ui, widget, signalChanPage):
        QThread.__init__(self)
        self.ui = ui
        self.widget = widget
        self.signalChangePage = signalChanPage
        options = webdriver.FirefoxOptions()
        options.add_argument("-headless")

        if platform.system() == "Windows":
            self.browser = webdriver.Firefox(options=options, executable_path=r'geckodriver.exe')
        elif platform.system() == "Linux":
            self.browser = webdriver.Firefox(options=options, executable_path=r'geckodriver')

    def checkText(self, txt):
        x = txt.find("://")
        if x == -1:
            return txt
        text = ""
        for i in range(0, txt.__len__()):
            if i > x + 2:
                text += txt[i]
        txt = text
        return txt

    def checkURL(self, txt):
        try:
            request = requests.get("http://"+txt)
        except:
            return False
        if request.status_code != 200:
            return False
        else:
            return True

    def collectDataFromURL(self, page, searched):
        typesetting = lxml

    def run(self):
        try:
            while True:
                if self.checkURL(self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(self.widget)).lineedit.text()):
                    self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(self.widget)).lineedit.setStyleSheet(" color: green; ")
                    self.browser.get("http://" + self.widget.lineedit.text())
                    self.signalChangePage.emit(BeautifulSoup(self.browser.page_source, "html.parser").prettify(), self.widget)
                else:
                    self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(self.widget)).lineedit.setStyleSheet(" color: red; ")
                #print(self.ui.TabWidget.tabText(self.ui.TabWidget.indexOf(self.widget)))
                try:
                    self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(self.widget)).lineedit.setText(self.checkText(self.widget.lineedit.text()))
                except:
                    print("Ошибка в редактировании ссылки на вкладке: " + str(self.ui.TabWidget.tabText(self.ui.TabWidget.indexOf(self.widget))))
                sleep(10)
        except:
            print("Ошибка браузера, с которого производится парсинг.")

    def __del__(self):
        try:
            self.browser.quit()
        except:
            pass

    # region LOADFILES
    def qsettings(self):
        try:
            self.dataHistory = QSettings(self.pathDataHistory, QSettings.IniFormat)
            self.history = {}
            for i in self.dataHistory.allKeys():
                self.history[int(i)] = self.dataHistory.value(str(i))
        except:
            self.history = {}
            QMessageBox.question(self, 'Предупреждение!', "Инициализация ПУСТЫХ ДАННЫХ об ИСТОРИИ.", QMessageBox.Ok)

        try:
            self.dataSites = QSettings(self.pathDataSites, QSettings.IniFormat)
            self.sites = {}
            for i in self.dataSites.allKeys():
                self.sites[int(i)] = self.dataSites.value(str(i))
        except:
            self.sites = {}
            QMessageBox.question(self, 'Предупреждение!', "Инициализация ПУСТЫХ ДАННЫХ о САЙТАХ.", QMessageBox.Ok)
    # endregion

#-------------------------------------------| QWidgets |-------------------------------------------#
# region WIDGETSETTINGS
class SettingsDBWidget(QDialog):
    def __init__(self, db, parent=None):
        QWidget.__init__(self, parent)
        self.infoBase = db
        self.initSettings()

    # region initUI
    def initSettings(self):
        self.setWindowTitle('Настройки подключения к БД')
        self.setWindowIcon(QIcon('../Images/icon_server.png'))

        self.defSettingsDBWidget, Base = uic.loadUiType('SettingsDBWidget.ui')

        self.SettingsDBWidget = self.defSettingsDBWidget()
        self.SettingsDBWidget.setupUi(self)

        self.show()
    # endregion
# endregion

# region TABWIDGET
class NewWidget(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()

        self.textedit = QTextEdit()
        self.textedit.setObjectName("text")
        self.lineedit = QLineEdit()
        self.lineedit.setObjectName("line")

        layout.addWidget(self.lineedit)
        layout.addWidget(self.textedit)

        self.setLayout(layout)
# endregion

#-------------------------------------------| MainForm |-------------------------------------------#
#region MAINFORM
class MainWindow(QMainWindow):
    signalChangePage = pyqtSignal(str, object)
    signalSelectedTextEdit = pyqtSignal(int, int, object)

    def __init__(self):
        super().__init__()
        self.initUI()

        # region HEADER

        # region FILE
        self.ui.exportSites.triggered.connect(self.exportSites)
        self.ui.importSites.triggered.connect(self.importSites)
        #
        self.ui.exportHistory.triggered.connect(self.exportHistory)
        self.ui.importHistory.triggered.connect(self.importHistory)
        # endregion

        # region SITES
        self.ui.addSiteAction.triggered.connect(self.addSite)
        #
        self.ui.delCurrentSite.triggered.connect(self.delCurrentSite)
        self.ui.delAllWorkSites.triggered.connect(self.delAllSites)
        # endregion

        # region HISTORY
        self.ui.returnSite.triggered.connect(self.returnSite)
        #
        self.ui.delCurrentHistory.triggered.connect(self.delCurrentHistory)
        self.ui.delAllHistories.triggered.connect(self.delAllHistories)
        # endregion

        # region SETTINGS
        self.ui.setDataBase.triggered.connect(self.setDataBase)
        #
        self.ui.saveSettingsWindow.triggered.connect(self.saveSettingsWindow)
        #
        self.ui.restoreSettingsWindow.triggered.connect(self.restoreSettingsWindow)
        self.ui.removeSettingsWindow.triggered.connect(self.removeSettingsWindow)
        # endregion

        # region MECHANISMS
        self.ui.StartStopParse.clicked.connect(self.StartStopParse)
        self.signalChangePage.connect(self.changePage)
        self.signalSelectedTextEdit.connect(self.selectedTextEdit)

        self.ui.ComboSites.currentIndexChanged.connect(self.changeNumTab)
        self.ui.ComboHistory.currentIndexChanged.connect(self.checkIndex)
        self.ui.TabWidget.currentChanged.connect(self.setCurrentIndexTab)

        #self.ui.threadToSites = QTimer()
        #self.ui.threadToSites.timeout.connect(self.startThreadsAndSites)

        # deb
        self.ui.testadd.triggered.connect(self.teSt)
        self.ui.current.triggered.connect(self.testCurrent)

        self.ui.timerTabToSites = QTimer()
        self.ui.timerTabToSites.timeout.connect(self.tabsToSites)
        self.ui.timerTabToSites.start(100)

        #self.ui.debug = QTimer()
        #self.ui.debug.timeout.connect(self.debuggerTimer)
        #self.ui.debug.start(3000)
        # endregion

        # endregion

        self.checkIndex()

        for i in range(0, self.ui.TabWidget.count()):
            self.ui.TabWidget.widget(i).textedit.clear()

        #self.addSite()
        #self.ui.ComboHistory.addItem('1')

    # region initUI
    def initUI(self):
        self.pathSettings = "../Data/settings.conf"
        self.pathDataSites = "../Data/dataSites.conf"
        self.pathDataHistory = "../Data/dataHistory.conf"

        self.ThreadsSites = {}
        self.infoBase = {}

        self.defMainForm, Base = uic.loadUiType("MainWindow.ui")

        self.ui = self.defMainForm()
        self.ui.setupUi(self)

        self.qsettings()

        self.syncDataToFile(False)

        self.show()
    # endregion

    def keyPressEvent(self, event):
        if self.ui.TabWidget.currentIndex == -1:
            return
        if (event.key() == QtCore.Qt.Key_Enter) | (event.key() != QtCore.Qt.Key_Shift) & (event.key() != QtCore.Qt.Key_Meta) & (event.key() != QtCore.Qt.Key_Control):
            self.changeTextNumSite()

    def closeEvent(self, event):
        self.dataSettings.sync()
        self.dataHistory.sync()
        self.dataSites.sync()
        self.syncDataToFile(True)
        if (self.ThreadsSites.__len__() != 0):
            self.StartStopParse()
        if not Exit:
            subprocess.Popen("./MainWindow.py 1", shell=True)
            print("restarted")
        elif Exit:
            print("exited")

    # region LOADFILES
    def qsettings(self):
        try:
            self.dataSettings = QSettings(self.pathSettings, QSettings.IniFormat)
            self.restoreGeometry(self.dataSettings.value('Window/G'))
            self.restoreState(self.dataSettings.value('Window/S'))
        except:
            self.ui = self.defMainForm()
            self.ui.setupUi(self)

            self.saveSettingsWindow()
            QMessageBox.question(self, 'Предупреждение!', "Загрузка невозможна, возможно программа открывается впервые.", QMessageBox.Ok)

        try:
            self.dataHistory = QSettings(self.pathDataHistory, QSettings.IniFormat)
            self.history = {}
            for i in self.dataHistory.allKeys():
                self.history[int(i)] = self.dataHistory.value(str(i))
        except:
            self.history = {}
            QMessageBox.question(self, 'Предупреждение!', "Инициализация ПУСТЫХ ДАННЫХ об ИСТОРИИ.", QMessageBox.Ok)

        try:
            self.dataSites = QSettings(self.pathDataSites, QSettings.IniFormat)
            self.sites = {}
            for i in self.dataSites.allKeys():
                self.sites[int(i)] = self.dataSites.value(str(i))
        except:
            self.sites = {}
            QMessageBox.question(self, 'Предупреждение!', "Инициализация ПУСТЫХ ДАННЫХ о САЙТАХ.", QMessageBox.Ok)
    # endregion

    # region DEB
    def teSt(self):
        print(self.ThreadsSites)

    def testCurrent(self):
        #self.ui.timerTabToSites.stop()
        print(str(self.dataSites.allKeys()) + " : " + str(self.dataHistory.allKeys()))
        print(str(self.sites) + " : " + str(self.history))

    def debuggerTimer(self):
        for i in self.dataSettings.allKeys():
            if (i == 'Window/G') and (i == 'Window/S'):
                try:
                    print(i + " : " + str(QTextStream(self.dataSettings.value(i)).readAll()))
                except:
                    pass
    # endregion

    # region WORKEDCODE

    # region FILE FUNC
    def exportSites(self):
        result = QFileDialog.getSaveFileName(parent=None, caption="Экспорт сайтов", directory='../ExportedSites/', filter='Файлы настроек (*.conf)\nВсе файлы (*)', options=QFileDialog.DontUseNativeDialog)[0]
        if QFile.exists(result):
            QFile.remove(result)
        self.dataSites = QSettings(result, QSettings.IniFormat)
        for i in self.sites:
            self.dataSites.setValue(str(i), self.sites[i])
        self.dataSites = QSettings(self.pathDataSites, QSettings.IniFormat)

    def importSites(self):
        result = QFileDialog.getOpenFileName(parent=None, caption="Импорт сайтов", directory='../ExportedSites/', filter='Файлы настроек (*.conf)\nВсе файлы (*)', options=QFileDialog.DontUseNativeDialog)[0]
        self.delAllSites()
        self.dataSites = QSettings(result, QSettings.IniFormat)
        for i in self.dataSites.allKeys():
            self.sites[int(i)] = self.dataSites.value(str(i))
        self.returnAllSites(self.sites, {})
        self.dataSites = QSettings(self.pathDataSites, QSettings.IniFormat)

    def exportHistory(self):
        result = QFileDialog.getSaveFileName(parent=None, caption="Экспорт истории", directory='../ExportedHistories/', filter='Файлы настроек (*.conf)\nВсе файлы (*)', options=QFileDialog.DontUseNativeDialog)[0]
        if QFile.exists(result):
            QFile.remove(result)
        self.dataHistory = QSettings(result, QSettings.IniFormat)
        for i in self.history:
            self.dataHistory.setValue(str(i), self.history[i])
        self.dataHistory = QSettings(self.pathDataHistory, QSettings.IniFormat)

    def importHistory(self):
        result = QFileDialog.getOpenFileName(parent=None, caption="Импорт истории", directory='../ExportedHistories/', filter='Файлы настроек (*.conf)\nВсе файлы (*)', options=QFileDialog.DontUseNativeDialog)[0]
        self.delAllHistories()
        self.dataHistory = QSettings(result, QSettings.IniFormat)
        for i in self.dataHistory.allKeys():
            self.history[int(i)] = self.dataHistory.value(str(i))
        self.returnAllSites({}, self.history)
        self.dataHistory = QSettings(self.pathDataHistory, QSettings.IniFormat)
    # endregion

    # region SITES FUNC
    def addSite(self):
        tab = NewWidget()
        for i in range(0, self.ui.ComboSites.count() + 1):
            if self.ui.ComboSites.findText(str(i+1)) == -1:
                self.ui.TabWidget.addTab(tab, str(i + 1))
                self.ui.ComboSites.addItem(str(i + 1))
                self.sites[i+1] = ("", "")
                break

    def delCurrentSite(self):
        if self.ui.ComboSites.currentIndex() != -1:
            if self.ui.ComboHistory.findText(self.ui.ComboSites.currentText()) != -1:
                self.ui.ComboHistory.removeItem(self.ui.ComboHistory.findText(self.ui.ComboSites.currentText()))

            self.ui.ComboHistory.addItem(self.ui.ComboSites.itemText(self.ui.ComboSites.currentIndex()), self.ui.ComboSites.currentText())

            i_s = -1
            i_t = -1

            for i in range(0, self.ui.TabWidget.count()):
                if self.ui.TabWidget.tabText(i) == self.ui.ComboSites.currentText():
                    i_t = i
                if self.ui.TabWidget.tabText(self.ui.TabWidget.currentIndex()) == self.ui.ComboSites.itemText(i):
                    i_s = i

            self.history[int(self.ui.ComboSites.itemText(i_s))] = (self.ui.TabWidget.widget(i_t).lineedit.text(), self.ui.TabWidget.widget(i_t).textedit.toPlainText())

            self.ui.TabWidget.removeTab(i_t)
            self.ui.ComboSites.removeItem(i_s)

            #for i in range(0, self.ui.TabWidget.count()):
            #    print(self.ui.ComboSites())

    def delAllSites(self):
        self.ui.timerTabToSites.stop()
        if self.ui.TabWidget.currentIndex() != -1:
            self.ui.ComboSites.setCurrentIndex(-1)
            self.ui.TabWidget.setCurrentIndex(-1)
            for i in self.sites.keys():
                if self.ui.ComboHistory.findText(str(i)) != -1:
                    self.ui.ComboHistory.removeItem(self.ui.ComboHistory.findText(str(i)))
            for i in self.sites.keys():
                self.ui.ComboHistory.insertItem(i, str(i))
                self.history[i] = self.sites.get(i)

            self.ui.TabWidget.clear()
            self.ui.ComboSites.clear()
            self.sites = {}
        self.ui.timerTabToSites.start()
    # endregion

    # region HISTORIES FUNC
    def returnSite(self):
        if self.ui.ComboHistory.currentIndex() == -1:
            return 0
        if self.ui.ComboSites.findText(self.ui.ComboHistory.currentText()) != -1:
            self.ui.ComboSites.removeItem(self.ui.ComboSites.findText(self.ui.ComboHistory.currentText()))
        for i in range(0, self.ui.TabWidget.count()):
            if self.ui.TabWidget.tabText(i) == self.ui.ComboHistory.currentText():
                self.ui.TabWidget.removeTab(i)
                break

        widget = NewWidget()
        widget.lineedit.setText(self.history[int(self.ui.ComboHistory.currentText())][0])
        widget.textedit.setText(self.history[int(self.ui.ComboHistory.currentText())][1])

        #self.ui.TabWidget.insertTab(int(self.ui.ComboHistory.currentText()), list(self.history.values())[self.ui.ComboHistory.currentIndex()], list(self.history.keys())[self.ui.ComboHistory.currentIndex()])
        self.ui.TabWidget.insertTab(int(self.ui.ComboHistory.currentText())-1, widget, self.ui.ComboHistory.currentText())
        self.ui.ComboSites.insertItem(int(self.ui.ComboHistory.currentText())-1, self.ui.ComboHistory.currentText())
        for i in range(0, self.ui.TabWidget.count()):
            if self.ui.TabWidget.tabText(i) == self.ui.ComboHistory.currentText():
                self.ui.TabWidget.setCurrentIndex(i)

    def delCurrentHistory(self):
        if self.ui.ComboHistory.currentIndex() != -1:
            del self.history[int(self.ui.ComboHistory.currentText())]
            self.ui.ComboHistory.removeItem(self.ui.ComboHistory.currentIndex())

    def delAllHistories(self):
        self.history.clear()
        self.ui.ComboHistory.clear()

    # endregion

    # region SETTINGS FUNC
    def StartStopParse(self):
        if self.ui.StartStopParse.text() == "Старт":
            self.startThreadsAndSites()
            self.ui.StartStopParse.setText("Стоп")
        else:
            self.removeThreadsAndSites()
            self.ui.StartStopParse.setText("Старт")
            for i in range(0, self.ui.TabWidget.count()):
                self.ui.TabWidget.widget(i).lineedit.setStyleSheet("")

    def restoreSettingsWindow(self):
        status = QMessageBox.question(self, 'Внимание!', "Вы точно хотите сделать СБРОС НАСТРОЕК?", QMessageBox.Ok | QMessageBox.Cancel)
        if status == QMessageBox.Ok:
            self.dataSettings.remove("Window/G")
            self.dataSettings.remove("Window/S")
            self.syncDataToFile(True)
        else:
            return
        status = QMessageBox.question(self, 'Внимание!', "Вы хотите ЗАКРЫТЬ ПРИЛОЖЕНИЕ для применения настроек?", QMessageBox.Ok | QMessageBox.Cancel)
        if status == QMessageBox.Ok:
            global Exit
            Exit = False
            self.close()

    def saveSettingsWindow(self):
        self.dataSettings.setValue('Window/G', self.saveGeometry())
        self.dataSettings.setValue('Window/S', self.saveState())

    def removeSettingsWindow(self):
        status = QMessageBox.question(self, 'Внимание!', "Вы точно хотите сделать СБРОС ВСЕХ НАСТРОЕК?", QMessageBox.Ok | QMessageBox.Cancel)
        if status == QMessageBox.Ok:
            os.remove(self.pathSettings)
            self.qsettings()
            self.syncDataToFile(True)
        else:
            return
        status = QMessageBox.question(self, 'Внимание!', "Вы хотите ЗАКРЫТЬ ПРИЛОЖЕНИЕ для применения настроек?", QMessageBox.Ok | QMessageBox.Cancel)
        if status == QMessageBox.Ok:
            global Exit
            Exit = False
            self.close()

    def setDataBase(self):
        self.SettingsDBWidget = SettingsDBWidget(self.infoBase)
    # endregion

    # region MECHANISMS FUNC

    # region Signals
    @pyqtSlot(str, object)
    def changePage(self, textPage, widget):
        cursor = self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(widget)).textedit.textCursor()
        begin = cursor.selectionStart()
        end = cursor.selectionEnd()

        self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(widget)).textedit.setPlainText(str(textPage))

        cursor.setPosition(begin, QTextCursor.MoveAnchor)
        cursor.setPosition(end, QTextCursor.KeepAnchor)
        self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(widget)).textedit.setTextCursor(cursor)

        text = str(self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(widget)).textedit.toPlainText())
        tree = html.fromstring(text)
        try:
            print(tree.xpath('.//h2')[0])
        except:
            pass

        ltext = QLabel()
        text = str(self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(widget)).textedit.toPlainText()).split("\n")
        ltext.setText(str(text))
        self.ui.statusbar.insertWidget(0, ltext)

    @pyqtSlot(int, int, object)
    def selectedTextEdit(self, begin, end, textedit):
        pass
    # endregion

    def removeThreadsAndSites(self):
        try:
            for i in self.ThreadsSites.keys():
                if self.ThreadsSites[i].isRunning():
                    self.ThreadsSites[i].terminate()
                    self.ThreadsSites[i].wait()
            print(self.ThreadsSites)
            for i in self.ThreadsSites.keys():
                if self.ThreadsSites[i].isRunning():
                    print("running: " + str(i))
                if self.ThreadsSites[i].isFinished():
                    print("finished: " + str(i))
        except Exception as e:
            print('Ошибка:\n', traceback.format_exc())

    def startThreadsAndSites(self):
        try:
            for i in range(0, self.ui.TabWidget.count()):
                self.ThreadsSites[int(self.ui.TabWidget.tabText(i))] = ThreadSite(self.ui, self.ui.TabWidget.widget(i), self.signalChangePage)
                self.ThreadsSites[int(self.ui.TabWidget.tabText(i))].start()
        except Exception as e:
            print('Ошибка:\n', traceback.format_exc())

    def changeTextParse(self, str, obj):
        widget = self.ui.TabWidget.widget(self.ui.TabWidget.indexOf(obj))
        widget.textedit.setText(str)

    def tabsToSites(self):
        self.sites = {}
        for i in range(0, self.ui.TabWidget.count()):
            self.sites[int(self.ui.TabWidget.tabText(i))] = (self.ui.TabWidget.widget(i).lineedit.text(), self.ui.TabWidget.widget(i).textedit.toPlainText())
        #print(str(self.sites) + " : " + str(self.history))

    def changeTextNumSite(self):
        try:
            int(self.ui.ComboSites.currentText())
            self.ui.ComboSites.setItemText(self.ui.ComboSites.findText(self.ui.TabWidget.tabText(self.ui.TabWidget.currentIndex())), str(int(self.ui.ComboSites.currentText())))
            self.ui.TabWidget.setTabText(self.ui.TabWidget.currentIndex(), self.ui.ComboSites.currentText())
        except Exception:
            #self.ui.ComboSites.setItemText(self.ui.ComboSites.currentIndex(), self.ui.TabWidget.tabText(self.ui.ComboSites.currentIndex()))
            self.ui.ComboSites.removeItem(self.ui.ComboSites.findText(self.ui.ComboSites.currentText()))
            QMessageBox.question(self, 'Предупреждение!', "Введите число, а не букву или симол в поле ввода номера вкладки.", QMessageBox.Ok)

    def changeNumTab(self):
        self.checkIndex()
        #print(self.ui.ComboSites.findText(self.ui.TabWidget.tabText(self.ui.TabWidget.currentIndex())))
        for i in range(0, self.ui.TabWidget.count()):
            if self.ui.TabWidget.tabText(i) == self.ui.ComboSites.currentText():
                self.ui.TabWidget.setCurrentIndex(i)
        #print(self.ui.TabWidget.currentIndex())

    def setCurrentIndexTab(self):
        if (self.ui.TabWidget.currentIndex() != -1) & (self.ui.ComboSites.currentIndex() != -1):
            self.ui.ComboSites.setCurrentIndex(self.ui.ComboSites.findText(self.ui.TabWidget.tabText(self.ui.TabWidget.currentIndex())))

    def checkIndex(self):
        if self.ui.ComboSites.currentIndex() == -1:
            self.ui.ComboSites.setEditable(False)
        else:
            self.ui.ComboSites.setEditable(True)

        if self.ui.ComboHistory.currentIndex() == -1:
            self.ui.ComboHistory.setEditable(False)
        else:
            self.ui.ComboHistory.setEditable(True)

    def returnAllSites(self, values1, values2):
        for i in values1:
            widget = NewWidget()
            widget.lineedit.setText(self.sites[int(i)][0])
            widget.textedit.setText(self.sites[int(i)][1])

            self.ui.TabWidget.insertTab(int(i) - 1, widget, str(i))
            self.ui.ComboSites.insertItem(int(i) - 1, str(i))
        for i in values2:
            self.ui.ComboHistory.insertItem(int(i) - 1, str(i))

    def syncDataToFile(self, operation):
        if operation:
            for i in self.dataSites.allKeys():
                self.dataSites.remove(str(i))
            for i in self.dataHistory.allKeys():
                self.dataHistory.remove(str(i))
            for i in self.sites:
                self.dataSites.setValue(str(i), self.sites[i])
            for i in self.history:
                self.dataHistory.setValue(str(i), self.history[i])
            #print(str(self.dataSites.allKeys()) + " : " + str(self.dataHistory.allKeys()))
            #print(str(self.sites) + " : " + str(self.history))
        else:
            for i in self.dataSites.allKeys():
                self.sites[int(i)] = self.dataSites.value(str(i))
            for i in self.dataHistory.allKeys():
                self.history[int(i)] = self.dataHistory.value(str(i))
            self.returnAllSites(self.sites, self.history)

    # endregion

    # endregion

#--------------------------------------------------------------------------------------------------#
# endregion

Exit = True

def Main():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    #sys.setrecursionlimit(50000)
    Main()


import logging
from alphaml.engine.components.components_manager import ComponentsManager
from alphaml.engine.components.data_manager import DataManager
from alphaml.engine.evaluator.base import BaseClassificationEvaluator, BaseRegressionEvaluator
from alphaml.engine.components.ensemble.bagging import Bagging
from alphaml.engine.components.ensemble.blending import Blending
from alphaml.engine.components.ensemble.stacking import Stacking
from alphaml.engine.components.ensemble.ensemble_selection import EnsembleSelection
from alphaml.utils.label_util import to_categorical, map_label, get_classnum
import numpy as np

class AutoML(object):
    """ The controller of a ML pipeline"""

    def __init__(
            self,
            time_budget,
            each_run_budget,
            memory_limit,
            ensemble_method,
            ensemble_size,
            include_models,
            exclude_models,
            optimizer_type,
            save_dir=None,
            seed=42):
        """
        :param time_budget: int, total time limit
        :param each_run_budget: int, time limit for each model
        :param memory_limit: int
        :param ensemble_method: str, algorithm for model ensemble
        :param ensemble_size: int, number of models participating model ensemble
        :param include_models: list, names of models included.
        :param exclude_models: list, names of models excluded.
        :param optimizer_type: str, algorithm hyper-parameter optimization
        :param save_dir: str, path to save models
        :param seed: int, random seed
        """
        self.time_budget = time_budget
        self.each_run_budget = each_run_budget
        self.ensemble_method = ensemble_method
        self.ensemble_size = ensemble_size
        self.memory_limit = memory_limit
        self.include_models = include_models
        self.exclude_models = exclude_models
        self.component_manager = ComponentsManager()
        self.optimizer_type = optimizer_type
        self.save_dir = save_dir
        self.seed = seed
        self.optimizer = None
        self.evaluator = None
        self.metric = None
        self.logger = logging.getLogger(__name__)
        self.ensemble_model = None

    def fit(self, data, **kwargs):
        """
        An AutoML pipeline includes:
            1) Automated feature engineering
            2) Model selection and hyper-parameter optimization
            3) Model Ensemble
        :param data: A DataManager
        :return: self
        """

        task_type = kwargs['task_type']
        self.metric = kwargs['metric']

        # TODO: Automated FE

        self.logger.debug('The optimizer type is: %s' % self.optimizer_type)
        # Conduct model selection and hyper-parameter optimization.
        if self.optimizer_type == 'smbo':
            # Generate the configuration space for the automl task.
            from alphaml.engine.optimizer.smac_smbo import SMAC_SMBO
            config_space = self.component_manager.get_hyperparameter_search_space(task_type,
                                                                                include=self.include_models,
                                                                                exclude=self.exclude_models,
                                                                                optimizer='smac')
            # Create optimizer.
            self.optimizer = SMAC_SMBO(self.evaluator, config_space, data, self.seed, **kwargs)
        elif self.optimizer_type == 'mono_smbo':
            # Generate the configuration space for the automl task.
            from alphaml.engine.optimizer.monotone_mab_optimizer import MONO_MAB_SMBO
            config_space = self.component_manager.get_hyperparameter_search_space(task_type,
                                                                                include=self.include_models,
                                                                                exclude=self.exclude_models,
                                                                                optimizer='smac')
            # Create optimizer.
            self.optimizer = MONO_MAB_SMBO(self.evaluator, config_space, data, self.seed, **kwargs)
        elif self.optimizer_type == 'tpe':
            # Generate the configuration space for the automl task.
            from alphaml.engine.optimizer.tpe_smbo import TPE_SMBO
            config_space = self.component_manager.get_hyperparameter_search_space(task_type,
                                                                                include=self.include_models,
                                                                                exclude=self.exclude_models,
                                                                                optimizer='tpe')
            self.optimizer = TPE_SMBO(self.evaluator, config_space, data, self.seed, **kwargs)
        elif self.optimizer_type == 'mono_tpe_smbo':
            # Generate the configuration space for the automl task.
            from alphaml.engine.optimizer.monotone_mab_tpe_optimizer import MONO_MAB_TPE_SMBO
            config_space = self.component_manager.get_hyperparameter_search_space(task_type,
                                                                                include=self.include_models,
                                                                                exclude=self.exclude_models,
                                                                                optimizer='tpe')
            self.optimizer = MONO_MAB_TPE_SMBO(self.evaluator, config_space, data, self.seed, **kwargs)
        else:
            raise ValueError('UNSUPPORTED optimizer: %s' % self.optimizer)
        self.optimizer.run()
        # Construct the ensemble model according to the ensemble method.
        model_infos = (self.optimizer.configs_list, self.optimizer.config_values)
        if self.ensemble_method == 'none':
            self.ensemble_model = None
        else:
            if self.ensemble_method == 'bagging':
                self.ensemble_model = Bagging(model_infos, self.ensemble_size, task_type, self.metric, self.evaluator,
                                              save_dir=self.save_dir, random_state=self.seed)
            elif self.ensemble_method == 'blending':
                self.ensemble_model = Blending(model_infos, self.ensemble_size, task_type, self.metric, self.evaluator,
                                               save_dir=self.save_dir, random_state=self.seed)
            elif self.ensemble_method == 'stacking':
                self.ensemble_model = Stacking(model_infos, self.ensemble_size, task_type, self.metric, self.evaluator,
                                               save_dir=self.save_dir, random_state=self.seed)
            elif self.ensemble_method == 'ensemble_selection':
                self.ensemble_model = EnsembleSelection(model_infos, self.ensemble_size, task_type, self.metric,
                                                        self.evaluator, save_dir=self.save_dir,
                                                        random_state=self.seed)
            else:
                raise ValueError('UNSUPPORTED ensemble method: %s' % self.ensemble_method)

        if self.ensemble_model is not None:
            # Train the ensemble model.
            self.ensemble_model.fit(data)
        else:
            self.evaluator.fit(self.optimizer.incumbent)
        return self

    def predict(self, X, **kwargs):
        """
        Make predictions for X.
        For traditional ML task, fit the optimized model on the whole training data and predict the input data's labels.
        :param X: array-like or sparse matrix of shape = [n_samples, n_features]
        :return: pred: array of shape = [n_samples]
        """
        if self.ensemble_model is None:
            pred = self.evaluator.predict(self.optimizer.incumbent, X)
            return pred
        else:
            # Predict the result.
            pred = self.ensemble_model.predict(X)
            return pred

    def predict_proba(self, X, **kwargs):
        """
        Make predictions for X.
        For traditional ML task, fit the optimized model on the whole training data and predict the input data's labels.
        :param X: array-like or sparse matrix of shape = [n_samples, n_features]
        :return: pred: array of shape = [n_samples, n_labels]
        """
        if self.ensemble_model is None:
            # For traditional ML task:
            #   fit the optimized model on the whole training data and predict the input data's labels.
            self.evaluator.fit(self.optimizer.incumbent)
            pred = self.evaluator.predict_proba(self.optimizer.incumbent, X)
            return pred
        else:
            # Predict the result.
            pred = self.ensemble_model.predict_proba(X)
            return pred

    def score(self, X, y):
        """
        Get the performance of prediction X according to label y
        :param X: array-like or sparse matrix of shape = [n_samples, n_features]
        :param y: array of shape = [n_samples] or [n_samples, n_labels]
        :return: score: float
        """
        pred_y = self.predict(X)
        score = self.metric(y, pred_y)
        return score

class AutoMLClassifier(AutoML):
    def __init__(self,
                 time_budget,
                 each_run_budget,
                 memory_limit,
                 ensemble_method,
                 ensemble_size,
                 include_models,
                 exclude_models,
                 optimizer_type,
                 cross_valid,
                 k_fold,
                 save_dir=None,
                 seed=None):
        super().__init__(time_budget, each_run_budget, memory_limit, ensemble_method, ensemble_size, include_models,
                         exclude_models, optimizer_type, save_dir, seed)
        # Define evaluator for classification
        if optimizer_type == 'smbo':
            self.evaluator = BaseClassificationEvaluator(optimizer='smac',
                                                         kfold=k_fold if cross_valid else None,
                                                         save_dir=save_dir)
        elif optimizer_type == 'tpe':
            self.evaluator = BaseClassificationEvaluator(optimizer='tpe',
                                                         kfold=k_fold if cross_valid else None,
                                                         save_dir=save_dir)

    def fit(self, data, **kwargs):
        return super().fit(data, **kwargs)

class AutoMLRegressor(AutoML):
    def __init__(self,
                 time_budget,
                 each_run_budget,
                 memory_limit,
                 ensemble_method,
                 ensemble_size,
                 include_models,
                 exclude_models,
                 optimizer_type,
                 cross_valid,
                 k_fold,
                 save_dir=None,
                 seed=None):
        super().__init__(time_budget, each_run_budget, memory_limit, ensemble_method, ensemble_size, include_models,
                         exclude_models, optimizer_type, save_dir, seed)
        # Define evaluator for regression
        if optimizer_type == 'smbo':
            self.evaluator = BaseRegressionEvaluator(optimizer='smac',
                                                     kfold=k_fold if cross_valid else None,
                                                     save_dir=save_dir)
        elif optimizer_type == 'tpe':
            self.evaluator = BaseRegressionEvaluator(optimizer='tpe',
                                                     kfold=k_fold if cross_valid else None,
                                                     save_dir=save_dir)

    def fit(self, data, **kwargs):
        return super().fit(data, **kwargs)

class AutoIMGClassifier(AutoML):
    def __init__(self,
                 time_budget,
                 each_run_budget,
                 memory_limit,
                 ensemble_size,
                 include_models,
                 exclude_models,
                 optimizer_type,
                 save_dir=None,
                 seed=None):
        super().__init__(time_budget, each_run_budget, memory_limit, ensemble_size, include_models,
                         exclude_models, optimizer_type, save_dir, seed)

        self.evaluator = None
        self.map_dict = None
        self.rev_map_dict = None

    def fit(self, data: DataManager, **kwargs):
        from alphaml.engine.evaluator.dl_evaluator import BaseImgEvaluator
        task_type = kwargs['task_type']
        if data.train_X is None and data.train_y is None:
            inputshape = data.target_shape
            classnum = None
        else:
            inputshape = data.train_X.shape[1:]
            classnum = None
            if task_type == 'img_multiclass':
                data.train_y, self.map_dict, self.rev_map_dict = map_label(data.train_y)
                data.train_y = to_categorical(data.train_y)
                data.val_y, _, _ = map_label(data.val_y, self.map_dict)
                data.val_y = to_categorical(data.val_y)
                classnum = len(self.rev_map_dict)

            elif task_type == 'img_binary':
                data.train_y, self.map_dict, self.rev_map_dict = map_label(data.train_y, if_binary=True)
                data.val_y, _, _ = map_label(data.val_y, self.map_dict, if_binary=True)
                classnum = 1

            elif task_type == 'img_multilabel-indicator':
                classnum = get_classnum(data.train_y)

        self.evaluator = BaseImgEvaluator(inputshape, classnum)

        return super().fit(data, **kwargs)

    def predict(self, X, **kwargs):
        y_pred = super().predict(X, **kwargs)
        if self.rev_map_dict is not None:
            y_pred = np.argmax(y_pred, axis=-1)
            y_pred = [self.rev_map_dict[i] for i in y_pred]
            y_pred = np.array(y_pred)
        return y_pred

    def score(self, X, y):
        raise NotImplementedError()


import sys
sys.stdin = open('2146_input.txt')

from collections import deque

dr = (-1, 1, 0, 0)
dc = (0, 0, -1, 1)

def bfs(sr, sc, cnt):
    Q = deque([(sr, sc)])
    sea[sr][sc] = cnt
    while Q:
        r, c = Q.popleft()
        for i in range(4):
            nr = r + dr[i]
            nc = c + dc[i]
            if not (0 <= nr < N and 0 <= nc < N):
                continue
            if not A[nr][nc] or sea[nr][nc]:
                continue
            sea[nr][nc] = cnt
            Q.append((nr, nc))

def bridge_length(num):
    # 한 섬의 모든 위치에서 시작
    while Q:
        r, c = Q.popleft()
        for i in range(4):
            nr = r + dr[i]
            nc = c + dc[i]
            if not (0 <= nr < N and 0 <= nc < N):
                continue
            # 다른 섬 만나면 거리 리턴
            if sea[nr][nc] and sea[nr][nc] != num:
                return visited[r][c] - 1
            # 바다일 때마다 거리 구하기
            if not sea[nr][nc] and not visited[nr][nc]:
                visited[nr][nc] = visited[r][c] + 1
                Q.append((nr, nc))

N = int(input())
A = [list(map(int, input().split())) for _ in range(N)]
MIN = float('inf')

# 섬에 번호 붙이기
island = 1
sea = [[0] * N for _ in range(N)]
for i in range(N):
    for j in range(N):
        if A[i][j] and not sea[i][j]:
            bfs(i, j, island)
            island += 1
# print(sea)
# print(island)

# 섬마다 최단거리 계산
for k in range(1, island):
    Q = deque()
    visited = [[0] * N for _ in range(N)]
    for i in range(N):
        for j in range(N):
            if A[i][j] == 1 and sea[i][j] == k:
                Q.append((i, j))
                visited[i][j] = 1
    # 같은 섬의 모든 위치를  Q에 넣고, 그 섬만 visited에 표시
    # print(Q)
    # print('전', visited)
    # 섬의 번호를 넣으면 다른 섬까지의 거리 구하는 함수
    MIN = min(bridge_length(k), MIN)
    # print('후', visited)
print(MIN)


#-*- coding: UTF-8 -*-
####################################################
# LSrouter.py
# Name: 袁一滔
# JHED ID:
#####################################################

import sys
from collections import defaultdict
from router import Router
from packet import Packet
from json import dumps, loads
import numpy as np
import heapq

class LSrouter(Router):
    """Link state routing protocol implementation."""

    pktadd = 1
    pktrem = 2
    pktupd = 3

    def __init__(self, addr, heartbeatTime):
        """TODO: add your own class fields and initialization code here"""
        Router.__init__(self, addr)  # initialize superclass - don't remove
        self.heartbeatTime = heartbeatTime
        self.last_time = 0
        # Hints: initialize local state

        self.port2edge = {}
        self.addr2shortestport = {}
        self.glbmap = {}  # {u:{v1:c1,v2:c2},...}
        self.rcvid = {addr: 0}
        self.sendid = 1

        pass

    def broadcast(self, pkt, excpt = None):
        for port in self.port2edge.keys():
            if(port == excpt):
                continue
            self.send(port, pkt)

    def handlePacket(self, port, packet):
        """TODO: process incoming packet"""
        if packet.isTraceroute():
            outport = self.addr2shortestport.get(packet.dstAddr)
            if(outport):
                self.send(outport, packet)
        else:
            typ, args = loads(packet.content)
            sender, id = args[0], args[1]
            preid = self.rcvid.get(sender)
            if(preid and ((typ == self.pktupd and id <= preid) or (typ != self.pktupd and id != preid + 1))):
                # 这个改成 id != preid + 1 第二个点会错，因为可能你前几次都没收到（未连通），然后连通之后就再也收不到了
                # 改成 id <= preid 也会错，因为可能会先接受到大的标号的更新而把小的丢了
                # 所以我们折中，认为小变动需要保证标号连续，而大更新只需要标号更大即可
                # 总之这个没有绝对正确，只能说在一定时间后会变得正确
                return
            self.rcvid.update({sender: id})
            self.broadcast(packet, excpt=port)
            if(typ == self.pktadd):
                self.mapadd(*args)
            elif(typ == self.pktrem):
                self.maprem(*args)
            elif(typ == self.pktupd):
                self.mapupd(*args)
            else:
                print("unkown pkt type")
            self.runnetwork()

    def runnetwork(self):
        L = len(self.glbmap)
        toaddr = {i: a for i, a in enumerate(self.glbmap.keys())}
        toindex = {a: i for i, a in toaddr.items()}
        edge = [[(toindex[v], c) for v, c in self.glbmap[toaddr[u]].items()] for u in range(L)]
        dis = np.array([-1] * L, dtype=int)
        first = np.array([-1] * L, dtype=int)
        vis = np.array([0] * L, dtype=int)
        hp = []
        src = toindex[self.addr]
        dis[src] = 0
        for v, c in edge[src]:
            dis[v] = c
            first[v] = v
            heapq.heappush(hp, (c, v))
        while(hp):
            u = heapq.heappop(hp)[1]
            if(vis[u]):
                continue
            vis[u] = 1
            for v,c in edge[u]:
                ndis = dis[u] + c
                if(dis[v] != -1 and ndis >= dis[v]):
                    continue
                dis[v] = ndis
                first[v] = first[u]
                heapq.heappush(hp, (dis[v], v))
        addr2port = {a:p for p, (a, _) in self.port2edge.items()}
        try:
            self.addr2shortestport = {toaddr[v]:addr2port[toaddr[first[v]]] for v in range(L) if (first[v] != -1)}
        except:
            print(self.addr)
            print(addr2port)
            print(self.glbmap)
            exit(-1)

    def mapset(self, a, b, c):
        disca = self.glbmap.get(a)
        if(not disca):
            self.glbmap.update({a:{b:c}})
        else:
            disca.update({b:c})

    def mappop(self, a, b):
        disca = self.glbmap.get(a)
        if(disca and disca.get(b)):
            disca.pop(b)

    def mapadd(self, addru, sendid, addrv, cost):
        self.mapset(addru, addrv, cost)
        self.mapset(addrv, addru, cost)

    def maprem(self, addru, sendid, addrv):
        self.mappop(addru, addrv)
        self.mappop(addrv, addru)

    def mapupd(self, addru, sendid, umap):
        preumap = self.glbmap.get(addru)
        directlinkvalue = None
        if(preumap):
            directlinkvalue = preumap.get(self.addr) # 看addru是否有与我相连的边
            for v in preumap.keys():
                self.glbmap[v].pop(addru)
        self.glbmap.update({addru: umap})
        for v, c in umap.items():
            self.mapset(v, addru, c)

        if(directlinkvalue):  # 非常关键，如果一个人的upd要改我的边，不允许他在我的地图里改（他的信息可能是滞后或超前的）。我的边应该全部由自己管辖，这样才不会导致我的port数组和map数组不匹配
            self.mapadd(self.addr, None, addru, directlinkvalue)
        else:
            self.maprem(self.addr, None, addru)

    def handleNewLink(self, port, endpoint, cost):

        # print("in newlink", self.addr, endpoint, cost)
        # self.handleRemoveLink(port) # is this usable?
        self.port2edge.update({port: (endpoint, cost)})
        self.handlePacket(None, Packet(Packet.ROUTING, self.addr, None, dumps((self.pktadd, (self.addr, self.sendid, endpoint, cost)))))
        self.sendid = self.sendid + 1

    def handleRemoveLink(self, port):
        prelink = self.port2edge.get(port)
        if (prelink):
            endpoint = prelink[0]
            self.port2edge.pop(port)
            self.handlePacket(None, Packet(Packet.ROUTING, self.addr, None, dumps((self.pktrem, (self.addr, self.sendid, endpoint)))))
            self.sendid = self.sendid + 1

    def handleTime(self, timeMillisecs):
        if timeMillisecs - self.last_time >= self.heartbeatTime:
            self.last_time = timeMillisecs
            self.handlePacket(None, Packet(Packet.ROUTING, self.addr, None, dumps((self.pktupd, (self.addr, self.sendid, self.glbmap[self.addr])))))
            self.sendid = self.sendid + 1
            # Hints:
            # broadcast the link state of this router to all neighbors

    def debugString(self):
        """TODO: generate a string for debugging in network visualizer"""
        return ""


import os
import pytest
from frictionless import Table, Resource, validate
from frictionless import FrictionlessException

BASE_URL = "https://raw.githubusercontent.com/frictionlessdata/datapackage-py/master/%s"

# Table

def test_table_multipart():
    with Table(["data/chunk1.csv", "data/chunk2.csv"]) as table:
        assert table.header == ["id", "name"]
        assert table.read_rows() == [
            {"id": 1, "name": "english"},
            {"id": 2, "name": "中国人"},
        ]

def test_table_multipart_with_compressed_parts():
    with Table(["data/chunk1.csv.zip", "data/chunk2.csv.zip"]) as table:
        assert table.compression == "no"
        assert table.compression_path == ""
        assert table.header == ["id", "name"]
        assert table.read_rows() == [
            {"id": 1, "name": "english"},
            {"id": 2, "name": "中国人"},
        ]

# Resource

def test_resource_source_multipart():
    descriptor = {
        "path": ["chunk1.csv", "chunk2.csv"],
        "schema": "resource-schema.json",
    }
    resource = Resource(descriptor, basepath="data")
    assert resource.inline is False
    assert resource.multipart is True
    assert resource.tabular is True
    assert resource.read_rows() == [
        {"id": 1, "name": "english"},
        {"id": 2, "name": "中国人"},
    ]

@pytest.mark.ci
def test_resource_source_multipart_remote():
    descriptor = {
        "name": "name",
        "path": ["chunk2.csv", "chunk3.csv"],
        "dialect": {"header": False},
        "schema": "resource_schema.json",
    }
    resource = Resource(descriptor, basepath=BASE_URL % "data")
    assert resource.inline is False
    assert resource.multipart is True
    assert resource.tabular is True
    assert resource.read_rows() == [
        {"id": 2, "name": "中国人"},
        {"id": 3, "name": "german"},
    ]

@pytest.mark.ci
def test_resource_source_multipart_remote_both_path_and_basepath():
    descriptor = {
        "name": "name",
        "path": ["chunk2.csv", BASE_URL % "data/chunk3.csv"],
        "dialect": {"header": False},
        "schema": "resource_schema.json",
    }
    resource = Resource(descriptor, basepath=BASE_URL % "data")
    assert resource.inline is False
    assert resource.multipart is True
    assert resource.tabular is True
    assert resource.read_rows() == [
        {"id": 2, "name": "中国人"},
        {"id": 3, "name": "german"},
    ]

def test_resource_source_multipart_error_bad_path():
    resource = Resource({"name": "name", "path": ["chunk1.csv", "chunk2.csv"]})
    with pytest.raises(FrictionlessException) as excinfo:
        resource.read_rows()
    error = excinfo.value.error
    assert error.code == "scheme-error"
    assert error.note == "[Errno 2] No such file or directory: 'chunk1.csv'"

def test_resource_source_multipart_error_bad_path_not_safe_absolute():
    bad_path = os.path.abspath("data/chunk1.csv")
    with pytest.raises(FrictionlessException) as excinfo:
        Resource({"name": "name", "path": [bad_path, "data/chunk2.csv"]})
    error = excinfo.value.error
    assert error.code == "resource-error"
    assert error.note.count("not safe")

def test_resource_source_multipart_error_bad_path_not_safe_traversing():
    bad_path = os.path.abspath("data/../chunk2.csv")
    with pytest.raises(FrictionlessException) as excinfo:
        Resource({"name": "name", "path": ["data/chunk1.csv", bad_path]})
    error = excinfo.value.error
    assert error.code == "resource-error"
    assert error.note.count("not safe")

def test_resource_source_multipart_infer():
    descriptor = {"path": ["data/chunk1.csv", "data/chunk2.csv"]}
    resource = Resource(descriptor)
    resource.infer()
    assert resource == {
        "path": ["data/chunk1.csv", "data/chunk2.csv"],
        "profile": "tabular-data-resource",
        "name": "chunk1",
        "scheme": "multipart",
        "format": "csv",
        "hashing": "md5",
        "encoding": "utf-8",
        "compression": "no",
        "compressionPath": "",
        "control": {"newline": ""},
        "dialect": {},
        "query": {},
        "schema": {
            "fields": [
                {"name": "id", "type": "integer"},
                {"name": "name", "type": "string"},
            ]
        },
        "stats": {
            "hash": "6c2c61dd9b0e9c6876139a449ed87933",
            "bytes": 30,
            "fields": 2,
            "rows": 2,
        },
    }

# TODO: fix this test
@pytest.mark.skip
def test_resource_multipart_write_file(tmpdir):
    source = "data/table.json"
    target = str(tmpdir.join("table{number}.json"))
    target1 = str(tmpdir.join("table1.json"))
    target2 = str(tmpdir.join("table2.json"))

    # Write
    resource = Resource(path=source)
    resource.write(target, scheme="multipart", control={"chunkSize": 80})

    # Read
    resource = Resource(path=[target1, target2], trusted=True)
    resource.read_header() == ["id", "name"]
    assert resource.read_rows() == [
        {"id": 1, "name": "english"},
        {"id": 2, "name": "中国人"},
    ]

# Validate

def test_validate_multipart_resource():
    report = validate({"path": ["data/chunk1.csv", "data/chunk2.csv"]})
    assert report.valid
    assert report.table.stats["rows"] == 2


import io
import os
import subprocess
import serial
import time
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()

#serial_write("COM2","text")
#return 1 on success
#return 0 on fail
def serial_write(obj, string):
        if(obj.write(string.encode('utf-8'))):
                return 1 #on success
        else:
                return 0 #on fail

#serial_read("COM2")
#return text on success
#return 0 on fail.
#def serial_read(chosen_port): #return 0 if no data was readed
#        recived_string = chosen_port.readline()
def serial_read_line(obj):
        wiadomosc = obj.readline()
        if(wiadomosc != "b''"):
                if(len(wiadomosc)!=0):
                        print( wiadomosc)
                        try:
                                wiadomosc = wiadomosc.decode("utf-8")
                                wiadomosc = wiadomosc.replace('\r','')
                                wiadomosc = wiadomosc.replace('\n','')
                                print('Po odkodowaniu: "'+ wiadomosc+'"')
                                return(wiadomosc)
                        except:
                                return("Oczekiwanie")

def serial_clear_read_buffer(obj):
        obj.reset_input_buffer()

def readData(object): #object type:  object = serial.Serial()
    buffer = ""
    while True:
        oneByte = object.read(1)
        if oneByte == b"\n":    #method should returns bytes #wait for EOL
            return buffer
        else:
            buffer += oneByte.decode("ascii")

# Program to find most frequent
# element in a list
def most_frequent(List):
        if(len(List)==0):
                return -1
        else:
                return max(set(List), key = List.count)

############################END Funkcje obsługi seriala

#return dictionary com:id
def print_what_is_connected_to_all_com_ports():
        print("Dostępne porty com: ")
        for port, desc, hwid in sorted(ports):
                print("{}: {} [{}]".format(port, desc, hwid))
        print()
        print("Dostępne porty com: ")
        for port in sorted(ports):
                print("{}".format(port))
        print()
        seq = []
        numer = 0
        slownik_port_nazwa = {}
        for port in sorted(ports):
            port = str(port)[:5]
            port = str(port).lstrip().rstrip()
            print("Odnaleziony port COM: "+str(port))
            if(str(port).find("USB")>-1 or str(port).find("COM")>-1):
                    print("Odnaleziony port COM: "+str(port))
                    ser = serial.Serial(port, 9600, timeout=1,\
                    parity=serial.PARITY_NONE,\
                    stopbits=serial.STOPBITS_ONE,\
                    bytesize=serial.EIGHTBITS)
                    time.sleep(1)
                    print("Otwieram port:")
                    #ser.open()
                    print("Nadaję wiadomość: NB\\r\\n")
                    print(("NB\r\n".encode()))
                    print("Czekam na odpowiedź")
                    serial_write(ser, "NB\r\n")
                    #ser.write(bytes(b"?\r\n")) #bytes() works
                    #ser.write("?".encode()) #works too
                    serial_write(ser, "C0\r\n")
                    #time.sleep(1)
                    lista_z_identyfikatorami = []
                    counter = 0
                    liczba_udanych_odbiorow = 0
                    polaczone_wiadomosci = ""
                    while 1:
                        #serial_clear_read_buffer(ser)
                        serial_write(ser, "NB\r\n")
                        message = serial_read_line(ser)
                        print((message))
                        if(str(message)!="None" and str(message)!="NB"):
                            counter = 0
                            polaczone_wiadomosci = polaczone_wiadomosci + str(message)+"|"
                        else: counter=counter+1
                        if str(message).find("NB A") != -1:
                            lista_z_identyfikatorami.append(str(message).replace("NB A","").replace('"','').strip())
                            liczba_udanych_odbiorow = liczba_udanych_odbiorow+1
                        if(liczba_udanych_odbiorow == 10):
                            serial_write(ser, "C1\r\n")
                            break
                        if(counter==5):
                            break
                    ser.close()
                    print("Najpopularniejszy element listy to: " + str(most_frequent(lista_z_identyfikatorami))+" i występuje on na porcie: "+port)
                    slownik_port_nazwa.update({str(most_frequent(lista_z_identyfikatorami)):port})
        print("widomosc")
        print(str(message))
        print(polaczone_wiadomosci)
        for krotka in lista_z_identyfikatorami:
                print(krotka)
        print()
        print("Mamy słownik co jest podłączone na każdym porcie")
        print(slownik_port_nazwa)
        return slownik_port_nazwa

slownik_xd = print_what_is_connected_to_all_com_ports()

#ok. Skanowanie portów masz już zaliczone
#Masz już słownik zawierajacy co jest na każdym porcie.
#teraz musimy wczytać ustawienia. Co, jest z czym?

file1 = open('ustawienia.txt', 'r')
lista = file1.readlines()
# Strips the newline character
count = 0
linia_gdzie_gotowe = 0
linia_gdzie_pairs=0
linia_gdzie_serial_settings = 0
for line in lista:
    if(line.strip().find("gotowe")!=-1 and line.find("=")!=-1 ):
        linia_gdzie_gotowe = count
    if(line.strip().find("pairs")!=-1):
        linia_gdzie_pairs = count
    if(line.strip().find("serial_settings")!=-1):
        linia_gdzie_serial_settings = count
    print("Line{}: {}".format(count, line.strip()))
    count += 1

print("Linia gdzie znajduje się string gotowe= "+str(linia_gdzie_gotowe))

print("Linia gdzie znajduje się string pairs= "+str(linia_gdzie_pairs))

print("Linia gdzie znajduje się string serial_settings= "+str(linia_gdzie_serial_settings))

print()

#Waga lewa piecowa^SCALE_ID#123456&PILOT_ID#pilot_jeden|pozX=0|pozY=0
def splituj_argumenty_z_napisu(zdanie,slownik):
        nazwa_wagi = (zdanie.split("^"))[0]
        print("Nazwa gui wagi:"+nazwa_wagi)
        SCALE_ID= (((((zdanie.split("&"))[0]).split("^"))[1]).split("#"))[1]
        print("ID WAGI:"+SCALE_ID)
        SCALE_PORT = slownik[SCALE_ID]
        print("PORT WAGI:" +SCALE_PORT)
        PILOT_ID= (((((zdanie.split("&"))[1]).split("|"))[0]).split("#"))[1]
        print("ID PILOTA:"+PILOT_ID)
        PILOT_PORT=slownik[PILOT_ID]
        print("PORT PILOTA:"+PILOT_PORT)
        pozX= ((zdanie.split("|"))[1].split("="))[1]
        pozY= ((zdanie.split("|"))[2].split("="))[1]
        print("POZ_X:"+pozX+" POZ_Y:"+pozY)
        print('"'+nazwa_wagi+"|"+SCALE_PORT+"|"+PILOT_PORT+"|"+pozX+"|"+pozY+'"')
        #os.system('gui0.2.py "'+nazwa_wagi+"|"+SCALE_PORT+"|"+PILOT_PORT+"|"+pozX+"|"+pozY)
        subprocess.call(
            'python gui0.2.py "'+nazwa_wagi+"|"+SCALE_PORT+"|"+PILOT_PORT+"|"+pozX+"|"+pozY+'"',
            shell=True
        )

print("Linie do dalszego splita")
lista_par = []
for i in range(linia_gdzie_pairs+1,linia_gdzie_serial_settings):
        print(str(i)+"||"+ lista[i].strip())
        splituj_argumenty_z_napisu(lista[i].strip(),slownik_xd)

Wagi radwag folder ostateczny/0.2/list_all_ports0.2_pyserial.py


import random
from itertools import groupby
import operator

SYMBOLS = ['♠', '♢', '♡', '♣']
SUIT = ['Hearts', 'Spades', 'Diamonds']
RANK = ['A', '2', '3', '4', '5']
RANK_VALUE = {'A': 1, '2': 2, '3': 3, '4': 4, '5': 5}
SUIT_SYMBOLS = {'Hearts': '♡', 'Spades': '♠', 'Diamonds': '♢'}

class Player:
    def __init__(self, name, character="None", turn="None", bluff_prob="None", call_prob="None", belief_model="None"):
        self.stash = list()
        self.grouped_stash = None
        self.name = name
        self.character = character
        self.turn = turn
        self.bluff_prob = bluff_prob
        self.call_prob = call_prob
        self.belief_model = belief_model

    def set_bluff_prob(self, bluff_prob):
        self.bluff_prob = bluff_prob

    def set_call_prob(self, call_prob):
        self.call_prob = call_prob

    def addTo_hand(self, card):
        try:
            self.stash.append(card)
            if len(self.stash) == 5:
                self.stash.sort(key=operator.attrgetter('rank'))
                self.grouped_stash = [list(v) for k, v in groupby(self.stash, key=operator.attrgetter('rank'))]
                # self.stash.sort(key=operator.attrgetter('rank'))
            if len(self.stash) > 5:
                raise ValueError('ERROR: Player cannot have more than 14 cards during turn')
        except ValueError as err:
            print(err.args)

    def removeFrom_hand(self, card):
        self.stash.remove(card)

    def play_Player(self, previous_card):
        random_card = random.choice(self.stash)
        print(self.name + " played " + random_card.rank + SUIT_SYMBOLS[random_card.suit])
        self.stash.remove(random_card)

        if (len(self.stash) == 0):
            return True
        else:
            return False

    def play_allrank(self, new_round, game_obj):
        max_len = 0
        max_list = 0
        if new_round == 0: #if new round
            for i in self.grouped_stash:  # find the rank with maximum cards
                if len(i) > max_len:
                    max_len = len(i)
                    max_list = i
        else:
            for i in self.grouped_stash:
                if game_obj.played_deck[-1][0].rank == i[0].rank:
                    max_list = i
                    break
        if max_list == 0:
            return 0
        self.grouped_stash.remove(max_list)
        game_obj.played_deck.append(max_list)
        for card in max_list:
            print(self.name + " played " + card.rank + SUIT_SYMBOLS[card.suit])
        for card in max_list:
            self.stash.remove(card)
        return 1

class CredulousPlayer(Player):
    def __init__(self, name):
        super().__init__(name, character="Credulous")

    def play(self, new_round, game_obj):
        played = self.play_allrank(new_round, game_obj)
        if played == 0:  #card not found, player must pass
            print(self.name + "passed")
            return 0
        else:
            print("End of turn for " + self.name)
            print("\n")
            return 1


import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.distributions import Normal
import numpy as np
import copy
import utils
import random
import pdb
from utils import soft_update, hard_update
LOG_SIG_MAX = 2
LOG_SIG_MIN = -20
epsilon = 1e-6
# Initialize Policy weights
def weights_init_(m):
    if isinstance(m, nn.Linear):
        torch.nn.init.xavier_uniform_(m.weight, gain=1)
        torch.nn.init.constant_(m.bias, 0)

class ValueNetwork(nn.Module):
    def __init__(self, num_inputs, hidden_dim):
        super(ValueNetwork, self).__init__()

        self.linear1 = nn.Linear(num_inputs, hidden_dim)
        self.linear2 = nn.Linear(hidden_dim, hidden_dim)
        self.linear3 = nn.Linear(hidden_dim, 1)

        self.apply(weights_init_)

    def forward(self, state):
        x = F.relu(self.linear1(state))
        x = F.relu(self.linear2(x))
        x = self.linear3(x)
        return x

class QNetwork(nn.Module):
    def __init__(self, num_inputs, num_actions, hidden_dim):
        super(QNetwork, self).__init__()

        # Q1 architecture
        self.linear1 = nn.Linear(num_inputs + num_actions, hidden_dim)
        self.linear2 = nn.Linear(hidden_dim, hidden_dim)
        self.linear3 = nn.Linear(hidden_dim, 1)

        # Q2 architecture
        self.linear4 = nn.Linear(num_inputs + num_actions, hidden_dim)
        self.linear5 = nn.Linear(hidden_dim, hidden_dim)
        self.linear6 = nn.Linear(hidden_dim, 1)

        self.apply(weights_init_)

    def forward(self, state, action):
        xu = torch.cat([state, action], 1)

        x1 = F.relu(self.linear1(xu))
        x1 = F.relu(self.linear2(x1))
        x1 = self.linear3(x1)

        x2 = F.relu(self.linear4(xu))
        x2 = F.relu(self.linear5(x2))
        x2 = self.linear6(x2)

        return x1, x2

class GaussianPolicy(nn.Module):
    def __init__(self, num_inputs, num_actions, hidden_dim, action_space=None):
        super(GaussianPolicy, self).__init__()

        self.linear1 = nn.Linear(num_inputs, hidden_dim)
        self.linear2 = nn.Linear(hidden_dim, hidden_dim)

        self.mean_linear = nn.Linear(hidden_dim, num_actions)
        self.log_std_linear = nn.Linear(hidden_dim, num_actions)

        self.apply(weights_init_)

        # action rescaling
        if action_space is None:
            self.action_scale = torch.tensor(1.)
            self.action_bias = torch.tensor(0.)
        else:
            self.action_scale = torch.FloatTensor(
                (action_space.high - action_space.low) / 2.)
            self.action_bias = torch.FloatTensor(
                (action_space.high + action_space.low) / 2.)

    def forward(self, state):
        x = F.relu(self.linear1(state))
        x = F.relu(self.linear2(x))
        mean = self.mean_linear(x)
        log_std = self.log_std_linear(x)
        log_std = torch.clamp(log_std, min=LOG_SIG_MIN, max=LOG_SIG_MAX)
        return mean, log_std

    def sample(self, state):
        mean, log_std = self.forward(state)
        std = log_std.exp()
        normal = Normal(mean, std)
        x_t = normal.rsample()  # for reparameterization trick (mean + std * N(0,1))
        y_t = torch.tanh(x_t)
        action = y_t * self.action_scale + self.action_bias
        log_prob = normal.log_prob(x_t)
        # Enforcing Action Bound
        log_prob -= torch.log(self.action_scale * (1 - y_t.pow(2)) + epsilon)
        log_prob = log_prob.sum(1, keepdim=True)
        mean = torch.tanh(mean) * self.action_scale + self.action_bias
        return action, log_prob, mean

    def to(self, device):
        self.action_scale = self.action_scale.to(device)
        self.action_bias = self.action_bias.to(device)
        return super(GaussianPolicy, self).to(device)

class DeterministicPolicy(nn.Module):
    def __init__(self, num_inputs, num_actions, hidden_dim, action_space=None):
        super(DeterministicPolicy, self).__init__()
        self.linear1 = nn.Linear(num_inputs, hidden_dim)
        self.linear2 = nn.Linear(hidden_dim, hidden_dim)

        self.mean = nn.Linear(hidden_dim, num_actions)
        self.noise = torch.Tensor(num_actions)

        self.apply(weights_init_)

        # action rescaling
        if action_space is None:
            self.action_scale = 1.
            self.action_bias = 0.
        else:
            self.action_scale = torch.FloatTensor(
                (action_space.high - action_space.low) / 2.)
            self.action_bias = torch.FloatTensor(
                (action_space.high + action_space.low) / 2.)

    def forward(self, state):
        x = F.relu(self.linear1(state))
        x = F.relu(self.linear2(x))
        mean = torch.tanh(self.mean(x)) * self.action_scale + self.action_bias
        return mean

    def sample(self, state):
        mean = self.forward(state)
        noise = self.noise.normal_(0., std=0.1)
        noise = noise.clamp(-0.25, 0.25)
        action = mean + noise
        return action, torch.tensor(0.), mean

    def to(self, device):
        self.action_scale = self.action_scale.to(device)
        self.action_bias = self.action_bias.to(device)
        self.noise = self.noise.to(device)
        return super(DeterministicPolicy, self).to(device)

class SAC(object):
    def __init__(self, num_inputs, action_space, args, writer=None, outdir=None, device=torch.device("cpu")):
        self.index = 0
        self.gamma = args.gamma
        self.tau = args.tau
        self.alpha = args.alpha
        self.writer = writer
        self.outdir = outdir
        self.batch_size = args.batch_size
        self.save_freq = args.save_freq

        self.policy_type = args.policy
        self.target_update_interval = args.target_update_interval
        self.automatic_entropy_tuning = args.automatic_entropy_tuning

        self.device = device

        self.replay_buffer = utils.ReplayMemory(capacity=args.buffer_max_size, seed=args.seed)

        self.critic = QNetwork(num_inputs, action_space.shape[0], args.hidden_size).to(device=self.device)
        self.critic_optim = torch.optim.Adam(self.critic.parameters(), lr=args.lr)

        self.critic_target = QNetwork(num_inputs, action_space.shape[0], args.hidden_size).to(self.device)
        hard_update(self.critic_target, self.critic)

        if self.policy_type == "Gaussian":
            # Target Entropy = −dim(A) (e.g. , -6 for HalfCheetah-v2) as given in the paper
            if self.automatic_entropy_tuning is True:
                self.target_entropy = -torch.prod(torch.Tensor(action_space.shape).to(self.device)).item()
                self.log_alpha = torch.zeros(1, requires_grad=True, device=self.device)
                self.alpha_optim = torch.optim.Adam([self.log_alpha], lr=args.lr)

            self.policy = GaussianPolicy(num_inputs, action_space.shape[0], args.hidden_size, action_space).to(self.device)
            self.policy_optim = torch.optim.Adam(self.policy.parameters(), lr=args.lr)

        else:
            self.alpha = 0
            self.automatic_entropy_tuning = False
            self.policy = DeterministicPolicy(num_inputs, action_space.shape[0], args.hidden_size, action_space).to(self.device)
            self.policy_optim = torch.optim.Adam(self.policy.parameters(), lr=args.lr)

    def select_action(self, state, evaluate=False):
        state = torch.FloatTensor(state).to(self.device).unsqueeze(0)
        if evaluate is False:
            action, _, _ = self.policy.sample(state)
        else:
            _, _, action = self.policy.sample(state)
        return action.detach().cpu().numpy()[0]

    def add_buffer(self, state, action, next_state, reward,  done):
        self.replay_buffer.push(state, action, next_state, reward, done)

    def update_parameters(self):
        # Sample a batch from memory
        state_batch, action_batch, next_state_batch, reward_batch, mask_batch = self.replay_buffer.sample(batch_size=self.batch_size)
        state_batch = torch.FloatTensor(state_batch).to(self.device)
        next_state_batch = torch.FloatTensor(next_state_batch).to(self.device)
        action_batch = torch.FloatTensor(action_batch).to(self.device)
        reward_batch = torch.FloatTensor(reward_batch).to(self.device).unsqueeze(1)
        mask_batch = torch.FloatTensor(mask_batch).to(self.device).unsqueeze(1)

        with torch.no_grad():
            next_state_action, next_state_log_pi, _ = self.policy.sample(next_state_batch)
            qf1_next_target, qf2_next_target = self.critic_target(next_state_batch, next_state_action)
            min_qf_next_target = torch.min(qf1_next_target, qf2_next_target) - self.alpha * next_state_log_pi
            next_q_value = reward_batch + mask_batch * self.gamma * (min_qf_next_target)
        qf1, qf2 = self.critic(state_batch, action_batch)  # Two Q-functions to mitigate positive bias in the policy improvement step
        qf1_loss = F.mse_loss(qf1, next_q_value)  # JQ = 𝔼(st,at)~D[0.5(Q1(st,at) - r(st,at) - γ(𝔼st+1~p[V(st+1)]))^2]
        qf2_loss = F.mse_loss(qf2, next_q_value)  # JQ = 𝔼(st,at)~D[0.5(Q1(st,at) - r(st,at) - γ(𝔼st+1~p[V(st+1)]))^2]
        qf_loss = qf1_loss + qf2_loss

        self.critic_optim.zero_grad()
        qf_loss.backward()
        self.critic_optim.step()

        pi, log_pi, _ = self.policy.sample(state_batch)

        qf1_pi, qf2_pi = self.critic(state_batch, pi)
        min_qf_pi = torch.min(qf1_pi, qf2_pi)

        policy_loss = ((self.alpha * log_pi) - min_qf_pi).mean() # Jπ = 𝔼st∼D,εt∼N[α * logπ(f(εt;st)|st) − Q(st,f(εt;st))]

        self.policy_optim.zero_grad()
        policy_loss.backward()
        self.policy_optim.step()

        if self.automatic_entropy_tuning:
            alpha_loss = -(self.log_alpha * (log_pi + self.target_entropy).detach()).mean()

            self.alpha_optim.zero_grad()
            alpha_loss.backward()
            self.alpha_optim.step()

            self.alpha = self.log_alpha.exp()
            alpha_tlogs = self.alpha.clone() # For TensorboardX logs
        else:
            alpha_loss = torch.tensor(0.).to(self.device)
            alpha_tlogs = torch.tensor(self.alpha) # For TensorboardX logs

        if self.index % self.target_update_interval == 0:
            soft_update(self.critic_target, self.critic, self.tau)

        if self.writer:
            self.writer.add_scalar('loss/critic_1', qf1_loss.item(), self.index)
            self.writer.add_scalar('loss/critic_2', qf2_loss.item(), self.index)
            self.writer.add_scalar('loss/policy', policy_loss.item(), self.index)
            self.writer.add_scalar('loss/entropy_loss', alpha_loss.item(), self.index)
            self.writer.add_scalar('entropy_temprature/alpha', alpha_tlogs.item(), self.index)
        if self.index % self.save_freq == 0:
            self.save_model()

        self.index += 1
        return qf1_loss.item(), qf2_loss.item(), policy_loss.item(), alpha_loss.item(), alpha_tlogs.item()

    def save_model(self):
        print('saving...')
        if self.outdir != None:
            torch.save(self.policy.state_dict(),self.outdir + '/actor_{:07d}.ckpt'.format(self.index))
            torch.save(self.critic.state_dict(),self.outdir + '/critic_{:07d}.ckpt'.format(self.index))
            torch.save(self.critic_target.state_dict(),self.outdir + '/critic_target_{:07d}.ckpt'.format(self.index))
        else:
            torch.save(self.policy.state_dict(),'./saved_models/actor_{:07d}.ckpt'.format(self.index))
            torch.save(self.critic.state_dict(),'./saved_models/critic_{:07d}.ckpt'.format(self.index))
            torch.save(self.critic_target.state_dict(),'./saved_models/critic_target_{:07d}.ckpt'.format(self.index))
        # self.replay_buffer.save()
        print('finish saving')
    # Load model parameters
    def load_model(self, actor_path, critic_path):
        print('Loading models from {} and {}'.format(actor_path, critic_path))
        if actor_path is not None:
            self.policy.load_state_dict(torch.load(actor_path, map_location=self.device))
        if critic_path is not None:
            self.critic.load_state_dict(torch.load(critic_path, map_location=self.device))
    def restore_model_for_test(self, index):
        self.policy.load_state_dict(torch.load('./saved_models/actor_{:07d}.ckpt'.format(index), map_location = self.device))
        # self.critic.load_state_dict(torch.load('./saved_models/critic_{:07d}.ckpt'.format(index), map_location = self.device))
        print('finish restoring model')

class Critic(torch.nn.Module):
    def __init__(self, state_dim:int , action_dim:int, hidden_size: int = 256):
        super(Critic, self).__init__()
        self.state_dim = state_dim
        self.action_dim	= action_dim
        self.hidden_size = hidden_size
        self.fc_1 = nn.Linear(state_dim + action_dim, hidden_size)
        self.fc_2 = nn.Linear(hidden_size, hidden_size)
        self.fc_3 = nn.Linear(hidden_size, hidden_size)
        self.fc_4 = nn.Linear(hidden_size, 1)
    def forward(self, state, action):
        hidden = torch.cat((state,action), dim=-1)
        hidden = F.relu(self.fc_1(hidden))
        hidden = F.relu(self.fc_2(hidden))
        hidden = F.relu(self.fc_3(hidden))
        q_value = self.fc_4(hidden)
        return q_value

if __name__ == "__main__":
    adversarial_dqn = AdversarialDQN(state_dim=3, n_actions=3,device='cpu',writer=None)
    dumb_state = np.ones(3)
    dumb_next_state = np.ones(3)
    dumb_action = np.array([1])
    dumb_reward = 10
    adversarial_dqn.add_buffer(dumb_state, dumb_action, dumb_next_state, dumb_reward, False)
    adversarial_dqn.train()
    print('finish')


# -*- coding: utf-8 -*-

from parser.modules import MLP, BertEmbedding, Biaffine, BiLSTM, CharLSTM
from parser.modules.dropout import IndependentDropout, SharedDropout
from parser.utils.alg import eisner
from parser.utils.fn import istree

import torch
import torch.nn as nn
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence

from typing import Dict, Optional, Tuple, Any, List

class Model(nn.Module):

    def __init__(self, args, mask_token_id=0):
        super(Model, self).__init__()

        self.args = args
        if args.n_embed:
            # the embedding layer
            self.word_embed = nn.Embedding(num_embeddings=args.n_words,
                                           embedding_dim=args.n_embed)
            self.unk_index = args.unk_index
        else:
            self.word_embed = None
        if args.feat == 'char':
            self.feat_embed = CharLSTM(n_chars=args.n_feats,
                                       n_embed=args.n_char_embed,
                                       n_out=args.n_feat_embed,
                                       pad_index=args.feat_pad_index)
            self.pad_index = args.pad_index
        elif args.feat == 'bert':
            if not hasattr(args, 'token_dropout'):
                args.token_dropout = 0.0 # PATCH
            self.feat_embed = BertEmbedding(model=args.bert_model,
                                            n_layers=args.n_bert_layers,
                                            n_out=args.n_feat_embed,
                                            requires_grad=args.bert_fine_tune,
                                            mask_token_id=mask_token_id,
                                            token_dropout=args.token_dropout,
                                            mix_dropout=args.mix_dropout,
                                            use_hidden_states=args.use_hidden_states,
                                            n_attentions=args.n_mlp_arc if args.n_attentions else 0,
                                            attention_layer=args.attention_layer)
            self.args.n_feat_embed = self.feat_embed.n_out # taken from the model
            self.args.n_bert_layers = self.feat_embed.n_layers # taken from the model
            self.pad_index = self.feat_embed.pad_index     # taken from the model
            self.args.pad_index = self.pad_index           # update
        else:
            self.feat_embed = nn.Embedding(num_embeddings=args.n_feats,
                                           embedding_dim=args.n_feat_embed)
            self.pad_index = args.pad_index
        self.embed_dropout = IndependentDropout(p=args.embed_dropout)

        if args.n_lstm_layers:
            # the lstm layer
            self.lstm = BiLSTM(input_size=args.n_embed+args.n_feat_embed,
                               hidden_size=args.n_lstm_hidden,
                               num_layers=args.n_lstm_layers,
                               dropout=args.lstm_dropout)
            self.lstm_dropout = SharedDropout(p=args.lstm_dropout)
            mlp_input_size = args.n_lstm_hidden*2
        else:
            self.lstm = None
            mlp_input_size = args.n_embed + args.n_feat_embed

        # the MLP layers
        self.mlp_arc_d = MLP(n_in=mlp_input_size,
                             n_out=args.n_mlp_arc,
                             dropout=args.mlp_dropout)
        self.mlp_arc_h = MLP(n_in=mlp_input_size,
                             n_out=args.n_mlp_arc,
                             dropout=args.mlp_dropout)
        self.mlp_rel_d = MLP(n_in=mlp_input_size,
                             n_out=args.n_mlp_rel,
                             dropout=args.mlp_dropout)
        self.mlp_rel_h = MLP(n_in=mlp_input_size,
                             n_out=args.n_mlp_rel,
                             dropout=args.mlp_dropout)

        # the Biaffine layers
        self.arc_attn = Biaffine(n_in=args.n_mlp_arc,
                                 bias_x=True,
                                 bias_y=False)
        self.rel_attn = Biaffine(n_in=args.n_mlp_rel,
                                 n_out=args.n_rels,
                                 bias_x=True,
                                 bias_y=True)

        # transformer attention
        if args.n_attentions:
            self.attn_mix = nn.Parameter(torch.randn(1))

        self.criterion = nn.CrossEntropyLoss()

    def extra_repr(self):
        total_params = sum(p.numel() for p in self.parameters())
        trainable_params = sum(p.numel() for p in self.parameters() if p.requires_grad)
        return f"Total parameters: {total_params}\n" \
            f"Trainable parameters: {trainable_params}"

    def load_pretrained(self, embed=None):
        if embed is not None:
            self.pretrained = nn.Embedding.from_pretrained(embed)
            nn.init.zeros_(self.word_embed.weight)

        return self

    def forward(self, words: torch.Tensor,
                feats: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        # words, feats are the first two items in the batch from TextDataLoader.__iter__()
        if words is None:
            words = feats[:,:,0] # drop subpiece dimension
        batch_size, seq_len = words.shape
        mask = words.ne(self.pad_index)
        # get the mask and lengths of given batch
        lens = mask.sum(dim=1)
        feat_embed, attn = self.feat_embed(feats)
        if self.word_embed:
            ext_words = words
            # set the indices larger than num_embeddings to unk_index
            if hasattr(self, 'pretrained'):
                ext_mask = words.ge(self.word_embed.num_embeddings)
                ext_words = words.masked_fill(ext_mask, self.unk_index)

            # get outputs from embedding layers
            word_embed = self.word_embed(ext_words)
            if hasattr(self, 'pretrained'):
                word_embed += self.pretrained(words)
            word_embed, feat_embed = self.embed_dropout(word_embed, feat_embed)
            # concatenate the word and feat representations
            embed = torch.cat((word_embed, feat_embed), dim=-1)
        else:
            embed = self.embed_dropout(feat_embed)[0]

        if self.lstm:
            x = pack_padded_sequence(embed, lens, True, False)
            x, _ = self.lstm(x)
            x, _ = pad_packed_sequence(x, True, total_length=seq_len)
            x = self.lstm_dropout(x)
        else:
            x = embed

        # apply MLPs to the BiLSTM output states
        arc_d = self.mlp_arc_d(x)
        arc_h = self.mlp_arc_h(x)
        rel_d = self.mlp_rel_d(x)
        rel_h = self.mlp_rel_h(x)

        # [batch_size, seq_len, seq_len]
        s_arc = self.arc_attn(arc_d, arc_h)
        # [batch_size, seq_len, seq_len, n_rels]
        s_rel = self.rel_attn(rel_d, rel_h).permute(0, 2, 3, 1)

        # mix bert attentions
        if attn is not None:
            s_arc += self.attn_mix * attn
        # set the scores that exceed the length of each sentence to -inf
        s_arc.masked_fill_(~mask.unsqueeze(1), float('-inf'))
        # Lower the diagonal, because the head of a word can't be itself.
        s_arc += torch.diag(s_arc.new(seq_len).fill_(float('-inf')))

        return s_arc, s_rel

    def loss(self, s_arc: torch.Tensor, s_rel: torch.Tensor,
             arcs: torch.Tensor, rels: torch.Tensor,
             mask: torch.Tensor) -> torch.Tensor:
        """
        Computes the arc and tag loss for a sequence given gold heads and tags.
        Parameters
        ----------
        s_arc : ``torch.Tensor``, required.
            A tensor of shape (batch_size, sequence_length, tags_count),
            which will be used to generate predictions for the dependency tags
            for the given arcs.
        s_rel : ``torch.Tensor``, required
            A tensor of shape (batch_size, sequence_length, tags_count),
            which will be used to generate predictions for the dependency tags
            for the given arcs.
        arcs : ``torch.Tensor``, required.
            A tensor of shape (batch_size, sequence_length).
            The indices of the heads for each word.
        rels : ``torch.Tensor``, required.
            A tensor of shape (batch_size, sequence_length).
            The dependency labels of the heads for each word.
        mask : ``torch.Tensor``, required.
            A mask of shape (batch_size, sequence_length), denoting unpadded
            elements in the sequence.
        Returns
        -------
        loss : ``torch.Tensor``.
            The sum of the cross-entropy losses from the arcs and rels predictions.
        """
        s_arc, arcs = s_arc[mask], arcs[mask]
        s_rel, rels = s_rel[mask], rels[mask]
        # select the predicted relations towards the correct heads
        s_rel = s_rel[torch.arange(len(arcs)), arcs]
        arc_loss = self.criterion(s_arc, arcs)
        rel_loss = self.criterion(s_rel, rels)

        return arc_loss + rel_loss

    def decode(self, s_arc: torch.Tensor, s_rel: torch.Tensor,
               mask: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        lens = mask.sum(1)
        # prevent self-loops
        s_arc.diagonal(0, 1, 2).fill_(float('-inf'))
        # select the most likely arcs
        arc_preds = s_arc.argmax(-1)
        if self.args.tree:
            # ensure the arcs form a tree
            bad = [not istree(seq[:i+1], self.args.proj)
                   for i, seq in zip(lens.tolist(), arc_preds.tolist())]
            if any(bad):
                arc_preds[bad] = eisner(s_arc[bad], mask[bad])
        # select the most likely rels
        rel_preds = s_rel.argmax(-1)
        # choose those corresponding to the predicted arcs
        rel_preds = rel_preds.gather(-1, arc_preds.unsqueeze(-1)).squeeze(-1)

        return arc_preds, rel_preds

    @classmethod
    def load(cls, path):
        device = 'cuda' if torch.cuda.is_available() else 'cpu'
        state = torch.load(path, map_location=device)
        model = cls(state['args'])
        model.load_pretrained(state['pretrained'])
        model.load_state_dict(state['state_dict'], False)
        model.to(device)

        return model

    def save(self, path):
        state_dict, pretrained = self.state_dict(), None
        if hasattr(self, 'pretrained'):
            pretrained = state_dict.pop('pretrained.weight')
        state = {
            'args': self.args,
            'state_dict': state_dict,
            'pretrained': pretrained
        }
        torch.save(state, path)


from tkinter import*
from tkinter import ttk
import pymysql
class student:
    def __init__(self,root):
        self.root=root
        self.root.title("student management system")
        self.root.geometry("1600x900+0+0")
        title=Label(self.root,text="student management system",bd=10,relief=GROOVE,font=("times new roman",40,"bold"),bg="black",fg="green")
        title.pack(side=TOP,fill=X)

        #=========variables========

        self.roll_no_var=StringVar()
        self.name_var=StringVar()
        self.email_var=StringVar()
        self.gender_var=StringVar()
        self.contact_var=StringVar()
        self.dob_var=StringVar()

        Manage_Frame=Frame(self.root,bd=4,relief=RIDGE,bg="black")
        Manage_Frame.place(x=20,y=100,width=450,height=670)

        m_title=Label(Manage_Frame,text="manage students",bg="black",fg="green",font=("times new roman",20,"bold"))
        m_title.grid(row=0,columnspan=2,pady=20)

        lbl_roll=Label(Manage_Frame,text="Roll number",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_roll.grid(row=1,column=0,pady=10,padx=20,sticky="w")

        txt_roll=Entry(Manage_Frame,textvariable=self.roll_no_var,font=("times new roman",15,"bold"),bd=5,relief=GROOVE)
        txt_roll.grid(row=1,column=1,pady=10,padx=20,sticky="w")

        lbl_name=Label(Manage_Frame,text="name",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_name.grid(row=2,column=0,pady=10,padx=20,sticky="w")

        txt_name=Entry(Manage_Frame,textvariable=self.name_var,font=("times new roman",15,"bold"),bd=5,relief=GROOVE)
        txt_name.grid(row=2,column=1,pady=10,padx=20,sticky="w")

        lbl_email=Label(Manage_Frame,text="email",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_email.grid(row=3,column=0,pady=10,padx=20,sticky="w")

        txt_email=Entry(Manage_Frame,textvariable=self.email_var,font=("times new roman",15,"bold"),bd=5,relief=GROOVE)
        txt_email.grid(row=3,column=1,pady=10,padx=20,sticky="w")

        lbl_gender=Label(Manage_Frame,text="gender",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_gender.grid(row=4,column=0,pady=10,padx=20,sticky="w")

        combo_gender=ttk.Combobox(Manage_Frame,textvariable=self.gender_var,font=("times new roman",14,"bold"),state='readonly')
        combo_gender['values']=("male","female","other")
        combo_gender.grid(row=4,column=1,pady=10,padx=20,sticky="w")

        lbl_contact=Label(Manage_Frame,text="contact",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_contact.grid(row=5,column=0,pady=10,padx=20,sticky="w")

        txt_contact=Entry(Manage_Frame,textvariable=self.contact_var,font=("times new roman",15,"bold"),bd=5,relief=GROOVE)
        txt_contact.grid(row=5,column=1,pady=10,padx=20,sticky="w")

        lbl_dob=Label(Manage_Frame,text="DOB",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_dob.grid(row=6,column=0,pady=10,padx=20,sticky="w")

        txt_dob=Entry(Manage_Frame,textvariable=self.dob_var,font=("times new roman",15,"bold"),bd=5,relief=GROOVE)
        txt_dob.grid(row=6,column=1,pady=10,padx=20,sticky="w")

        lbl_address=Label(Manage_Frame,text="address",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_address.grid(row=7,column=0,pady=10,padx=20,sticky="w")

        self.txt_address=Text(Manage_Frame,width=20,height=3)
        self.txt_address.grid(row=7,column=1,pady=10,padx=20,sticky="w")

        btn_Frame=Frame(Manage_Frame,bd=4,relief=RIDGE,bg="black")
        btn_Frame.place(x=10,y=500,width=430)

        Addbtn=Button(btn_Frame,text="Add",width=10,command=self.add_students).grid(row=0,column=0,padx=10,pady=10)
        Updatebtn=Button(btn_Frame,text="Update",width=10).grid(row=0,column=1,padx=10,pady=10)
        Deletebtn=Button(btn_Frame,text="Delete",width=10).grid(row=0,column=2,padx=10,pady=10)
        Clearbtn=Button(btn_Frame,text="Clear",width=10).grid(row=0,column=3,padx=10,pady=10)

        Detail_Frame=Frame(self.root,bd=4,relief=RIDGE,bg="black")
        Detail_Frame.place(x=500,y=100,width=950,height=670)

        lbl_search=Label(Detail_Frame,text="search by",bg="black",fg="green",font=("times new roman",20,"bold"))
        lbl_search.grid(row=0,column=0,pady=10,padx=20,sticky="w")

        combo_search=ttk.Combobox(Detail_Frame,font=("times new roman",14,"bold"),state='readonly')
        combo_search['values']=("roll","name","contact")
        combo_search.grid(row=0,column=1,pady=10,padx=20)

        txt_search=Entry(Detail_Frame,font=("times new roman",15,"bold"),bd=5,relief=GROOVE)
        txt_search.grid(row=0,column=2,pady=10,padx=20,sticky="w")

        searchbtn=Button(Detail_Frame,text="search",width=10).grid(row=0,column=3,padx=10,pady=10)
        showallbtn=Button(Detail_Frame,text="showall",width=10).grid(row=0,column=4,padx=10,pady=10)

        table_Frame=Frame(Detail_Frame,bd=4,relief=RIDGE,bg="black")
        table_Frame.place(x=10,y=70,width=830,height=550)

        scroll_x=Scrollbar(table_Frame,orient=HORIZONTAL)
        scroll_y=Scrollbar(table_Frame,orient=VERTICAL)
        student_table=ttk.Treeview(table_Frame,columns=("roll","name","gender","contact","dob","email","address"),xscrollcommand=scroll_x.set,yscrollcommand=scroll_y.set)
        scroll_x.pack(side=BOTTOM,fill=X)
        scroll_y.pack(side=RIGHT,fill=Y)
        scroll_x.config(command=student_table.xview)
        scroll_y.config(command=student_table.yview)
        student_table.heading("roll",text="roll number")
        student_table.heading("name",text="Name")
        student_table.heading("gender",text="Gender")
        student_table.heading("contact",text="contact number")
        student_table.heading("dob",text="DOB")
        student_table.heading("email",text="email ID")
        student_table.heading("address",text="address")
        student_table['show']='headings'
        student_table.pack(fill=BOTH,expand=1)
    def add_students(self):

            con=pymysql.connect(host="localhost",user="root",password="",database="stms")
            cur=con.cursor()
            cur.execute("insert into student values(%s,%s,%s,%s,%s,%s,%s)",(self.roll_no_var.get(),
                                                                            self.name_var.get(),
                                                                            self.email_var.get(),
                                                                            self.gender_var.get(),
                                                                            self.contact_var.get(),
                                                                            self.dob_var.get(),
                                                                            self.txt_address.get('1.0',END)
                                                                             ))
            con.commit()
            con.close()

root=Tk()
ob=student(root)
root.mainloop()


from dagster import check
from dagster.utils.indenting_printer import IndentingStringIoPrinter

def format_config_for_graphql(config):
    '''This recursive descent thing formats a config dict for GraphQL.'''

    def _format_config_subdict(config, current_indent=0):
        check.dict_param(config, 'config', key_type=str)

        printer = IndentingStringIoPrinter(indent_level=2, current_indent=current_indent)
        printer.line('{')

        n_elements = len(config)
        for i, key in enumerate(sorted(config, key=lambda x: x[0])):
            value = config[key]
            with printer.with_indent():
                formatted_value = (
                    _format_config_item(value, current_indent=printer.current_indent)
                    .lstrip(' ')
                    .rstrip('\n')
                )
                printer.line(
                    '{key}: {formatted_value}{comma}'.format(
                        key=key,
                        formatted_value=formatted_value,
                        comma=',' if i != n_elements - 1 else '',
                    )
                )
        printer.line('}')

        return printer.read()

    def _format_config_sublist(config, current_indent=0):
        printer = IndentingStringIoPrinter(indent_level=2, current_indent=current_indent)
        printer.line('[')

        n_elements = len(config)
        for i, value in enumerate(config):
            with printer.with_indent():
                formatted_value = (
                    _format_config_item(value, current_indent=printer.current_indent)
                    .lstrip(' ')
                    .rstrip('\n')
                )
                printer.line(
                    '{formatted_value}{comma}'.format(
                        formatted_value=formatted_value, comma=',' if i != n_elements - 1 else ''
                    )
                )
        printer.line(']')

        return printer.read()

    def _format_config_item(config, current_indent=0):
        printer = IndentingStringIoPrinter(indent_level=2, current_indent=current_indent)

        if isinstance(config, dict):
            return _format_config_subdict(config, printer.current_indent)
        elif isinstance(config, list):
            return _format_config_sublist(config, printer.current_indent)
        elif isinstance(config, bool):
            return repr(config).lower()
        else:
            return repr(config).replace('\'', '"')

    check.dict_param(config, 'config', key_type=str)
    if not isinstance(config, dict):
        check.failed('Expected a dict to format as config, got: {item}'.format(item=repr(config)))

    return _format_config_subdict(config)


import numpy as np
import matplotlib.image as mpimg
from scipy import ndimage as ndi
import os, sys

def load_image(infilename):
    data = mpimg.imread(infilename)
    return data

def load_training_set(root_dir, max_images = 20):
    im_dir = root_dir + "images/"
    gt_dir = root_dir + "groundtruth/"
    #cn_dir = root_dir + "cannyedges/"

    files = os.listdir(im_dir)
    n = min(max_images, len(files))

    imgs    = [load_image(im_dir + files[i]) for i in range(n)]
    gt_imgs = [load_image(gt_dir + files[i]) for i in range(n)]
    pr_imgs    = [process(i) for i in imgs]

    return imgs, pr_imgs, gt_imgs

def process(rgb):
    return rgb

def sharpen(rgb, alpha = 0.1):
    blurred = blur(rgb, 1.0)
    return np.clip(rgb + alpha * (rgb - blurred), 0.0, 255.0)

def median(rgb, size = 5):
    bl = np.zeros(rgb.shape)
    bl[:, :, 0] = ndi.median_filter(rgb[:, :, 0], size)
    bl[:, :, 1] = ndi.median_filter(rgb[:, :, 1], size)
    bl[:, :, 2] = ndi.median_filter(rgb[:, :, 2], size)
    return bl

def blur(rgb, sig = 3.0):
    bl = np.zeros(rgb.shape)
    bl[:, :, 0] = ndi.gaussian_filter(rgb[:, :, 0], sig)
    bl[:, :, 1] = ndi.gaussian_filter(rgb[:, :, 1], sig)
    bl[:, :, 2] = ndi.gaussian_filter(rgb[:, :, 2], sig)
    return bl

def saturate(rgb, amount):
    bl = np.zeros(rgb.shape)
    bl[:, :, 0] = ndi.gaussian_filter(rgb[:, :, 0], sig)
    bl[:, :, 1] = ndi.gaussian_filter(rgb[:, :, 1], sig)
    bl[:, :, 2] = ndi.gaussian_filter(rgb[:, :, 2], sig)
    return bl

def to_bool(gray, threshold = 0.75):
    return gray > threshold

def to_lum(rgb):
    r = rgb[:, :, 0]
    g = rgb[:, :, 1]
    b = rgb[:, :, 2]
    return 0.2989 * r + 0.5870 * g + 0.1140 * b

def to_gray(rgb):
    r = rgb[:, :, 0]
    g = rgb[:, :, 1]
    b = rgb[:, :, 2]
    return (r + g + b) / 3.0

def to_rgb(img):
    if len(img.shape) == 3:
        return img

    img_3c = np.zeros((img.shape[0], img.shape[1], 3))
    img_3c[:, :, 0] = img
    img_3c[:, :, 1] = img
    img_3c[:, :, 2] = img
    return img_3c