############################################################
# -*- coding: utf-8 -*-
#
#       #   #  #   #   #    #
#      ##  ##  #  ##  #    #
#     # # # #  # # # #    #  #
#    #  ##  #  ##  ##    ######
#   #   #   #  #   #       #
#
# Python-based Tool for interaction with the 10micron mounts
# GUI with PyQT5 for python
#
# written in python3, (c) 2019-2023 by mworion
# Licence APL2.0
#
###########################################################
from base import packageConfig

# standard libraries
from datetime import datetime
import time

# external packages
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTransform
from skyfield.almanac import dark_twilight_day, TWILIGHTS

# local import
if packageConfig.isAvailable:
    from gui.extWindows.simulatorW import SimulatorWindow

from gui.utilities.toolsQtWidget import sleepAndEvents
from gui.extWindows.keypadW import KeypadWindow
from gui.utilities.stylesQtCss import Styles
from gui.utilities.toolsQtWidget import MWidget
from gui.extWindows.messageW import MessageWindow
from gui.extWindows.hemisphereW import HemisphereWindow
from gui.extWindows.measureW import MeasureWindow
from gui.extWindows.imageW import ImageWindow
from gui.extWindows.satelliteW import SatelliteWindow
from gui.extWindows.analyseW import AnalyseWindow
from gui.extWindows.videoW1 import VideoWindow1
from gui.extWindows.videoW2 import VideoWindow2
from gui.extWindows.videoW3 import VideoWindow3
from gui.extWindows.videoW4 import VideoWindow4
from gui.extWindows.bigPopupW import BigPopup
from gui.widgets.main_ui import Ui_MainWindow
from gui.mainWmixin.tabMount import Mount
from gui.mainWmixin.tabEnviron import Environ
from gui.mainWmixin.tabAlmanac import Almanac
from gui.mainWmixin.tabModel import Model
from gui.mainWmixin.runBasic import BasicRun
from gui.mainWmixin.tabBuildPoints import BuildPoints
from gui.mainWmixin.tabManageModel import ManageModel
from gui.mainWmixin.tabSat_Search import SatSearch
from gui.mainWmixin.tabSat_Track import SatTrack
from gui.mainWmixin.tabMinorPlanet import MinorPlanet
from gui.mainWmixin.tabRelay import Relay
from gui.mainWmixin.tabTools_Rename import Rename
from gui.mainWmixin.tabTools_IERSTime import IERSTime
from gui.mainWmixin.tabAnalysis import Analysis
from gui.mainWmixin.tabPower import Power
from gui.mainWmixin.tabSett_Device import SettDevice
from gui.mainWmixin.tabSett_Mount import SettMount
from gui.mainWmixin.tabSett_Dome import SettDome
from gui.mainWmixin.tabSett_ParkPos import SettParkPos
from gui.mainWmixin.tabSett_Relay import SettRelay
from gui.mainWmixin.tabSett_Misc import SettMisc
from gui.mainWmixin.tabImage_Manage import ImageManage
from gui.mainWmixin.tabImage_Stats import ImagsStats
from logic.profiles.profile import loadProfile, saveProfile, blendProfile

class MainWindow(
    MWidget,
    SettMisc,
    Mount,
    Environ,
    Almanac,
    Model,
    BasicRun,
    BuildPoints,
    ManageModel,
    SatSearch,
    SatTrack,
    MinorPlanet,
    Relay,
    Power,
    Rename,
    IERSTime,
    Analysis,
    SettDevice,
    SettMount,
    ImageManage,
    ImagsStats,
    SettDome,
    SettParkPos,
    SettRelay,
):
    """
    the main window class handles the main menu as well as the show and no show
    part of any other window. all necessary processing for functions of that gui
    will be linked to this class. therefore, window classes will have a threadpool
    for managing async processing if needed.
    """

    __all__ = ['MainWindow']

    def __init__(self, app):
        # has to be put before super to adjust the color before the stylesheet
        # on the parent classes is drawn first
        colSet = app.config.get('colorSet', 0)
        Styles.colorSet = colSet
        super().__init__()
        self.app = app
        self.msg = app.msg
        self.threadPool = app.threadPool
        self.deviceStat = app.deviceStat
        self.uiWindows = app.uiWindows
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.satStatus = False
        self.gameControllerRunning = False
        self.setWindowTitle(f'MountWizzard4 - v{self.app.__version__}')

        self.uiWindows['showMessageW'] = {
            'button': self.ui.openMessageW,
            'classObj': None,
            'name': 'MessageDialog',
            'class': MessageWindow,
        }
        self.uiWindows['showHemisphereW'] = {
            'button': self.ui.openHemisphereW,
            'classObj': None,
            'name': 'HemisphereDialog',
            'class': HemisphereWindow,
        }
        self.uiWindows['showImageW'] = {
            'button': self.ui.openImageW,
            'classObj': None,
            'name': 'ImageDialog',
            'class': ImageWindow,
        }
        self.uiWindows['showMeasureW'] = {
            'button': self.ui.openMeasureW,
            'classObj': None,
            'name': 'MeasureDialog',
            'class': MeasureWindow,
        }
        self.uiWindows['showSatelliteW'] = {
            'button': self.ui.openSatelliteW,
            'classObj': None,
            'name': 'SatelliteDialog',
            'class': SatelliteWindow,
        }
        self.uiWindows['showAnalyseW'] = {
            'button': self.ui.openAnalyseW,
            'classObj': None,
            'name': 'AnalyseDialog',
            'class': AnalyseWindow,
        }
        self.uiWindows['showVideoW1'] = {
            'button': self.ui.openV1,
            'classObj': None,
            'name': 'Video1',
            'class': VideoWindow1,
        }
        self.uiWindows['showVideoW2'] = {
            'button': self.ui.openV2,
            'classObj': None,
            'name': 'Video2',
            'class': VideoWindow2,
        }
        self.uiWindows['showVideoW3'] = {
            'button': self.ui.openV3,
            'classObj': None,
            'name': 'Video3',
            'class': VideoWindow3,
        }
        self.uiWindows['showVideoW4'] = {
            'button': self.ui.openV4,
            'classObj': None,
            'name': 'Video4',
            'class': VideoWindow4,
        }
        if packageConfig.isAvailable:
            self.uiWindows['showSimulatorW'] = {
                'button': self.ui.mountConnected,
                'classObj': None,
                'name': 'SimulatorDialog',
                'class': SimulatorWindow,
            }
        self.uiWindows['showKeypadW'] = {
            'button': self.ui.openKeypadW,
            'classObj': None,
            'name': 'KeypadDialog',
            'class': KeypadWindow,
        }
        self.uiWindows['showBigPopupW'] = {
            'button': self.ui.big,
            'classObj': None,
            'name': 'BigPopup',
            'class': BigPopup,
        }
        self.deviceStatGui = {
            'dome': self.ui.domeConnected,
            'camera': self.ui.cameraConnected,
            'refraction': self.ui.refractionConnected,
            'plateSolve': self.ui.plateSolveConnected,
            'mount': self.ui.mountConnected,
        }
        self.mwSuper('__init__')
        self.app.mount.signals.pointDone.connect(self.updateStatusGUI)
        self.app.mount.signals.mountUp.connect(self.updateMountConnStat)
        self.app.mount.signals.settingDone.connect(self.updateMountWeatherStat)
        self.app.remoteCommand.connect(self.remoteCommand)
        self.app.plateSolve.signals.message.connect(self.updatePlateSolveStatus)
        self.app.dome.signals.message.connect(self.updateDomeStatus)
        self.app.camera.signals.message.connect(self.updateCameraStatus)
        self.ui.saveConfigQuit.clicked.connect(self.quitSave)
        self.ui.loadFrom.clicked.connect(self.loadProfileGUI)
        self.ui.addFrom.clicked.connect(self.addProfileGUI)
        self.ui.saveConfigAs.clicked.connect(self.saveConfigAs)
        self.ui.saveConfig.clicked.connect(self.saveConfig)
        self.app.seeingWeather.b = self.ui.label_b.property('a')

        for window in self.uiWindows:
            self.uiWindows[window]['button'].clicked.connect(self.toggleWindow)

        self.initConfig()
        self.ui.colorSet.currentIndexChanged.connect(self.refreshColorSet)
        self.ui.collectWindows.clicked.connect(self.collectWindows)
        self.showExtendedWindows()
        self.activateWindow()

        self.ui.tabsMovable.clicked.connect(self.enableTabsMovable)
        self.app.update1s.connect(self.updateTime)
        self.app.update1s.connect(self.updateControllerStatus)
        self.app.update1s.connect(self.updateThreadAndOnlineStatus)
        self.app.update1s.connect(self.updateWindowsStats)
        self.app.update1s.connect(self.smartFunctionGui)
        self.app.update1s.connect(self.smartTabGui)
        self.app.update1s.connect(self.updateWindowsStats)
        self.app.update1s.connect(self.setEnvironDeviceStats)
        self.app.update1s.connect(self.updateDeviceStats)

    def initConfig(self):
        """
        :return: True for test purpose
        """
        config = self.app.config
        self.ui.profile.setText(config.get('profileName'))
        colSet = config.get('colorSet', 0)
        Styles.colorSet = colSet
        self.ui.colorSet.setCurrentIndex(colSet)
        self.setStyleSheet(self.mw4Style)

        if 'mainW' not in config:
            config['mainW'] = {}
        config = config['mainW']

        self.positionWindow(config)
        self.mwSuper('initConfig')
        self.setTabAndIndex(self.ui.mainTabWidget, config, 'orderMain')
        self.setTabAndIndex(self.ui.mountTabWidget, config, 'orderMount')
        self.setTabAndIndex(self.ui.imagingTabWidget, config, 'orderImaging')
        self.setTabAndIndex(self.ui.modelingTabWidget, config, 'orderModeling')
        self.setTabAndIndex(self.ui.manageTabWidget, config, 'orderManage')
        self.setTabAndIndex(self.ui.settingsTabWidget, config, 'orderSettings')
        self.setTabAndIndex(self.ui.toolsTabWidget, config, 'orderTools')
        self.setTabAndIndex(self.ui.satTabWidget, config, 'orderSatellite')

        self.changeStyleDynamic(self.ui.mountConnected, 'color', 'gray')
        self.smartTabGui()
        self.enableTabsMovable()
        self.setupIcons()
        self.show()
        return True

    def storeConfigExtendedWindows(self):
        """
        :return: True for test purpose
        """
        config = self.app.config
        for window in self.uiWindows:
            config[window] = bool(self.uiWindows[window]['classObj'])
            if config[window]:
                self.uiWindows[window]['classObj'].storeConfig()

        return True

    def storeConfig(self):
        """
        :return: True for test purpose
        """
        config = self.app.config
        config['colorSet'] = self.ui.colorSet.currentIndex()
        config['profileName'] = self.ui.profile.text()
        if 'mainW' not in config:
            config['mainW'] = {}
        else:
            config['mainW'].clear()
        config = config['mainW']

        config['winPosX'] = self.pos().x()
        config['winPosY'] = self.pos().y()
        self.getTabAndIndex(self.ui.mainTabWidget, config, 'orderMain')
        self.getTabAndIndex(self.ui.mountTabWidget, config, 'orderMount')
        self.getTabAndIndex(self.ui.imagingTabWidget, config, 'orderImaging')
        self.getTabAndIndex(self.ui.modelingTabWidget, config, 'orderModeling')
        self.getTabAndIndex(self.ui.manageTabWidget, config, 'orderManage')
        self.getTabAndIndex(self.ui.settingsTabWidget, config, 'orderSettings')
        self.getTabAndIndex(self.ui.toolsTabWidget, config, 'orderTools')
        self.getTabAndIndex(self.ui.satTabWidget, config, 'orderSatellite')
        self.mwSuper('storeConfig')
        self.storeConfigExtendedWindows()
        return True

    def enableTabsMovable(self):
        """
        :return: True for test purpose
        """
        isMovable = self.ui.tabsMovable.isChecked()
        self.ui.mainTabWidget.setMovable(isMovable)
        self.ui.mountTabWidget.setMovable(isMovable)
        self.ui.imagingTabWidget.setMovable(isMovable)
        self.ui.modelingTabWidget.setMovable(isMovable)
        self.ui.manageTabWidget.setMovable(isMovable)
        self.ui.settingsTabWidget.setMovable(isMovable)
        self.ui.toolsTabWidget.setMovable(isMovable)
        self.ui.satTabWidget.setMovable(isMovable)
        self.app.tabsMovable.emit(isMovable)
        return True

    def closeEvent(self, closeEvent):
        """
        :return:    nothing
        """
        self.gameControllerRunning = False
        self.app.timer0_1s.stop()
        self.changeStyleDynamic(self.ui.pauseModel, 'pause', False)
        self.closeExtendedWindows()
        self.stopDrivers()
        self.threadPool.waitForDone(5000)
        super().closeEvent(closeEvent)
        self.app.quit()

    def quitSave(self):
        """
        :return:    true for test purpose
        """
        self.app.storeConfig()
        self.saveConfig()
        self.close()
        return True

    def setupIcons(self):
        """
        :return:    True if success for test
        """
        # main window
        self.wIcon(self.ui.saveConfigAs, 'save')
        self.wIcon(self.ui.loadFrom, 'load')
        self.wIcon(self.ui.addFrom, 'load')
        self.wIcon(self.ui.saveConfig, 'save')
        self.wIcon(self.ui.saveConfigQuit, 'save')
        self.wIcon(self.ui.mountOn, 'power-on')
        self.wIcon(self.ui.mountOff, 'power-off')
        self.wIcon(self.ui.stop, 'hand')
        self.wIcon(self.ui.tracking, 'target')
        self.wIcon(self.ui.followSat, 'satellite')
        self.wIcon(self.ui.flipMount, 'flip')
        self.wIcon(self.ui.setSiderealTracking, 'sidereal')
        self.wIcon(self.ui.setLunarTracking, 'lunar')
        self.wIcon(self.ui.setSolarTracking, 'solar')
        self.wIcon(self.ui.park, 'park')

        # model points
        self.wIcon(self.ui.loadBuildPoints, 'load')
        self.wIcon(self.ui.saveBuildPoints, 'save')
        self.wIcon(self.ui.saveBuildPointsAs, 'save')
        self.wIcon(self.ui.clearBuildP, 'trash')

        # model
        self.wIcon(self.ui.plateSolveSync, 'start')
        pixmap = self.img2pixmap(':/pics/azimuth.png').scaled(101, 101)
        self.ui.picAZ.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/pics/altitude.png').scaled(101, 101)
        self.ui.picALT.setPixmap(pixmap)

        self.wIcon(self.ui.cancelModel, 'cross-circle')
        self.wIcon(self.ui.runModel, 'start')
        self.wIcon(self.ui.pauseModel, 'pause')
        self.wIcon(self.ui.endModel, 'stop_m')
        self.wIcon(self.ui.dataModel, 'choose')

        # manage model
        self.wIcon(self.ui.runOptimize, 'start')
        self.wIcon(self.ui.cancelOptimize, 'cross-circle')
        self.wIcon(self.ui.deleteWorstPoint, 'circle-minus')
        self.wIcon(self.ui.clearModel, 'trash')
        self.wIcon(self.ui.openAnalyseW, 'bar-chart')
        self.wIcon(self.ui.showActualModelAnalyse, 'copy')
        self.wIcon(self.ui.showOriginalModelAnalyse, 'copy')

        self.wIcon(self.ui.loadName, 'load')
        self.wIcon(self.ui.saveName, 'save')
        self.wIcon(self.ui.deleteName, 'trash')
        self.wIcon(self.ui.refreshName, 'reload')
        self.wIcon(self.ui.refreshModel, 'reload')

        # minor planets
        self.wIcon(self.ui.progMinorPlanetsFull, 'run')
        self.wIcon(self.ui.progMinorPlanetsFiltered, 'run')
        self.wIcon(self.ui.progMinorPlanetsSelected, 'run')
        self.wIcon(self.ui.progEarthRotationData, 'run')
        self.wIcon(self.ui.downloadIERS, 'run')

        # satellite
        self.wIcon(self.ui.stopSatelliteTracking, 'cross-circle')
        self.wIcon(self.ui.startSatelliteTracking, 'start')
        self.wIcon(self.ui.progSatellitesFull, 'run')
        self.wIcon(self.ui.progSatellitesFiltered, 'run')
        self.wIcon(self.ui.progTrajectory, 'run')

        # analyse
        self.wIcon(self.ui.runFlexure, 'start')
        self.wIcon(self.ui.runHysteresis, 'start')
        self.wIcon(self.ui.cancelAnalysis, 'cross-circle')

        # tools
        self.wIcon(self.ui.renameStart, 'start')
        self.wIcon(self.ui.renameInputSelect, 'folder')
        self.wIcon(self.ui.posButton0, 'target')
        self.wIcon(self.ui.posButton1, 'target')
        self.wIcon(self.ui.posButton2, 'target')
        self.wIcon(self.ui.posButton3, 'target')
        self.wIcon(self.ui.posButton4, 'target')
        self.wIcon(self.ui.posButton5, 'target')
        self.wIcon(self.ui.posButton6, 'target')
        self.wIcon(self.ui.posButton7, 'target')
        self.wIcon(self.ui.posButton8, 'target')
        self.wIcon(self.ui.posButton9, 'target')

        self.wIcon(self.ui.moveNorth, 'north')
        self.wIcon(self.ui.moveEast, 'east')
        self.wIcon(self.ui.moveSouth, 'south')
        self.wIcon(self.ui.moveWest, 'west')
        self.wIcon(self.ui.moveNorthEast, 'northEast')
        self.wIcon(self.ui.moveNorthWest, 'northWest')
        self.wIcon(self.ui.moveSouthEast, 'southEast')
        self.wIcon(self.ui.moveSouthWest, 'southWest')
        self.wIcon(self.ui.moveNorthAltAz, 'north')
        self.wIcon(self.ui.moveEastAltAz, 'east')
        self.wIcon(self.ui.moveSouthAltAz, 'south')
        self.wIcon(self.ui.moveWestAltAz, 'west')
        self.wIcon(self.ui.moveNorthEastAltAz, 'northEast')
        self.wIcon(self.ui.moveNorthWestAltAz, 'northWest')
        self.wIcon(self.ui.moveSouthEastAltAz, 'southEast')
        self.wIcon(self.ui.moveSouthWestAltAz, 'southWest')
        self.wIcon(self.ui.stopMoveAll, 'stop_m')
        self.wIcon(self.ui.moveAltAzAbsolute, 'target')
        self.wIcon(self.ui.moveRaDecAbsolute, 'target')

        # driver setting
        for driver in self.drivers:
            if self.drivers[driver]['uiSetup'] is not None:
                ui = self.drivers[driver]['uiSetup']
                self.wIcon(ui, 'cogs')

        self.wIcon(self.ui.ascomConnect, 'link')
        self.wIcon(self.ui.ascomDisconnect, 'unlink')

        # imaging
        self.wIcon(self.ui.copyFromTelescopeDriver, 'copy')
        self.wIcon(self.ui.haltFocuser, 'bolt-alt')
        self.wIcon(self.ui.moveFocuserIn, 'exit-down')
        self.wIcon(self.ui.moveFocuserOut, 'exit-up')
        self.wIcon(self.ui.coverPark, 'exit-down')
        self.wIcon(self.ui.coverUnpark, 'exit-up')

        # dome setting
        pixmap = self.img2pixmap(':/dome/radius.png')
        self.ui.picDome1.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/north.png')
        self.ui.picDome2.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/east.png')
        self.ui.picDome3.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/z_gem.png')
        self.ui.picDome4.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/z_10micron.png')
        self.ui.picDome5.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/gem.png')
        self.ui.picDome6.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/lat.png')
        self.ui.picDome7.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/shutter.png')
        self.ui.picDome8.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/hysteresis.png')
        self.ui.picDome9.setPixmap(pixmap)
        pixmap = self.img2pixmap(':/dome/zenith.png')
        self.ui.picDome10.setPixmap(pixmap)
        self.wIcon(self.ui.copyFromDomeDriver, 'copy')
        self.wIcon(self.ui.domeCloseShutter, 'exit-down')
        self.wIcon(self.ui.domeOpenShutter, 'exit-up')
        self.wIcon(self.ui.domeAbortSlew, 'bolt-alt')

        # park positions
        self.wIcon(self.ui.posSave0, 'download')
        self.wIcon(self.ui.posSave1, 'download')
        self.wIcon(self.ui.posSave2, 'download')
        self.wIcon(self.ui.posSave3, 'download')
        self.wIcon(self.ui.posSave4, 'download')
        self.wIcon(self.ui.posSave5, 'download')
        self.wIcon(self.ui.posSave6, 'download')
        self.wIcon(self.ui.posSave7, 'download')
        self.wIcon(self.ui.posSave8, 'download')
        self.wIcon(self.ui.posSave9, 'download')

        # misc setting
        self.wIcon(self.ui.installVersion, 'world')
        pixmap = self.svg2pixmap(':/icon/controller.svg', self.M_BLUE)
        self.ui.controller1.setPixmap(pixmap.scaled(16, 16))
        self.ui.controller2.setPixmap(pixmap.scaled(16, 16))
        self.ui.controller3.setPixmap(pixmap.scaled(16, 16))
        self.ui.controller4.setPixmap(pixmap.scaled(16, 16))
        self.ui.controller5.setPixmap(pixmap.scaled(16, 16))
        pixmap = self.svg2pixmap(':/icon/controllerNew.svg', self.M_BLUE)
        self.ui.controllerOverview.setPixmap(pixmap)
        self.ui.controller1.setEnabled(False)
        self.ui.controller2.setEnabled(False)
        self.ui.controller3.setEnabled(False)
        self.ui.controller4.setEnabled(False)
        self.ui.controller5.setEnabled(False)

        # environment
        pixmap = self.svg2pixmap(':/icon/meteoblue.svg', '#124673')
        pixmap = pixmap.transformed(QTransform().rotate(-90))
        pixmap = pixmap.scaled(37, 128, 1)
        self.ui.meteoblueIcon.setPixmap(pixmap)
        self.ui.meteoblueIcon.setVisible(False)
        self.ui.meteoblueSeeing.setVisible(False)
        return True

    def updateMountConnStat(self, status):
        """
        updateMountConnStat show the connection status of the mount. if status
        is None, which means there is no valid host entry for connection,
        the status is grey

        :param status:
        :return: true for test purpose
        """
        hasSim = packageConfig.isAvailable
        self.deviceStat['mount'] = status

        if status and hasSim:
            self.ui.mountConnected.setEnabled(status)
            self.ui.mountConnected.setText('Mount 3D')
        elif status:
            self.ui.mountConnected.setText('Mount')
        elif not status and hasSim:
            self.ui.mountConnected.setText('Mount')
            if self.uiWindows['showSimulatorW']['classObj']:
                self.uiWindows['showSimulatorW']['classObj'].close()
        return True

    def updateMountWeatherStat(self, setting):
        """
        updateMountWeatherStat show the connection status of the mount weather
        station connected. if the data values are None there is no station
        attached to the GPS port.

        :return: true for test purpose
        """
        if setting.weatherTemperature is None and setting.weatherPressure is None:
            self.deviceStat['directWeather'] = None
        else:
            if setting.weatherStatus is None:
                self.deviceStat['directWeather'] = False
            else:
                self.deviceStat['directWeather'] = True
        return True

    def smartFunctionGui(self):
        """
        smartFunctionGui enables and disables gui actions depending on the
        actual state of the different devices. this should be the core of
        avoiding user misused during running operations. smartGui is run every
        1 second synchronously, because it can't be simpler done with dynamic
        approach. all different situations in a running environment is done
        locally.

        :return: true for test purpose
        """
        isMountReady = bool(self.deviceStat.get('mount'))
        isDomeReady = bool(self.deviceStat.get('dome'))
        isModelingReady = all(
            bool(self.deviceStat.get(x)) for x in ['mount', 'camera', 'plateSolve'])
        isPause = self.ui.pauseModel.property('pause')

        if isModelingReady and self.app.data.buildP and not isPause:
            self.ui.runModel.setEnabled(True)
        else:
            self.ui.runModel.setEnabled(False)

        if isModelingReady:
            self.ui.runModel.setEnabled(True)
            self.ui.plateSolveSync.setEnabled(True)
            self.ui.dataModel.setEnabled(True)
            self.ui.runFlexure.setEnabled(True)
            self.ui.runHysteresis.setEnabled(True)
        else:
            self.ui.runModel.setEnabled(False)
            self.ui.plateSolveSync.setEnabled(False)
            self.ui.dataModel.setEnabled(False)
            self.ui.runFlexure.setEnabled(False)
            self.ui.runHysteresis.setEnabled(False)

        if isMountReady:
            self.ui.refractionGroup.setEnabled(True)
            self.ui.dsoGroup.setEnabled(True)
            self.ui.mountCommandTable.setEnabled(True)
        else:
            self.ui.dsoGroup.setEnabled(False)
            self.ui.refractionGroup.setEnabled(False)
            self.ui.mountCommandTable.setEnabled(False)

        if isDomeReady and isMountReady:
            self.ui.useDomeAz.setEnabled(True)
        else:
            self.ui.useDomeAz.setEnabled(False)

        return True

    def smartTabGui(self):
        """
        smartTabGui enables and disables tab visibility depending on the actual
        state of the different devices.
        :return: true for test purpose
        """
        smartTabs = {
            'Power': {
                'statID': 'power',
                'tab': self.ui.toolsTabWidget,
            },
            'Relay': {
                'statID': 'relay',
                'tab': self.ui.toolsTabWidget,
            },
            'RelaySett': {
                'statID': 'relay',
                'tab': self.ui.settingsTabWidget,
            },
        }
        tabChanged = False

        for key, tab in smartTabs.items():
            tabIndex = self.getTabIndex(smartTabs[key]['tab'], key)
            tabStatus = smartTabs[key]['tab'].isTabVisible(tabIndex)

            stat = bool(self.deviceStat.get(smartTabs[key]['statID']))
            smartTabs[key]['tab'].setTabVisible(tabIndex, stat)
            actChanged = tabStatus != stat
            tabChanged = tabChanged or actChanged

        tabIndex = self.getTabIndex(self.ui.imagingTabWidget, 'reference')
        self.ui.imagingTabWidget.setTabVisible(tabIndex, packageConfig.isReference)
        tabIndex = self.getTabIndex(self.ui.imagingTabWidget, 'AnalyseFlexure')
        self.ui.toolsTabWidget.setTabVisible(tabIndex, packageConfig.isAnalyse)

        # redraw tabs only when a change occurred. this is necessary, because
        # enable and disable does not remove tabs
        if tabChanged:
            ui = self.ui.mainTabWidget
            ui.setStyleSheet(ui.styleSheet())
            ui = self.ui.toolsTabWidget
            ui.setStyleSheet(ui.styleSheet())
        return True

    def updateWindowsStats(self):
        """
        :return: True for test purpose
        """
        for win in self.uiWindows:
            winObj = self.uiWindows[win]

            if winObj['classObj']:
                self.changeStyleDynamic(winObj['button'], 'running', True)
            else:
                self.changeStyleDynamic(winObj['button'], 'running', False)
        return True

    def setEnvironDeviceStats(self):
        """
        :return:
        """
        refracOn = self.app.mount.setting.statusRefraction == 1
        isManual = self.ui.refracManual.isChecked()
        isTabEnabled = self.ui.showTabEnviron.isChecked()
        if not refracOn or not isTabEnabled:
            self.deviceStat['refraction'] = None
            self.ui.refractionConnected.setText('Refraction')
        elif isManual:
            self.ui.refractionConnected.setText('Refrac Manu')
            self.deviceStat['refraction'] = True
        else:
            self.ui.refractionConnected.setText('Refrac Auto')
            isSource = self.deviceStat.get(self.refractionSource, False)
            self.deviceStat['refraction'] = isSource
        return True

    def updateDeviceStats(self):
        """
        :return: True for test purpose
        """
        for device, ui in self.deviceStatGui.items():
            if self.deviceStat.get(device) is None:
                self.changeStyleDynamic(ui, 'color', 'gray')
            elif self.deviceStat[device]:
                self.changeStyleDynamic(ui, 'color', 'green')
            else:
                self.changeStyleDynamic(ui, 'color', 'red')

        isMount = self.deviceStat.get('mount', False)
        self.changeStyleDynamic(self.ui.mountOn, 'running', isMount)
        self.changeStyleDynamic(self.ui.mountOff, 'running', not isMount)
        return True

    def updatePlateSolveStatus(self, text):
        """
        :param text:
        :return: true for test purpose
        """
        self.ui.plateSolveText.setText(text)
        return True

    def updateDomeStatus(self, text):
        """
        :param text:
        :return: true for test purpose
        """
        self.ui.domeText.setText(text)
        return True

    def updateCameraStatus(self, text):
        """
        :param text:
        :return: true for test purpose
        """
        self.ui.cameraText.setText(text)
        return True

    def updateControllerStatus(self):
        """
        :return: True for test purpose
        """
        gcStatus = self.gameControllerRunning
        self.ui.controller1.setEnabled(gcStatus)
        self.ui.controller2.setEnabled(gcStatus)
        self.ui.controller3.setEnabled(gcStatus)
        self.ui.controller4.setEnabled(gcStatus)
        self.ui.controller5.setEnabled(gcStatus)
        return True

    def updateThreadAndOnlineStatus(self):
        """
        :return: True for test purpose
        """
        if self.ui.isOnline.isChecked():
            mode = 'Online'
        else:
            mode = 'Offline'

        moon = self.ui.moonPhaseIllumination.text()

        f = dark_twilight_day(self.app.ephemeris, self.app.mount.obsSite.location)
        twilight = TWILIGHTS[int(f(self.app.mount.obsSite.ts.now()))]

        activeCount = self.threadPool.activeThreadCount()
        t = f'{mode} - {twilight} - Moon: {moon}% - Threads:{activeCount:2d} / 30'
        self.ui.statusOnline.setTitle(t)
        return True

    def updateTime(self):
        """
        :return: True for test purpose
        """
        self.ui.timeComputer.setText(datetime.now().strftime('%H:%M:%S'))
        tzT = time.tzname[1] if time.daylight else time.tzname[0]
        t = f'TZ: {tzT}'
        self.ui.statusTime.setTitle(t)
        return True

    def updateStatusGUI(self, obs):
        """
        :return:    True if ok for testing
        """
        if obs.statusText() is not None:
            self.ui.statusText.setText(obs.statusText())
        else:
            self.ui.statusText.setText('-')

        if self.app.mount.obsSite.status == 0:
            self.changeStyleDynamic(self.ui.tracking, 'running', True)
        else:
            self.changeStyleDynamic(self.ui.tracking, 'running', False)

        if self.app.mount.obsSite.status == 5:
            self.changeStyleDynamic(self.ui.park, 'running', True)
        else:
            self.changeStyleDynamic(self.ui.park, 'running', False)

        if self.app.mount.obsSite.status == 1:
            self.changeStyleDynamic(self.ui.stop, 'running', True)
        else:
            self.changeStyleDynamic(self.ui.stop, 'running', False)

        if self.app.mount.obsSite.status == 10 and not self.satStatus:
            self.app.playSound.emit('SatStartTracking')
            self.satStatus = True
        elif self.app.mount.obsSite.status != 10:
            self.satStatus = False

        return True

    def deleteWindowResource(self, widget=None):
        """
        :return: success
        """
        if not widget:
            return False

        for window in self.uiWindows:
            if self.uiWindows[window]['name'] != widget.objectName():
                continue
            self.uiWindows[window]['classObj'] = None

        return True

    def setColorSet(self):
        """
        :return:
        """
        Styles.colorSet = self.ui.colorSet.currentIndex()
        return True

    def refreshColorSet(self):
        """
        :return:
        """
        self.setColorSet()
        self.setStyleSheet(self.mw4Style)
        self.setupIcons()
        self.app.colorChange.emit()
        return True

    def buildWindow(self, window):
        """
        buildWindow makes new object instance from window class. both are
        stored in the uiWindows dict for usage.

        :return: true for test purpose
        """
        self.uiWindows[window]['classObj'] = self.uiWindows[window]['class'](self.app)
        self.uiWindows[window]['classObj'].destroyed.connect(self.deleteWindowResource)
        self.uiWindows[window]['classObj'].initConfig()
        self.uiWindows[window]['classObj'].showWindow()
        return True

    def toggleWindow(self):
        """
        :return: true for test purpose
        """
        for window in self.uiWindows:
            if self.uiWindows[window]['button'] != self.sender():
                continue

            if not self.uiWindows[window]['classObj']:
                self.buildWindow(window)
            else:
                self.uiWindows[window]['classObj'].close()
        return True

    def showExtendedWindows(self):
        """
        showExtendedWindows opens all extended windows depending on their
        opening status stored in the configuration dict.

        :return: true for test purpose
        """
        for window in self.uiWindows:
            if window == 'showSimulatorW':
                continue
            if not self.app.config.get(window, False):
                continue

            self.buildWindow(window)
        return True

    def waitClosedExtendedWindows(self):
        """
        waits until the window class is deleted
        :return:
        """
        waitDeleted = True
        while waitDeleted:
            for window in self.uiWindows:
                if self.uiWindows[window]['classObj']:
                    continue

                waitDeleted = False
            sleepAndEvents(100)
        return True

    def closeExtendedWindows(self):
        """
        closeExtendedWindows closes all open extended windows by calling
        close.

        :return: true for test purpose
        """
        for window in self.uiWindows:
            if not self.uiWindows[window]['classObj']:
                continue

            self.uiWindows[window]['classObj'].close()
        self.waitClosedExtendedWindows()
        return True

    @staticmethod
    def checkExtension(filePath, ext):
        """
        :param filePath:
        :param ext:
        :return:
        """
        if not filePath.endswith(ext):
            filePath += ext
        return filePath

    def switchProfile(self, config):
        """
        :param config:
        :return:
        """
        self.closeExtendedWindows()
        # self.stopDrivers()
        self.app.config = config
        topo = self.app.initConfig()
        self.app.mount.obsSite.location = topo
        self.initConfig()
        self.showExtendedWindows()
        return True

    def loadProfileGUI(self):
        """
        :return:
        """
        folder = self.app.mwGlob['configDir']
        loadFilePath, name, ext = self.openFile(
            self, 'Open config file', folder, 'Config files (*.cfg)',
            enableDir=False)
        if not name:
            return False

        config = loadProfile(configDir=self.app.mwGlob['configDir'], name=name)
        if config:
            self.ui.profile.setText(name)
            self.msg.emit(1, 'System', 'Profile', f'loaded {name}')
        else:
            self.msg.emit(2, 'System', 'Profile error',
                          f'{name}] cannot no be loaded')
            return False

        self.switchProfile(config)
        return True

    def addProfileGUI(self):
        """
        :return:
        """
        config = self.app.config
        folder = self.app.mwGlob['configDir']
        loadFilePath, name, ext = self.openFile(
            self, 'Open add-on config file', folder, 'Config files (*.cfg)',
            enableDir=False)
        if not name:
            self.ui.profileAdd.setText('-')
            return False

        self.storeConfig()
        self.app.storeConfig()
        configAdd = loadProfile(configDir=self.app.mwGlob['configDir'], name=name)
        if configAdd:
            self.ui.profileAdd.setText(name)
            profile = self.ui.profile.text()
            self.msg.emit(1, 'System', 'Profile', f'Base: {profile}')
            self.msg.emit(1, 'System', 'Profile', f'Add : {name}')
        else:
            self.ui.profileAdd.setText('-')
            self.msg.emit(2, 'System', 'Profile error',
                          f'{name}] cannot no be loaded')
            return False

        config = blendProfile(config, configAdd)
        self.switchProfile(config)
        return True

    def saveConfigAs(self):
        """
        :return:
        """
        folder = self.app.mwGlob['configDir']
        saveFilePath, name, ext = self.saveFile(
            self, 'Save config file', folder, 'Config files (*.cfg)',
            enableDir=False)
        if not name:
            return False

        self.storeConfig()
        self.app.storeConfig()
        suc = saveProfile(configDir=self.app.mwGlob['configDir'],
                          name=name,
                          config=self.app.config)
        if suc:
            self.ui.profile.setText(name)
            self.msg.emit(1, 'System', 'Profile', f'saved {name}')
            self.ui.profileAdd.setText('-')
        else:
            self.msg.emit(2, 'System', 'Profile error',
                          f'{name}] cannot no be saved')
        return True

    def saveConfig(self):
        """
        :return: nothing
        """
        self.storeConfig()
        self.app.storeConfig()
        suc = saveProfile(configDir=self.app.mwGlob['configDir'],
                          name=self.ui.profile.text(),
                          config=self.app.config)
        if suc:
            self.ui.profileAdd.setText('-')
            self.msg.emit(1, 'System', 'Profile', 'Actual profile saved')
        else:
            self.msg.emit(2, 'System', 'Profile',
                          'Actual profile cannot not be saved')
        return suc

    def remoteCommand(self, command):
        """
        remoteCommand received signals from remote class and executes them.
        :param command:
        :return: True for test purpose
        """
        if command == 'shutdown':
            self.quitSave()
            self.msg.emit(2, 'System', 'Remote', 'Shutdown MW4 remotely')
        elif command == 'shutdown mount':
            self.mountShutdown()
            self.msg.emit(2, 'System', 'Remote', 'Shutdown MW4 remotely')
        elif command == 'boot mount':
            self.mountBoot()
            self.msg.emit(2, 'System', 'Remote', 'Boot Mount remotely')
        return True

    def collectWindows(self):
        """
        :return:
        """
        for i, window in enumerate(self.uiWindows):
            if self.uiWindows[window]['classObj']:
                self.uiWindows[window]['classObj'].resize(800, 600)
                self.uiWindows[window]['classObj'].move(i * 50 + 10, i * 50 + 10)
                self.uiWindows[window]['classObj'].activateWindow()
        self.move(i * 50 + 10, i * 50 + 10)
        self.activateWindow()
        return True


import numpy as np
import matplotlib.pyplot as plt
from bg_atlasapi import BrainGlobeAtlas
from skimage.filters import gaussian

from cordmap.postprocessing.prob_map import get_bins

atlas_name = "salk_cord_10um"
atlas = BrainGlobeAtlas(atlas_name)

def generate_histogram2d(points_file, pos, smoothing=100, axis="x"):

    points = np.load(points_file)
    if axis == "z":
        atlas_resolution = atlas.resolution[1:]
        points_slice = points[np.where(points[:, 0] == pos)]
        points_slice = points_slice[:, 1:]
        bins = get_bins(atlas.annotation.shape[1:], (1, 1))
        atlas_image = atlas.annotation[pos, :, :]
    elif axis == "y":
        atlas_resolution = atlas.resolution[::2]
        points_slice = points[np.where(points[:, 1] == pos)]
        points_slice = points_slice[:, ::2]
        bins = get_bins(atlas.annotation.shape[::2], (1, 1))
        atlas_image = atlas.annotation[:, pos, :]
    elif axis == "x":
        atlas_resolution = atlas.resolution[:-1]
        points_slice = points[np.where(points[:, 2] == pos)]
        points_slice = points_slice[:, :-1]
        bins = get_bins(atlas.annotation.shape[:-1], (1, 1))
        atlas_image = atlas.annotation[:, :, pos]
    probability_map, _ = np.histogramdd(points_slice, bins=bins, density=True)

    if smoothing is not None:
        smoothing = [int(round(smoothing / res)) for res in atlas_resolution]
        probability_map = gaussian(probability_map, sigma=smoothing)

    plt.figure()
    plt.imshow(probability_map)
    [plt.plot(p[1], p[0], "o", color="w") for p in points_slice]

    plt.figure()
    plt.imshow(atlas_image)
    [plt.plot(p[1], p[0], "o", color="w") for p in points_slice]
    plt.show()


from Move import Move

class ReadModule:
    """
    Class ReadModule
    :param file_path: Stores file_path
    :type file_path: str

    :param turtle: object from Turtle class
    :type turtle: Turtle

    :param paint: object from Paint class
    :type heads: Paint

    :param x_length: width of painting background
    :type x_length: int

    :param y_length: height of painting background
    :type y_length: int

    """

    def __init__(self, file_path, turtle, paint, x_length, y_length):
        """Constructor method"""
        self.file_path = file_path
        self.turtle = turtle
        self.paint = paint
        self.x_length = x_length
        self.y_length = y_length

    def reading_file(self):
        """
        For comennds in file_path draw and move turtle.
        """
        try:
            with open(self.file_path, 'r') as file:
                leave = 0
                try:
                    for line in file:
                        if len(line.split()) == 1:
                            move = Move(line.split()[0], 0)
                            if move.how_to_move == 'opusc':
                                leave += 1
                            elif move.how_to_move == 'podnies':
                                leave -= 1
                        elif len(line.split()) == 2:
                            move = Move(line.split()[0], line.split()[1])

                            if move.how_to_move == "naprzod" and leave == 1:
                                move.straight_and_paint(self.turtle,
                                                        self.paint,
                                                        self.x_length,
                                                        self.y_length)
                            elif move.how_to_move == 'naprzod' and leave == 0:
                                move.straight_move(self.turtle,
                                                   self.x_length,
                                                   self.y_length)
                            elif move.how_to_move == "obrot":
                                move.turn_move(self.turtle)

                except UnicodeDecodeError as e:
                    print(f'{e}: niepoprawny format pliku')

            self.paint.saving_picture()
            self.paint.show_picture()

        except FileNotFoundError as e:
            print(f'{e}: nipoprawny plik wejsciowy')


import os
import tarfile
import tempfile
from operator import add

import h5py
import pandas as pd
import wget

def get_name(index, hdf5_data):
    name = hdf5_data['/digitStruct/name']
    return ''.join([chr(v[0]) for v in hdf5_data[name[index][0]].value])

def get_bbox(index, hdf5_data):
    """Retrieves the bounding box from hdf5 data for a specific index.

    Args:
        index (int): index of image.
        hdf5_data (h5py file): h5py file containing bounding box information.

    Returns:
        dictionnary: label, left, top, width and height values for the bounding box.
    """
    attrs = {}
    item = hdf5_data['digitStruct']['bbox'][index].item()
    for key in ['label', 'left', 'top', 'width', 'height']:
        attr = hdf5_data[item][key]
        values = [int(hdf5_data[attr.value[i].item()].value[0][0])
                  for i in range(len(attr))] if len(attr) > 1 else [int(attr.value[0][0])]
        attrs[key] = values
    return attrs

def img_boundingbox_data_constructor(data_folder, mode, csv_path):
    """Creates bounding boxes for all images. This will generate a csv file indicating for each image the label and bounding box coordinates
    and return the corresponding DataFrame.

    Args:
        data_folder (string): path to data directory containing digitStruct.mat file.
        mode (string): training or testing.
        csv_path (string): path to save the csv file containing the bounding boxes information.

    Returns:
        DataFrame: bounding boxes information (image, label and coordinates)
    """
    f = h5py.File(os.path.join(data_folder, "digitStruct.mat"), 'r')
    row_list = []
    num_example = f['/digitStruct/bbox'].shape[0]
    logging_interval = num_example // 10
    print("found %d number of examples for %s" % (num_example, mode))
    for j in range(num_example):
        if j % logging_interval == 0:
            print("retrieving bounding box for %s: %.2f%%" % (mode, j / num_example * 100))
        img_name = get_name(j, f)
        bbox = get_bbox(j, f)
        row_dict = {
            'image': os.path.join(mode, img_name),
            'label': bbox["label"],
            'x1': bbox["left"],
            'y1': bbox["top"],
            'x2': list(map(add, bbox["left"], bbox["width"])),
            'y2': list(map(add, bbox["top"], bbox["height"]))
        }
        row_list.append(row_dict)
    bbox_df = pd.DataFrame(row_list, columns=['image', 'label', 'x1', 'y1', 'x2', 'y2'])
    bbox_df.to_csv(csv_path, index=False)
    return bbox_df

def load_data(path=None):
    """Downloads the svhn dataset to local storage, if not already downloaded. This will generate 2 csv files (train and test), which contain all the path
        information.

    Args:
        path (str, optional): The path to store the svhn data. Defaults to None, will save at `tempfile.gettempdir()`.

    Returns:
    string: path to train csv file.
    string: path to test csv file.
    string: path to data directory.
    """
    if path is None:
        path = os.path.join(tempfile.gettempdir(), ".fe", "SVHN")
    if not os.path.exists(path):
        os.makedirs(path)
    train_csv = os.path.join(path, "train_data.csv")
    test_csv = os.path.join(path, "test_data.csv")
    train_compressed_path = os.path.join(path, "train.tar.gz")
    test_compressed_path = os.path.join(path, "test.tar.gz")
    train_folder_path = os.path.join(path, "train")
    test_folder_path = os.path.join(path, "test")
    if not (os.path.exists(train_compressed_path) and os.path.exists(test_compressed_path)):
        print("Downloading data to %s" % path)
        wget.download('http://ufldl.stanford.edu/housenumbers/train.tar.gz', path)
        wget.download("http://ufldl.stanford.edu/housenumbers/test.tar.gz", path)
    if not (os.path.exists(train_folder_path) and os.path.exists(test_folder_path)):
        print(" ")
        print("extracting data...")
        with tarfile.open(train_compressed_path) as tar:
            tar.extractall(path)
        with tarfile.open(test_compressed_path) as tar:
            tar.extractall(path)
    if not (os.path.exists(train_csv) and os.path.exists(test_csv)):
        print("constructing bounding box data...")
        img_boundingbox_data_constructor(train_folder_path, "train", train_csv)
        img_boundingbox_data_constructor(test_folder_path, "test", test_csv)
    return train_csv, test_csv, path


from django.http import HttpResponse
from django.shortcuts import render

def home(request):
    return render(request, 'home.html')

def reverse(request):
    user_text = request.GET['usertext']
    reversed_test = user_text[::-1]
    s = user_text.split()
    l = len(s)
    return render(request, 'reverse.html', {'usertext':user_text, 'reversedtext':reversed_test, 'count_words':l})


import numpy as np

# The sigmoid actiovation function
def _sigmoid(x):
    return 1 / (1 + np.exp(-x))

# The sigmoid derivative
def _sigmoid_der(x):
    y = _sigmoid(x)
    return y * (1 - y)

# The ReLU activation function
def _relu(x, leak=0):
    return np.where(x <= 0, leak * x, x)

# The ReLU derivative
def _relu_der(x, leak=0):
    return np.where(x <= 0, leak, 1)

def _identity(x):
    return x

# Compute the MSE
def _mse(y_true, y_pred):
    return np.mean((y_true - y_pred) ** 2)

# Compute the MSE derivative
def _mse_der(y_true, y_pred):
    N = y_true.shape[0]

    return 2 * (y_pred - y_true) / N

# NICE TODO: use batch normalization per layer
def _normalize(x):  # Layer Normalization
    mean = x.mean()
    std = x.std()

    return (x - mean) / (std + 10 ** -100)

# From https://medium.com/@neuralthreads/layer-normalization-applied-on-a-neural-network-f6ad51341726
def _normalize_der(x):  # Normalization derivative
    N = len(x)
    I = np.eye(N)
    mean = x.mean()
    std = x.std()

    return ((N * I - 1) / (N * std + 10 ** -100)) - (((x - mean).dot((x - mean).T)) / (N * std ** 3 + 10 ** -100))

class Layer:
    def __init_weights(self, n, n_prev, activation):

        # Initialize W and b (normalized initialization on W)
        if activation == 'sigmoid':
            u = np.sqrt(6. / (n + n_prev))
        elif activation == 'relu':
            u = 1. / np.sqrt(n)
        self.W = np.random.uniform(-u, u, (n, n_prev))
        self.b = np.zeros((n, 1))

    # Define a layer comprising n neurons, n_prev = #neurons in the previous layer, learning rate lr,
    # optimizer 'adam' (Adam gradient) or 'gd' (standard GD), beta1 and beta2 are Adam parameters
    def __init__(self, n, n_prev, activation='relu', lr=.01, optimizer='adam', beta1=.9, beta2=.999):
        self.lr = lr  # Set the learning rate
        self.beta1 = beta1
        self.beta2 = beta2
        self.beta1_t = 1.  # = pow(beta1, t) in the t-th iteration/call of compute_grad()
        self.beta2_t = 1.
        self.optimizer = optimizer

        # Set the activation function
        act_map = {'relu': _relu, 'sigmoid': _sigmoid, None: _identity}
        if activation not in act_map:
            ValueError('Activation function', activation, 'is unknown.')
        self.activate = act_map[activation]

        # Set the derivative thereof
        act_der_map = {'relu': _relu_der, 'sigmoid': _sigmoid_der, None: _identity}
        self.activate_der = act_der_map[activation]

        self.__init_weights(n, n_prev, activation)
        self.grad_W = None
        self.grad_b = None

        # Init the Adam GD parameters
        self.W_m = np.zeros((n, n_prev))
        self.W_v = np.zeros((n, n_prev))
        self.b_m = np.zeros((n, 1))
        self.b_v = np.zeros((n, 1))

    # Propagate the input data through this layer & return the result
    # Propagation of a list of samples is possible, where each sample is a column
    def __call__(self, x):
        # x = normalize(x)  # TODO: Normalization would be nice
        self.last_z = self.W @ x + self.b
        self.last_out = self.activate(self.last_z)
        y = self.last_out
        if len(y) == 1:
            return y[0]
        return y

    # Compute the gradient of the loss function w.r.t. the parameters W and b
    # Inspired by https://medium.com/@neuralthreads/backpropagation-made-super-easy-for-you-part-1-6fb4aa5a0aaf
    # ADAM GD, see e.g. p.105 of the lecture notes
    def compute_grad(self, err_grad):
        n_samples = self.last_out.shape[1]

        # Compute the gradient w.r.t. b per sample
        grad_b = err_grad * self.activate_der(self.last_z)

        # Compute the gradient w.r.t. W (averaged over all samples)
        grad_W = np.zeros(self.W.shape)
        for i in range(n_samples):
            grad_W += grad_b[:, i] @ self.last_out[:, i].T
        grad_W /= n_samples

        # Compute the error gradient to propagate
        new_err_grad = self.W.T @ grad_b

        # Compute the gradient w.r.t. b (averaged over all samples)
        grad_b = np.mean(grad_b, axis=1).reshape((-1, 1))

        # Update the Adam parameters
        self.W_m = self.beta1 * self.W_m + (1 - self.beta1) * grad_W
        self.W_v = self.beta2 * self.W_v + (1 - self.beta2) * np.square(grad_W)
        self.b_m = self.beta1 * self.b_m + (1 - self.beta1) * grad_b
        self.b_v = self.beta2 * self.b_v + (1 - self.beta2) * np.square(grad_b)

        return new_err_grad

    # Update the weights W and b using Adam
    def update_weights(self):
        if self.optimizer == 'adam':
            # Compute the relevant Adam parameters
            self.beta1_t *= self.beta1  # beta1_t = pow(beta1, t), where t denotes the t-th iteration
            self.beta2_t *= self.beta2
            W_m_hat = self.W_m / (1 - self.beta1_t)
            W_v_hat = self.W_v / (1 - self.beta2_t)
            b_m_hat = self.b_m / (1 - self.beta1_t)
            b_v_hat = self.b_v / (1 - self.beta2_t)
            eps = 1E-15

            # Update the weights W and b
            self.W -= self.lr / (np.sqrt(W_v_hat) + eps) * W_m_hat
            self.b -= self.lr / (np.sqrt(b_v_hat) + eps) * b_m_hat
        else:
            # Update the weights W and b
            self.W -= self.lr * self.W_m
            self.b -= self.lr * self.b_m


def update_scalingip(context, id, content):
    """Update an existing scaling IP.

    :param context: neutron api request context.
    :param id: id of the scaling ip
    :param content: dictionary with keys indicating fields to update.
        valid keys are those that have a value of True for 'allow_put'
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.

    :returns: Dictionary containing details for the new scaling IP.  If values
        are declared in the fields parameter, then only those keys will be
        present.
    """
    LOG.info('update_scalingip %s for tenant %s and body %s' %
             (id, context.tenant_id, content))
    requested_ports = content.get('ports', [])
    flip = _update_flip(context, id, ip_types.SCALING, requested_ports)
    return v._make_scaling_ip_dict(flip)


from discord.ext import commands

from bot import BaseBot
from core.utils import read_config

config = read_config()

class CogsOps(commands.Cog):
    def __init__(self, bot: BaseBot):
        self.bot = bot

    @commands.group(description="Cog related commands", invoke_without_command=True)
    @commands.has_role(config["perms"]["cog_ops_access_role"])
    async def cog(self, ctx: commands.Context):
        loaded_cogs = []
        unloaded_cogs = []
        for ext in self.bot.config["default"]["core_cogs"]:
            try:
                await self.bot.load_extension(f"core.{ext}")
            except commands.ExtensionAlreadyLoaded:
                loaded_cogs.append(ext)
            except commands.ExtensionNotFound:
                unloaded_cogs.append(ext)
        for ext in self.bot.config["cogs"]["custom"]:
            try:
                await self.bot.load_extension(f"cogs.custom.{ext}")
            except commands.ExtensionAlreadyLoaded:
                loaded_cogs.append(ext)
            except commands.ExtensionNotFound:
                unloaded_cogs.append(ext)
        for ext in self.bot.config["cogs"]["list"]:
            try:
                await self.bot.load_extension(f"cogs.{ext}")
            except commands.ExtensionAlreadyLoaded:
                loaded_cogs.append(ext)
            except commands.ExtensionNotFound:
                unloaded_cogs.append(ext)
        await ctx.send(
            f"```\nLoaded cogs: {', '.join(loaded_cogs)}\nUnloaded cogs: {','.join(unloaded_cogs)}```"
        )

    @cog.command()
    async def rel(self, ctx: commands.Context, ext):
        self.bot.log(
            f"Cog [{ext}] reload initiated by @{ctx.author.name}#{ctx.author.discriminator} [{ctx.author.id}]"
        )
        if ext in self.bot.config["default"]["core_cogs"]:
            msg = await ctx.send("`Reloading core cog: {}` 🛠".format(ext))
            try:
                await self.bot.reload_extension("core.{}".format(ext))
                await msg.edit(content="`Reloaded core cog: {}` 🆗".format(ext))
            except Exception as e:
                await msg.edit(content="`Failed to reload core cog: {}` 🔴".format(ext))
                raise e

        else:
            msg = await ctx.send("`Trying to reload cog: {}` 🛠".format(ext))
            try:
                await self.bot.reload_extension("cogs.{}".format(ext))
                await msg.edit(content="`Reloaded cog: {}` 🆗".format(ext))
            except Exception as e:
                await msg.edit(content="`Failed to reload cog: {}` 🔴".format(ext))
                raise e

async def setup(bot):
    await bot.add_cog(CogsOps(bot))


from rdflib import Graph, RDF, URIRef

from compare.compare_code.common import get_specific_constant, RESOURCES_LEFT_BUT_NOT_RIGHT, \
    RESOURCES_RIGHT_BUT_NOT_LEFT, BOTH
from compare.compare_code.comparison_config import ComparisonConfig

def compare_iris_in_type(
        left_ontology: Graph,
        right_ontology: Graph,
        ontology_type, config: ComparisonConfig,
        left_revision_id: str,
        right_revision_id: str) -> dict:
    left_resources = set(left_ontology.subjects(predicate=RDF.type, object=ontology_type))
    right_resources = set(right_ontology.subjects(predicate=RDF.type, object=ontology_type))
    left_iris = filter_to_iris(left_resources)
    right_iris = filter_to_iris(right_resources)

    diff_left_minus_right = list(left_iris.difference(right_iris))
    diff_right_minus_left = list(right_iris.difference(left_iris))

    common = list(left_iris.intersection(right_iris))

    left_but_not_right_key_name = \
        get_specific_constant(
            constant=RESOURCES_LEFT_BUT_NOT_RIGHT,
            left_specific=left_revision_id,
            right_specific=right_revision_id)
    right_but_not_left_key_name = \
        get_specific_constant(
            constant=RESOURCES_RIGHT_BUT_NOT_LEFT,
            left_specific=left_revision_id,
            right_specific=right_revision_id)

    if config.strict:
        if len(diff_left_minus_right) == 0 and len(diff_right_minus_left) == 0:
            return dict()

    if not config.verbose:
        diff_dict = \
            {
                'type': str(ontology_type),
                left_but_not_right_key_name: len(diff_left_minus_right),
                right_but_not_left_key_name: len(diff_right_minus_left),
            }
    else:
        diff_dict = \
            {
                'type': str(ontology_type),
                left_but_not_right_key_name: diff_left_minus_right,
                right_but_not_left_key_name: diff_right_minus_left
            }
    if config.show_common:
        if not config.verbose:
            diff_dict = diff_dict | {BOTH: len(common)}
        else:
            common = list(left_iris.intersection(right_iris))
            diff_dict = diff_dict | {BOTH: common}

    return diff_dict

def filter_to_iris(resources) -> set:
    iris = set()
    for resource in resources:
        if isinstance(resource, URIRef):
            iris.add(resource)
    return iris


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

def get_data_from_user():
    return input('input your text\n>>')

def convert(original, post_fix):
    if len(original) > 0 and original.isalpha():
        first_char = original[0]
        new_word = original[1:] + first_char + post_fix
        return new_word
    else:
        return 'invalid word'
    return

def main():

    post_fix = 'jaask'

    original = get_data_from_user()

    converted = convert(original, post_fix)
    print(converted)

if __name__ == '__main__':
    main()
    #print('이 모듈은 실행파일이 아닙니다')


import FWCore.ParameterSet.Config as cms
from Configuration.Generator.Pythia8CommonSettings_cfi import *
from Configuration.Generator.Pythia8CUEP8M1Settings_cfi import *
from GeneratorInterface.EvtGenInterface.EvtGenSetting_cff import *

generator = cms.EDFilter("Pythia8GeneratorFilter",
    pythiaPylistVerbosity = cms.untracked.int32(0),
    pythiaHepMCVerbosity = cms.untracked.bool(False),
    comEnergy = cms.double(13000.0),
    maxEventsToPrint = cms.untracked.int32(0),
    ExternalDecays = cms.PSet(
        EvtGen130 = cms.untracked.PSet(
            decay_table = cms.string('GeneratorInterface/EvtGenInterface/data/DECAY_2014_NOLONGLIFE.DEC'),
            particle_property_file = cms.FileInPath('GeneratorInterface/EvtGenInterface/data/evt_2014.pdl'),
            convertPythiaCodes = cms.untracked.bool(False),
            list_forced_decays = cms.vstring('MyB+','MyB-','MyB0','Myanti-B0','MyB_s0','Myanti-B_s0','MyLambda_b0','Myanti-Lambda_b0'),
            operates_on_particles = cms.vint32(511,521,531,5122),
            user_decay_embedded= cms.vstring(
'''
Define Hp 0.49
Define Hz 0.775
Define Hm 0.4
Define pHp 2.50
Define pHz 0.0
Define pHm -0.17

Alias      MyB0   B0
Alias      Myanti-B0   anti-B0
ChargeConj Myanti-B0   MyB0

Alias      MyB+   B+
Alias      MyB-   B-
ChargeConj MyB-   MyB+

Alias      MyB_s0   B_s0
Alias      Myanti-B_s0   anti-B_s0
ChargeConj Myanti-B_s0   MyB_s0

Alias      MyLambda_b0   Lambda_b0
Alias      Myanti-Lambda_b0   anti-Lambda_b0
ChargeConj Myanti-Lambda_b0   MyLambda_b0

Alias MyJ/psi J/psi
ChargeConj MyJ/psi MyJ/psi

Alias Mychi_c0 chi_c0
ChargeConj Mychi_c0 Mychi_c0

Alias Mychi_c1 chi_c1
ChargeConj Mychi_c1 Mychi_c1

Alias Mychi_c2 chi_c2
ChargeConj Mychi_c2 Mychi_c2

Alias Myh_c h_c
ChargeConj Myh_c Myh_c

Alias Mypsi(2S) psi(2S)
ChargeConj Mypsi(2S) Mypsi(2S)

Alias Mypsi(3770) psi(3770)
ChargeConj Mypsi(3770) Mypsi(3770)

Decay MyJ/psi
 1.0000  mu+        mu-                    PHOTOS VLL ;
Enddecay

Decay Mychi_c0
 1.0000  gamma      MyJ/psi                PHSP ;
Enddecay

Decay Mychi_c1
 1.0000  MyJ/psi    gamma                  VVP 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ;
Enddecay

Decay Mychi_c2
 1.0000  gamma      MyJ/psi                PHSP ;
Enddecay

Decay Myh_c
 1.0000  MyJ/psi    pi0                    PHSP ;
Enddecay

Decay Mypsi(2S)
 0.4762  MyJ/psi    pi+        pi-         VVPIPI ;
 0.2346  MyJ/psi    pi0        pi0         VVPIPI ;
 0.1741  mu+        mu-                    PHOTOS VLL ;
 0.0517  gamma      Mychi_c1               PHSP ;
 0.0306  MyJ/psi    eta                    PARTWAVE 0.0 0.0 1.0 0.0 0.0 0.0 ;
 0.0281  gamma      Mychi_c2               PHSP ;
 0.0028  gamma      Mychi_c0               PHSP ;
 0.0018  MyJ/psi    pi0                    PARTWAVE 0.0 0.0 1.0 0.0 0.0 0.0 ;
 0.0000  Myh_c      pi0                    PHSP ;
Enddecay

Decay Mypsi(3770)
 1.0000  MyJ/psi    pi+        pi-         PHSP ;
Enddecay

Decay MyB+
 0.1739  MyJ/psi    K_1+                 SVV_HELAMP 0.5 0.0 1.0 0.0 0.5 0.0 ;
 0.1382  MyJ/psi    K*+                  SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.1082  Mypsi(2S)  K+         pi-  pi+  PHSP ;
 0.1034  MyJ/psi    K+         pi-  pi+  PHSP;
 0.0972  MyJ/psi    K+                   SVS ;
 0.0382  Mypsi(2S)  K*+                  SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0369  Mypsi(2S)  K+                   SVS ;
 0.0338  MyJ/psi    omega      K+        PHSP;
 0.0168  Mychi_c1   K+                   SVS ;
 0.0119  Mychi_c1   K*+                  SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0104  MyJ/psi    eta        K+        PHSP;
 0.0050  MyJ/psi    phi        K+        PHSP;
 0.0048  MyJ/psi    rho+                 SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0047  MyJ/psi    pi+                  SVS ;
 0.0013  Mypsi(2S)  pi+                  SVS;
 0.0008  Mychi_c1   pi+                  SVS ;
 0.0452  MyJ/psi    K_2*+                PHSP ;
 0.0295  Mypsi(2S)  K_1+                 PHSP ;
 0.0194  Mychi_c1   K+         pi-        pi+         PHSP ;
 0.0185  Mypsi(2S)  K+         pi0         PHSP ;
 0.0185  Mypsi(2S)  K0       pi+         PHSP ;
 0.0121  MyJ/psi    K+         pi0         PHSP ;
 0.0121  MyJ/psi    K0       pi+         PHSP ;
 0.0119  MyJ/psi    K'_1+                SVV_HELAMP 0.5 0.0 1.0 0.0 0.5 0.0 ;
 0.0097  Mychi_c1   K+         pi0         PHSP ;
 0.0097  Mychi_c1   K0       pi+         PHSP ;
 0.0093  Mypsi(2S)  K+         pi0        pi0         PHSP ;
 0.0051  Mychi_c2   K+         pi-        pi+         PHSP ;
 0.0046  Mypsi(2S)  K0       pi+        pi0         PHSP ;
 0.0026  Mychi_c2   K+         pi0         PHSP ;
 0.0026  Mychi_c2   K0       pi+         PHSP ;
 0.0008  Mychi_c0   K+                     PHSP ;
 0.0007  K*+        Mychi_c0            SVS ;
 0.0005  Mychi_c0   K+         pi-        pi+         PHSP ;
 0.0005  Mychi_c2   K+                     STS ;
 0.0003  Mychi_c2   K*+                  PHSP ;
 0.0002  Mychi_c0   K+         pi0         PHSP ;
 0.0002  Mychi_c0   K0       pi+         PHSP ;
 0.0002  Mypsi(3770) K+                     SVS ;
 0.0002  Mypsi(3770) K*+                  PHSP ;
 0.0001  Mypsi(3770) K+         pi0         PHSP ;
Enddecay

CDecay MyB-

Decay MyB0
 0.1441  MyJ/psi    K*0                  SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.1408  MyJ/psi    K_10                 SVV_HELAMP 0.5 0.0 1.0 0.0 0.5 0.0 ;
 0.0943  MyJ/psi    K0                   SVS ;
 0.0867  MyJ/psi    K*+     pi-        PHSP ;
 0.0715  MyJ/psi    K*0    pi+     pi-        PHSP ;
 0.0460  Mypsi(2S)  K*0                  SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0396  Mypsi(2S)  K0                   SVS ;
 0.0336  MyJ/psi    omega      K0        PHSP ;
 0.0141  Mychi_c1   K+         pi-         PHSP ;
 0.0217  MyJ/psi    K0   pi+     pi-        PHSP ;
 0.0173  MyJ/psi    eta      K0        PHSP ;
 0.0144  Mychi_c1   K0                   SVS ;
 0.0102  MyJ/psi    phi      K0        PHSP ;
 0.0074  Mychi_c1   K*0                  SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0029  rho0       MyJ/psi              SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0021  MyJ/psi    pi+     pi-        PHSP ;
 0.0019  MyJ/psi    pi0                   SVS ;
 0.0011  MyJ/psi    eta                   SVS ;
 0.0004  Mychi_c1   pi0         PHSP ;
 0.0002  K*0        Mychi_c0          SVS ;
 0.0575  MyJ/psi    K_2*0                PHSP ;
 0.0416  Mypsi(2S)  K+         pi-         PHSP ;
 0.0326  Mypsi(2S)  K_10                   PHSP ;
 0.0271  MyJ/psi    K+         pi-         PHSP ;
 0.0133  MyJ/psi    K'_10                SVV_HELAMP 0.5 0.0 1.0 0.0 0.5 0.0 ;
 0.0109  Mychi_c1   K+         pi-        pi0         PHSP ;
 0.0104  Mypsi(2S)  K0       pi0         PHSP ;
 0.0104  Mypsi(2S)  K0       pi-        pi+         PHSP ;
 0.0104  Mypsi(2S)  K+         pi-        pi0         PHSP ;
 0.0068  MyJ/psi    K0       pi0         PHSP ;
 0.0058  Mychi_c2   K+         pi-         PHSP ;
 0.0055  Mychi_c1   K0       pi0         PHSP ;
 0.0052  Mypsi(2S)  K0       pi0        pi0         PHSP ;
 0.0040  MyJ/psi    omega                SVV_HELAMP PKHplus PKphHplus PKHzero PKphHzero PKHminus PKphHminus ;
 0.0029  Mychi_c2   K+         pi-        pi0         PHSP ;
 0.0014  Mychi_c2   K_S0                   STS ;
 0.0014  Mychi_c2   K0       pi0         PHSP ;
 0.0007  Mychi_c2   K*0                  PHSP ;
 0.0006  Mychi_c0   K+         pi-         PHSP ;
 0.0005  Mychi_c0   K_S0                   PHSP ;
 0.0003  Mychi_c0   K+         pi-        pi0         PHSP ;
 0.0002  Mychi_c0   K0       pi0         PHSP ;
 0.0002  Mypsi(3770) K_S0                   SVS ;
Enddecay

CDecay Myanti-B0

Decay MyB_s0
 0.1547  MyJ/psi     phi        PVV_CPLH 0.02 1 Hp pHp Hz pHz Hm pHm;
 0.0809  MyJ/psi    K-         K+          PHSP ;
 0.0809  MyJ/psi    K-         K+         pi0         PHSP ;
 0.0708  Mypsi(2S)     phi        PVV_CPLH 0.02 1 Hp pHp Hz pHz Hm pHm;
 0.0475  MyJ/psi    eta'                 SVS ;
 0.0435  Mychi_c1   phi                  SVV_HELAMP 1.0 0.0 1.0 0.0 1.0 0.0 ;
 0.0405  MyJ/psi    K0       K-         pi+         PHSP ;
 0.0297  MyJ/psi    eta'     pi+        pi-         PHSP ;
 0.0295  MyJ/psi    phi      pi+        pi-         PHSP ;
 0.0295  MyJ/psi    phi      pi0        pi0         PHSP ;
 0.0271  Mypsi(2S)  K-         K+         pi0         PHSP ;
 0.0271  Mypsi(2S)  K-         K+          PHSP ;
 0.0270  Mypsi(2S)  eta'                 SVS ;
 0.0247  MyJ/psi    eta                  SVS ;
 0.0232  Mypsi(2S)  eta'     pi+        pi-         PHSP ;
 0.0231  MyJ/psi    pi+        pi-         PHSP ;
 0.0213  Mychi_c1   eta'                 SVS ;
 0.0202  MyJ/psi    anti-K0  K0        PHSP ;
 0.0201  Mypsi(2S)  phi      pi+        pi-         PHSP ;
 0.0201  Mypsi(2S)  phi      pi0        pi0         PHSP ;
 0.0181  Mypsi(2S)  pi+        pi-         PHSP ;
 0.0181  Mypsi(2S)  pi0        pi0         PHSP ;
 0.0154  MyJ/psi    eta      pi+        pi-         PHSP ;
 0.0141  Mypsi(2S)  eta                  SVS ;
 0.0135  Mypsi(2S)  K0       K-         pi+         PHSP ;
 0.0123  Mychi_c1   K-         K+          PHSP ;
 0.0123  Mychi_c1   K-         K+         pi0         PHSP ;
 0.0120  Mypsi(2S)  eta      pi+        pi-         PHSP ;
 0.0095  Mychi_c1   eta                  SVS ;
 0.0075  Mychi_c2   eta'                 STS ;
 0.0067  Mypsi(2S)  anti-K0  K0        PHSP ;
 0.0046  MyJ/psi    K0                   SVS ;
 0.0040  Mychi_c2   K-         K+          PHSP ;
 0.0040  Mychi_c2   K-         K+         pi0         PHSP ;
 0.0039  Mychi_c2   eta                  STS ;
 0.0008  Myh_c      phi                  SVV_HELAMP 1.0 0.0 1.0 0.0 1.0 0.0 ;
 0.0004  Myh_c      eta'                 SVS ;
 0.0003  phi      Mychi_c0               SVS ;
 0.0002  Myh_c      K-         K+         pi0         PHSP ;
 0.0002  Myh_c      K-         K+          PHSP ;
 0.0002  Myh_c      eta                  SVS ;
 0.0002  Mychi_c0   eta'                 PHSP ;
 0.0001  Mychi_c0   eta                  PHSP ;
 0.0001  Mychi_c0   K-         K+         pi0         PHSP ;
 0.0001  Mychi_c0   K-         K+          PHSP ;
Enddecay

CDecay Myanti-B_s0

Decay MyLambda_b0
 0.168  MyJ/psi       Lambda0                  PHSP ;
 0.188  MyJ/psi       Lambda(1670)0            PHSP ;
 0.175  MyJ/psi       K-       p+              PHSP ;
 0.145  MyJ/psi       Lambda0  pi+  pi-        PHSP ;
 0.116  MyJ/psi       K*-      p+              PHSP ;
 0.096  MyJ/psi       Lambda(1520)0  pi+  pi-  PHSP ;
 0.059  Mypsi(2S)     Lambda(1520)0            PHSP ;
 0.053  Mypsi(2S)     Lambda0                  PHSP ;
Enddecay

CDecay Myanti-Lambda_b0

End
'''
        )
        ),
        parameterSets = cms.vstring('EvtGen130')
    ),
    PythiaParameters = cms.PSet(
        pythia8CommonSettingsBlock,
        pythia8CUEP8M1SettingsBlock,
        processParameters = cms.vstring(
            'HardQCD:hardbbbar = on'
        ),
        parameterSets = cms.vstring(
            'pythia8CommonSettings',
            'pythia8CUEP8M1Settings',
            'processParameters',
        )
    )
)

generator.PythiaParameters.processParameters.extend(EvtGenExtraParticles)

muminusfilter = cms.EDFilter("PythiaDauVFilter",
    MotherID = cms.untracked.int32(0),
    MinPt = cms.untracked.vdouble(3.),
    ParticleID = cms.untracked.int32(443),
    ChargeConjugation = cms.untracked.bool(False),
    MinEta = cms.untracked.vdouble(-3.),
    MaxEta = cms.untracked.vdouble(3.),
    NumberDaughters = cms.untracked.int32(1),
    DaughterIDs = cms.untracked.vint32(-13)
)

muplusfilter = cms.EDFilter("PythiaDauVFilter",
    MotherID = cms.untracked.int32(0),
    MinPt = cms.untracked.vdouble(3.),
    ParticleID = cms.untracked.int32(443),
    ChargeConjugation = cms.untracked.bool(False),
    MinEta = cms.untracked.vdouble(-3.),
    MaxEta = cms.untracked.vdouble(3.),
    NumberDaughters = cms.untracked.int32(1),
    DaughterIDs = cms.untracked.vint32(13)
)

ProductionFilterSequence = cms.Sequence(generator*muminusfilter*muplusfilter)


'''

-Medium-
*DFS*

There is an undirected tree with n nodes labeled from 0 to n - 1 and n - 1 edges.

You are given a 2D integer array edges of length n - 1 where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree. You are also given an integer array restricted which represents restricted nodes.

Return the maximum number of nodes you can reach from node 0 without visiting a restricted node.

Note that node 0 will not be a restricted node.

Example 1:

Input: n = 7, edges = [[0,1],[1,2],[3,1],[4,0],[0,5],[5,6]], restricted = [4,5]
Output: 4
Explanation: The diagram above shows the tree.
We have that [0,1,2,3] are the only nodes that can be reached from node 0 without visiting a restricted node.
Example 2:

Input: n = 7, edges = [[0,1],[0,2],[0,5],[0,4],[3,2],[6,5]], restricted = [4,2,1]
Output: 3
Explanation: The diagram above shows the tree.
We have that [0,5,6] are the only nodes that can be reached from node 0 without visiting a restricted node.

Constraints:

2 <= n <= 105
edges.length == n - 1
edges[i].length == 2
0 <= ai, bi < n
ai != bi
edges represents a valid tree.
1 <= restricted.length < n
1 <= restricted[i] < n
All the values of restricted are unique.

'''

from typing import List
from collections import defaultdict

class Solution:
    def reachableNodes(self, n: int, edges: List[List[int]], restricted: List[int]) -> int:
        graph = defaultdict(list)
        R = set(restricted)
        for u, v in edges:
            graph[u].append(v)
            graph[v].append(u)
        cnt = 0
        vis = [False]*n
        def dfs(u):
            nonlocal cnt
            cnt += 1
            vis[u] = True
            for v in graph[u]:
                if v not in R and not vis[v]:
                    dfs(v)
        dfs(0)
        return cnt

    def reachableNodes2(self, n: int, edges: List[List[int]], restricted: List[int]) -> int:
        graph = defaultdict(list)
        vis = set(restricted)
        for u, v in edges:
            graph[u].append(v)
            graph[v].append(u)
        def dfs(u):
            vis.add(u)
            for v in graph[u]:
                if v not in vis:
                    dfs(v)
        dfs(0)
        return len(vis) - len(restricted)

if __name__ == "__main__":
    print(Solution().reachableNodes(n = 7, edges = [[0,1],[1,2],[3,1],[4,0],[0,5],[5,6]], restricted = [4,5]))
    print(Solution().reachableNodes(n = 7, edges = [[0,1],[0,2],[0,5],[0,4],[3,2],[6,5]], restricted = [4,2,1]))


"""
给定一个二叉树，找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明：叶子节点是指没有子节点的节点。

示例 1：

输入：root = [3,9,20,null,null,15,7]
输出：2
示例 2：

输入：root = [2,null,3,null,4,null,5,null,6]
输出：5

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/minimum-depth-of-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
"""
# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
from collections import deque

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        #bfs也可以解决最短路径问题
        if not root:
            return 0
        ans=0
        q=deque()
        q.append(root)
        while q:
            size=len(q)
            ans+=1 #进入了下一层
            for i in range(size):
                tmp=q.popleft()
                if not tmp.left and not tmp.right:
                    return ans # 遇到叶子节点就直接返回层数
                if tmp.left:
                    q.append(tmp.left)
                if tmp.right:
                    q.append(tmp.right)
        return ans

分类/树的BFS（层次遍历）/111.二叉树的最小深度.py

111.二叉树的最小深度.py


#-*- coding = utf-8 -*-
# @Time    : 2021/3/21 12:42
# @Author  : circle
# @File    : wordcloud.py
# @Software: PyCharm
import jieba
from matplotlib import pyplot as plt
from wordcloud import WordCloud
from PIL import Image
import numpy as np
import sqlite3

conn = sqlite3.connect('../movie.db')
cur = conn.cursor()
sql = 'select instroduction from movie250'
content = cur.execute(sql)
print('打开数据库')
text = ''
for item in content:
    text = text + item[0]
cur.close()
conn.close()
#分词
cut = jieba.cut(text)
temp = ' '.join(cut)
print('cut value', temp)
img = Image.open('tree.jpg')
#将图片转化为数组
img_array = np.array(img)
#设置
wc = WordCloud(
    background_color='white',
    mask=img_array,
    font_path='msyh.ttc',
).generate_from_text(temp)
#绘制图片
fig = plt.figure(1)
plt.imshow(wc)
plt.axis('off')
# plt.show() 显示图片
plt.savefig('wordcloud.jpg')


def collect_links(self, env=None):
        """
        Return links without build files
        """
        for asset in self.assets.values():
            if asset.has_bundles():
                asset.collect_files()
        if env is None:
            env = self.config.env
        if env == static_bundle.ENV_PRODUCTION:
            self._minify(emulate=True)
        self._add_url_prefix()


from microbit import *

def lumiere(row):
    for i in range(5):
        display.set_pixel(row, i, 9)

while True:
    intensity = display.read_light_level()
    #display.scroll(intensity)
    if intensity >= 0 and intensity <= 50:
        lumiere(0)
    if intensity > 50 and intensity <= 100:
        lumiere(1)
    if intensity > 100 and intensity <= 150:
        lumiere(2)
    if intensity > 150 and intensity <= 200:
        lumiere(3)
    if intensity > 200 and intensity <= 250:
        lumiere(4)
    sleep(1000)
    display.clear()


__author__ = "Saumik"
__date__ = "11/03/2023"
__source__ = "https://3dmatch.cs.princeton.edu/"

# This script is used for extracting and registering point clouds using the
# datasets provided by the 3DMatch project (https://3dmatch.cs.princeton.edu/).
# It includes functionalities to download a .mat file from Google Drive,
# extract point clouds, and run a registration pipeline.

import sys
import os
import gdown
from RegistrationPipeline import RegistrationPipeline
from PointCloudExtractor import PointCloudExtractor

def main():
    if len(sys.argv) != 3:
        print("Usage: python main.py <action> <number of point clouds>")
        sys.exit(1)

    action = sys.argv[1]
    num = int(sys.argv[2])

    # Google Drive URL for the .mat file
    url = 'https://drive.google.com/uc?id=1ba9Styp7qjCpJlrZnvCCHtgYV1Mv255E'
    # Local directory to save the downloaded .mat file
    data_dir = 'data'
    # Ensure the data directory exists
    os.makedirs(data_dir, exist_ok=True)
    # Local file path to save the downloaded .mat file
    mat_file_path = os.path.join(data_dir, 'validation-set.mat')

    # Download the .mat file from Google Drive if it does not exist
    if not os.path.exists(mat_file_path):
        print("Downloading .mat file...")
        gdown.download(url, mat_file_path, quiet=False)
    else:
        print(".mat file already exists. Skipping download.")

    if action == "extract":
        extractor = PointCloudExtractor(mat_file_path)
        extractor.extract_point_clouds(limit=num)
    elif action == "register":
        pipeline = RegistrationPipeline(mat_file_path)
        pipeline.run(limit=num)
        pipeline.save_to_hdf5()
    else:
        print("Invalid action. Use 'extract' or 'register'.")

if __name__ == "__main__":
    main()


import requests
from bs4 import BeautifulSoup
import sqlite3

conn = sqlite3.connect('assign.db')
c = conn.cursor()

def create_table():
    c.execute('CREATE TABLE IF NOT EXISTS moviedetails (title TEXT , released_date TEXT ,duration TEXT , description TEXT , rating TEXT , url TEXT)')

def data_entry(i):
    c.execute("INSERT INTO moviedetails (title, released_date, duration, description, rating, url) VALUES (?,?,?,?,?,?)",
              (title[i],date[i],duration[i],description[i],rating[i],movies[i]))
    conn.commit()

URL = "https://www.imdb.com/chart/top?ref_=nv_mv_250"
r = requests.get(URL)

soup = BeautifulSoup(r.content, 'html5lib')

movies=[]
rating = []
description = []
duration = []
title = []
date = []

table = soup.findAll('td', attrs = {'class':'titleColumn'})

for row in table:
    movie = {}
    movie['url']=row.a['href']
    movies.append(movie)

print(movies)

for i in range(0,250):
        movies[i] = str(movies[i])
        movies[i]=(movies[i][9:-2])
        movies[i]= 'https://www.imdb.com' + movies[i]

for i in range(0,250):
    r = requests.get(movies[i])
    soup = BeautifulSoup(r.content, 'html5lib')
    table = soup.findAll('div', attrs = {'class':'ratingValue'})
    for row in table:
        rating.append(row.strong.text)

    table = soup.findAll('div', attrs = {'class':'widget_inline_blurb'})
    for row in table:
        title.append(row.a.text)

    table = soup.findAll('div', attrs = {'class':'subtext'})
    for row in table:
        duration.append(row.time.text)

    table = soup.findAll('a', attrs = {'title':'See more release dates'})
    for row in table:
        date.append(row.text)

    table = soup.findAll('div', attrs = {'class':'summary_text'})
    for row in table:
        description.append(row.text)
    print(i)
    date[i] = date[i][:-1]
    description[i]=description[i][21:-13]
    duration[i] = duration[i][25:-21]

rows = zip(title,date,duration,description,rating,movies)

create_table()
for i in range(0,250):
    data_entry(i)
c.close()
conn.close()

#with open("output.csv", "w") as f:
 #   writer = csv.writer(f)
  #  for movie in rows:
   #     writer.writerow([movie])


from collections import UserDict
from functools import wraps
import itertools
from typing import Generator, Iterable, Mapping, Union

from fiona.transform import transform_geom  # type: ignore
import shapely  # type: ignore
import shapely.ops  # type: ignore
from shapely.geometry import mapping, shape  # type: ignore
from shapely.geometry.base import BaseGeometry, BaseMultipartGeometry  # type: ignore

from .errors import ReduceError
from . import snuggs

# Patch snuggs's func_map, extending it with Python builtins, geometry
# methods and attributes, and functions exported in the shapely module
# (such as set_precision).

class FuncMapper(UserDict, Mapping):
    """Resolves functions from names in pipeline expressions."""

    def __getitem__(self, key):
        """Get a function by its name."""
        if key in self.data:
            return self.data[key]
        elif key in __builtins__ and not key.startswith("__"):
            return __builtins__[key]
        elif key in dir(shapely):
            return lambda g, *args, **kwargs: getattr(shapely, key)(g, *args, **kwargs)
        elif key in dir(shapely.ops):
            return lambda g, *args, **kwargs: getattr(shapely.ops, key)(
                g, *args, **kwargs
            )
        else:
            return (
                lambda g, *args, **kwargs: getattr(g, key)(*args, **kwargs)
                if callable(getattr(g, key))
                else getattr(g, key)
            )

def collect(geoms: Iterable) -> object:
    """Turn a sequence of geometries into a single GeometryCollection.

    Parameters
    ----------
    geoms : Iterable
        A sequence of geometry objects.

    Returns
    -------
    Geometry

    """
    return shapely.GeometryCollection(list(geoms))

def dump(geom: Union[BaseGeometry, BaseMultipartGeometry]) -> Generator:
    """Get the individual parts of a geometry object.

    If the given geometry object has a single part, e.g., is an
    instance of LineString, Point, or Polygon, this function yields a
    single result, the geometry itself.

    Parameters
    ----------
    geom : a shapely geometry object.

    Yields
    ------
    A shapely geometry object.

    """
    if hasattr(geom, "geoms"):
        parts = geom.geoms
    else:
        parts = [geom]
    for part in parts:
        yield part

def identity(obj: object) -> object:
    """Get back the given argument.

    To help in making expression lists, where the first item must be a
    callable object.

    Parameters
    ----------
    obj : objeect

    Returns
    -------
    obj

    """
    return obj

def vertex_count(obj: object) -> int:
    """Count the vertices of a GeoJSON-like geometry object.

    Parameters
    ----------
    obj: object
        A GeoJSON-like mapping or an object that provides
        __geo_interface__.

    Returns
    -------
    int

    """
    shp = shape(obj)
    if hasattr(shp, "geoms"):
        return sum(vertex_count(part) for part in shp.geoms)
    elif hasattr(shp, "exterior"):
        return vertex_count(shp.exterior) + sum(
            vertex_count(ring) for ring in shp.interiors
        )
    else:
        return len(shp.coords)

def binary_projectable_property_wrapper(func):
    """Project func's geometry args before computing a property.

    Parameters
    ----------
    func : callable
        Signature is func(geom1, geom2, *args, **kwargs)

    Returns
    -------
    callable
        Signature is func(geom1, geom2, projected=True, *args, **kwargs)

    """

    @wraps(func)
    def wrapper(geom1, geom2, *args, projected=True, **kwargs):
        if projected:
            geom1 = shape(transform_geom("OGC:CRS84", "EPSG:6933", mapping(geom1)))
            geom2 = shape(transform_geom("OGC:CRS84", "EPSG:6933", mapping(geom2)))

        return func(geom1, geom2, *args, **kwargs)

    return wrapper

def unary_projectable_property_wrapper(func):
    """Project func's geometry arg before computing a property.

    Parameters
    ----------
    func : callable
        Signature is func(geom1, *args, **kwargs)

    Returns
    -------
    callable
        Signature is func(geom1, projected=True, *args, **kwargs)

    """

    @wraps(func)
    def wrapper(geom, *args, projected=True, **kwargs):
        if projected:
            geom = shape(transform_geom("OGC:CRS84", "EPSG:6933", mapping(geom)))

        return func(geom, *args, **kwargs)

    return wrapper

def unary_projectable_constructive_wrapper(func):
    """Project func's geometry arg before constructing a new geometry.

    Parameters
    ----------
    func : callable
        Signature is func(geom1, *args, **kwargs)

    Returns
    -------
    callable
        Signature is func(geom1, projected=True, *args, **kwargs)

    """

    @wraps(func)
    def wrapper(geom, *args, projected=True, **kwargs):
        if projected:
            geom = shape(transform_geom("OGC:CRS84", "EPSG:6933", mapping(geom)))
            product = func(geom, *args, **kwargs)
            return shape(transform_geom("EPSG:6933", "OGC:CRS84", mapping(product)))
        else:
            return func(geom, *args, **kwargs)

    return wrapper

area = unary_projectable_property_wrapper(shapely.area)
buffer = unary_projectable_constructive_wrapper(shapely.buffer)
distance = binary_projectable_property_wrapper(shapely.distance)
set_precision = unary_projectable_constructive_wrapper(shapely.set_precision)
simplify = unary_projectable_constructive_wrapper(shapely.simplify)
length = unary_projectable_property_wrapper(shapely.length)

snuggs.func_map = FuncMapper(
    area=area,
    buffer=buffer,
    collect=collect,
    distance=distance,
    dump=dump,
    identity=identity,
    length=length,
    simplify=simplify,
    set_precision=set_precision,
    vertex_count=vertex_count,
    **{
        k: getattr(itertools, k)
        for k in dir(itertools)
        if not k.startswith("_") and callable(getattr(itertools, k))
    },
)

def map_feature(
    expression: str, feature: Mapping, dump_parts: bool = False
) -> Generator:
    """Map a pipeline expression to a feature.

    Yields one or more values.

    Parameters
    ----------
    expression : str
        A snuggs expression. The outermost parentheses are optional.
    feature : dict
        A Fiona feature object.
    dump_parts : bool, optional (default: False)
        If True, the parts of the feature's geometry are turned into
        new features.

    Yields
    ------
    object

    """
    if not (expression.startswith("(") and expression.endswith(")")):
        expression = f"({expression})"

    try:
        geom = shape(feature.get("geometry", None))
        if dump_parts and hasattr(geom, "geoms"):
            parts = geom.geoms
        else:
            parts = [geom]
    except (AttributeError, KeyError):
        parts = [None]

    for part in parts:
        result = snuggs.eval(expression, g=part, f=feature)
        if isinstance(result, (str, float, int, Mapping)):
            yield result
        elif isinstance(result, (BaseGeometry, BaseMultipartGeometry)):
            yield mapping(result)
        else:
            try:
                for item in result:
                    if isinstance(item, (BaseGeometry, BaseMultipartGeometry)):
                        item = mapping(item)
                    yield item
            except TypeError:
                yield result

def reduce_features(expression: str, features: Iterable[Mapping]) -> Generator:
    """Reduce a collection of features to a single value.

    The pipeline is a string that, when evaluated by snuggs, produces
    a new value. The name of the input feature collection in the
    context of the pipeline is "c".

    Parameters
    ----------
    pipeline : str
        Geometry operation pipeline such as "(unary_union c)".
    features : iterable
        A sequence of Fiona feature objects.

    Yields
    ------
    object

    Raises
    ------
    ReduceError

    """
    if not (expression.startswith("(") and expression.endswith(")")):
        expression = f"({expression})"

    collection = (shape(feat["geometry"]) for feat in features)
    result = snuggs.eval(expression, c=collection)

    if isinstance(result, (str, float, int, Mapping)):
        yield result
    elif isinstance(result, (BaseGeometry, BaseMultipartGeometry)):
        yield mapping(result)
    else:
        raise ReduceError("Expression failed to reduce to a single value.")


import xml.etree.ElementTree as et
import Levenshtein as lev
import csv

def parser_xml(curriculo):

    t = et.parse(curriculo)
    cv = t.getroot()

    return cv

def extrair_livros(cv):
    m = []
    l = []
    a = 0

    while a <= len(cv[1][2][1])-1:
        for i in cv[1][2][1][a]:
            l.append(i.attrib)
        m.append(l)
        l = []
        a += 1
    print('Foram extraidos',len(m),'livros')
    print()
    return m

def extrair_metadados(m):
    x = 0
    au = []
    pc = []
    metadados = []
    while x <= len(m)-1:
        for i in m[x]:
            try:
                tit = i['TITULO-DO-CAPITULO-DO-LIVRO']
                ano = i['ANO']
                idi = i['IDIOMA']
            except KeyError:
                try:
                    livro = i['TITULO-DO-LIVRO']
                    pg_i = i['PAGINA-INICIAL']
                    pg_f = i['PAGINA-FINAL']
                    cidade = i['CIDADE-DA-EDITORA']
                    editora = i['NOME-DA-EDITORA']
                except KeyError:
                    try:
                        au.append(i['NOME-COMPLETO-DO-AUTOR'])
                    except KeyError:
                        try:
                           pc.append(i['PALAVRA-CHAVE-1'])
                           pc.append(i['PALAVRA-CHAVE-2'])
                           pc.append(i['PALAVRA-CHAVE-3'])
                        except:
                            ignore = 0

        d = {
            'titulo' : tit,
            'ano' : ano,
            'idioma' : idi,
            'livro' : livro,
            'pag. inicial' : pg_i,
            'pag. final' : pg_f,
            'cidade' : cidade,
            'editora' : editora,
            'autores' : au,
            'assunto' : pc,
            }

        metadados.append(d)
        au = []
        pc = []

        x += 1

    return metadados

def eliminar_titulos_similares(metadados):
    repetidos = []
    for i in range(len(metadados)-1):
        for j in range(i+1, len(metadados)):
            if lev.distance(metadados[i]['titulo'], metadados[j]['titulo']) <= 5:
                repetidos.append(metadados[j])

    m = []
    print('Foram eliminados',len(repetidos),'títulos similares')
    for i in metadados:
        if i not in repetidos:
            m.append(i)

    return m

def escrever_csv(metadados):
    with open('capitulo_livros.csv', 'w', newline='', encoding='utf-8') as f:
        n = ['Autores',
             'Título',
             'Livro',
             'Idioma',
             'Cidade',
             'Editora',
             'Ano',
             'Pag. Inicial',
             'Pag. Final',
             'Assunto']
        e = csv.DictWriter(f, fieldnames=n)

        e.writeheader()
        c = 0
        while c <= len(metadados)-1:
            e.writerow({'Autores' : metadados[c]['autores'],
                        'Título' : metadados[c]['titulo'],
                        'livro' : metadados[c]['livro'],
                        'Idioma' : metadados[c]['idioma'],
                        'Cidade' : metadados[c]['cidade'],
                        'Editora' : metadados[c]['editora'],
                        'Ano' : metadados[c]['ano'],
                        'Pag. Inicial' : metadados[c]['pag. inicial'],
                        'Pag. Final' : metadados[c]['pag. final'],
                        'Assunto' : metadados[c]['assunto']})
            c += 1


from numpy import *
import matplotlib.pyplot as plt
from Tkinter import *

def loadDataSet(fileName):
    dataMat = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = list(map(float, curLine)) #转化为float类型
        dataMat.append(fltLine)
    return dataMat

def plotDataSet(fileName):
    dataMat = loadDataSet(fileName)
    print(shape(dataMat))
    dataMat = array(dataMat)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(dataMat[:, 0], dataMat[:, 1], s = 20, c = 'b')
    plt.title('DataSet')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.show()

'''
函数说明:根据特征切分数据集合
    Parameters:
        dataSet - 数据集合
        feature - 带切分的特征
        value - 该特征的值
    Returns:
        mat0 - 切分的数据集合0
        mat1 - 切分的数据集合1
'''
def binSplitDataSet(dataSet, feature, value):
    mat0 = dataSet[nonzero(dataSet[:, feature] > value)[0], :]
    mat1 = dataSet[nonzero(dataSet[:, feature] <= value)[0], :]
    return mat0, mat1

'''
函数说明:生成叶结点
    Parameters:
        dataSet - 数据集合
    Returns:
        目标变量的均值
'''
def regLeaf(dataSet):
    return mean(dataSet[:, -1])

'''
函数说明:误差估计函数
    Parameters:
        dataSet - 数据集合
    Returns:
        目标变量的总方差
'''
def regErr(dataSet):
    # 均方差 * 样本个数 = 总方差
    return var(dataSet[:, -1] * shape(dataSet)[0])

'''
函数说明:找到数据的最佳二元切分方式函数
    Parameters:
        dataSet - 数据集合
        leafType - 生成叶结点
        regErr - 误差估计函数
        ops - 用户定义的参数构成的元组
    Returns:
        bestIndex - 最佳切分特征
        bestValue - 最佳特征值
'''
def chooseBestSplit(dataSet, leafType = regLeaf, errType = regErr, ops = (1,4)):
    tolS = ops[0]   # tolS允许的误差下降值
    tolN = ops[1]   # tolN切分的最少样本数
    if (len(set(dataSet[:, -1].T.tolist()[0])) == 1):
        # 如果当前所有值相等,则退出。(根据set的特性)
        return None, leafType(dataSet)
    m, n =shape(dataSet)
    S = errType(dataSet)    #默认最后一个特征为最佳切分特征,计算其误差估计
    bestS = float('inf')    #最佳误差
    bestIndex = 0           #最佳特征切分的索引值
    bestValue = 0           #最佳特征值
    for featIndex in range(n - 1):  #遍历所有特征列
        for splitVal in set(dataSet[:, featIndex].T.A.tolist()[0]): #遍历所有特征值
            mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)  #根据特征和特征值切分数据集
            if (shape(mat0)[0] < tolN or shape(mat1)[0] < tolN):    #如果数据少于tolN,则退出
                continue
            newS = errType(mat0) + errType(mat1)     #计算误差估计
            if newS < bestS:    #如果误差估计更小,则更新特征索引值和特征值
                bestIndex = featIndex
                bestValue = splitVal
                bestS = newS
    if ((S - bestS) < tolS):    #如果误差减少不大则退出
        return None, leafType(dataSet)
    mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue) #根据最佳的切分特征和特征值切分数据集合
    if (shape(mat0)[0] < tolN or shape(mat1)[0] < tolN):    #如果切分出的数据集很小则退出
        return None, leafType(dataSet)
    return bestIndex, bestValue #返回最佳切分特征和特征值

'''
函数说明:树构建函数
    Parameters:
        dataSet - 数据集合
        leafType - 建立叶结点的函数
        errType - 误差计算函数
        ops - 包含树构建所有其他参数的元组
    Returns:
        retTree - 构建的回归树
'''
def createTree(dataSet, leafType = regLeaf, errType = regErr, ops = (1, 4)):
    # 选择最佳切分特征和特征值
    feat, val = chooseBestSplit(dataSet, leafType, errType, ops)
    if feat == None:    #r如果没有特征,则返回特征值
        return val
    retTree ={} #回归树
    retTree['spInd'] = feat
    retTree['spVal'] = val
    lSet, rSet = binSplitDataSet(dataSet, feat, val)    #分成左数据集和右数据集
    # 创建左子树和右子树
    retTree['left'] = createTree(lSet, leafType, errType, ops)
    retTree['right'] = createTree(rSet, leafType, errType, ops)
    return retTree

# fileName = 'ex2.txt'
# plotDataSet(fileName)

def isTree(obj):    #判断测试输入变量是否是一棵树
    import types
    return (type(obj).__name__ == 'dict')

def getMean(tree):  # 如果找到两个leaf，则对树进行塌陷处理(即返回树平均值)
    if (isTree(tree['left'])):
        tree['left'] = getMean(tree['left'])
    if (isTree(tree['right'])):
        tree['right'] = getMean(tree['right'])
    return (tree['left'] + tree['right']) / 2.0

def prune(tree, testData): # 后剪枝
    if (shape(testData)[0] == 0):   #如果测试集为空,则对树进行塌陷处理
        return getMean(tree)
    if (isTree(tree['left']) or isTree(tree['right'])): #如果有左子树或者右子树,则切分数据集
        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])
    if (isTree(tree['left'])):  #处理左子树(剪枝)
        tree['left'] = prune(tree['left'], lSet)
    if (isTree(tree['right'])): #处理右子树(剪枝)
        tree['right'] = prune(tree['right'], rSet)
    if not isTree(tree['left']) and not isTree(tree['right']):  #如果当前结点的左右结点为叶结点
        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])
        # 计算没有合并的误差
        errorNoMerge = sum((lSet[:, -1] - tree['left']) ** 2) + sum((rSet[:, -1] - tree['right']) ** 2)
        # 计算合并的均值
        treeMean = (tree['left'] + tree['right']) / 2.0
        # 计算合并的误差
        errorMerge = sum((testData[:, -1] - treeMean) ** 2)
        # 如果合并的误差小于没有合并的误差,则合并
        if errorMerge < errorNoMerge:
            return treeMean
        else:
            return tree
    else:
        return tree


# def twoSum(arr, target):
#     for i in range(len(arr)):
#         for j in range(len(arr)):
#             if arr[i] + arr[j] == target:
#                 return [i+1, j+1]

# def twoSum(arr, target):
#     required = {}
#     for i in range(len(arr)):
#         if target-arr[i] in required:
#             return [required[target-arr[i]]+1, i+1]
#         else:
#             required[arr[i]] = i

def twoSum(arr,target):
    left= 0
    right = len(arr)-1
    while left <right:
        x = target-arr[left]

        if arr[right] == target :
            break
        elif numbers[right]<x:
            left+=1
        else:
            right-=1
    return [left+1,right+1]

numbers = [0, 0, 1, 2]
target = 0

print(twoSum(numbers, target))


def start(self):
        """
        Starts HDLC controller's threads.
        """

        self.receiver = self.Receiver(
            self.read,
            self.write,
            self.send_lock,
            self.senders,
            self.frames_received,
            callback=self.receive_callback,
            fcs_nack=self.fcs_nack,
        )

        self.receiver.start()