'''
4D Map Viewer Module
'''

import matplotlib
matplotlib.use('qt5Agg')
from matplotlib.backends.backend_qt5agg import (FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NTBar)
from matplotlib.figure import Figure
from matplotlib.gridspec import GridSpec
from matplotlib.ticker import NullFormatter
from matplotlib.lines import Line2D
from matplotlib import cm
from matplotlib.colors import ListedColormap
from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QVBoxLayout, QGroupBox, QLabel, QDoubleSpinBox, QSpinBox, QSlider,
QSizePolicy, QStyleFactory, QFrame, QPushButton, QComboBox, QCheckBox, QMenu)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QIcon, QCursor
from Data import Spectrum
from Viewer.Selector import Selector
from Viewer.colormap import CustomComboBox
import glob, os, copy
import numpy as np

class fourDmap(QWidget):
    def __init__(self, viewer):
        super(fourDmap, self).__init__()
        self.data = Spectrum()
        self.viewer = viewer
        self.spec_aspect = "auto"
        self.map_aspect = "auto"

        #init view
        self.fig = Figure(figsize=(3, 3), dpi=150)
        gs = GridSpec(3, 6, figure=self.fig)
        self.ax_Spec = self.fig.add_subplot(gs[1:3, 1:3])
        self.ax_XDC = self.fig.add_subplot(gs[0, 1:3])
        self.ax_YDC = self.fig.add_subplot(gs[1:3, 0])
        self.ax_Speccmap = self.fig.add_subplot(gs[0, 0])
        self.ax_Map = self.fig.add_subplot(gs[1:3, 3:5])
        self.ax_ZDC = self.fig.add_subplot(gs[0, 3:5])
        self.ax_TDC = self.fig.add_subplot(gs[1:3, 5])
        self.ax_Mapcmap = self.fig.add_subplot(gs[0, 5])
        self.fig.subplots_adjust(top=0.96, bottom=0.08, left=0.1, right=0.9, wspace=0.15, hspace=0.15)
        self.ax_Spec.tick_params(direction='inout', labelsize=8.5, labelleft=False)
        self.ax_XDC.tick_params(axis='x', labelsize=8.5, labelbottom=False)
        self.ax_XDC.tick_params(axis='y', labelsize=8.5, left=False, labelleft=False)
        self.ax_YDC.tick_params(axis='x', labelsize=8.5, bottom=False, labelbottom=False)
        self.ax_YDC.tick_params(axis='y', labelsize=8.5)
        self.ax_Map.tick_params(direction='inout', labelsize=8.5, labelleft=False)
        self.ax_ZDC.tick_params(axis='x', labelsize=8.5, labelbottom=False)
        self.ax_ZDC.tick_params(axis='y', labelsize=8.5, left=False, labelleft=False)
        self.ax_TDC.tick_params(axis='x', labelsize=8.5, bottom=False, labelbottom=False)
        self.ax_TDC.tick_params(axis='y', labelsize=8.5, left=False, labelleft=False, right=True, labelright=True)
        self.ax_YDC.invert_xaxis()
        self.setTickLabelFont(self.ax_Spec, "Comic Sans MS")
        self.setTickLabelFont(self.ax_XDC, "Comic Sans MS")
        self.setTickLabelFont(self.ax_YDC, "Comic Sans MS")
        self.setTickLabelFont(self.ax_Map, "Comic Sans MS")
        self.setTickLabelFont(self.ax_ZDC, "Comic Sans MS")
        self.setTickLabelFont(self.ax_TDC, "Comic Sans MS")
        x0, y0, width, height = self.ax_Speccmap.get_position().bounds
        nheight = height*0.2
        ny0 = y0+height*0.5*(1-0.2)
        self.ax_Speccmap.set_position([x0, ny0, width, nheight])
        self.ax_Speccmap.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)
        self.ax_Speccmap.set_title("CMap", {'fontsize': 8}, fontname="Comic Sans Ms")
        x0, y0, width, height = self.ax_Mapcmap.get_position().bounds
        nheight = height*0.2
        ny0 = y0+height*0.5*(1-0.2)
        self.ax_Mapcmap.set_position([x0, ny0, width, nheight])
        self.ax_Mapcmap.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)
        self.ax_Mapcmap.set_title("CMap", {'fontsize': 8}, fontname="Comic Sans Ms")
        self.gradient = np.vstack((np.linspace(0, 1, 256), np.linspace(0, 1, 256)))
        self.XDCLine = Line2D(np.array([0]), np.array([0]), color="blue", linewidth=1, animated=True, solid_joinstyle="round")
        self.YDCLine = Line2D(np.array([0]), np.array([0]), color="blue", linewidth=1, animated=True, solid_joinstyle="round")
        self.ZDCLine = Line2D(np.array([0]), np.array([0]), color="red", linewidth=1, animated=True, solid_joinstyle="round")
        self.TDCLine = Line2D(np.array([0]), np.array([0]), color="red", linewidth=1, animated=True, solid_joinstyle="round")
        self.ax_XDC.add_line(self.XDCLine)
        self.ax_YDC.add_line(self.YDCLine)
        self.ax_ZDC.add_line(self.ZDCLine)
        self.ax_TDC.add_line(self.TDCLine)

        # canvas
        self.canvas = FigureCanvas(self.fig)
        self.fig.patch.set_facecolor("None")
        self.canvas.setStyleSheet("background-color:transparent;")
        self.canvas.setFocusPolicy(Qt.ClickFocus)
        self.GetBbox()

        #cursor
        self.SpecXline1 = self.ax_Spec.axhline(self.ax_Spec.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.SpecYline1 = self.ax_Spec.axvline(self.ax_Spec.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.SpecXline2 = self.ax_Spec.axhline(self.ax_Spec.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.SpecYline2 = self.ax_Spec.axvline(self.ax_Spec.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.MapXline1 = self.ax_Map.axhline(self.ax_Map.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.MapYline1 = self.ax_Map.axvline(self.ax_Map.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.MapXline2 = self.ax_Map.axhline(self.ax_Map.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.MapYline2 = self.ax_Map.axvline(self.ax_Map.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.XDCCursor = self.ax_XDC.axvline(self.ax_XDC.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.YDCCursor = self.ax_YDC.axhline(self.ax_YDC.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.ZDCCursor = self.ax_ZDC.axvline(self.ax_ZDC.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)
        self.TDCCursor = self.ax_TDC.axhline(self.ax_TDC.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75)

        #selector
        self.selector_Spec = Selector(self.ax_Spec, self.canvas)
        self.selector_Map = Selector(self.ax_Map, self.canvas)
        self.cid_keypress = self.canvas.mpl_connect('key_press_event', self.OnKeyPress)
        self.cid_press = self.canvas.mpl_connect('button_press_event', self.OnPress)
        self.cid_release = self.canvas.mpl_connect('button_release_event', self.OnRelease)

        #contextMenu
        self.contextMenu = QMenu(self)
        self.CropAction = self.contextMenu.addAction("Crop")
        self.CropAction.setIcon(QIcon("./image/crop.ico"))
        #self.CropAction.triggered.connect(self.crop)
        self.RestoreAction = self.contextMenu.addAction("Restore")
        self.RestoreAction.setIcon(QIcon("./image/restore.ico"))
        #self.RestoreAction.triggered.connect(self.viewer.Win.DataProcessor.tab_single.RestoreData)
        self.SelectMenu = self.contextMenu.addMenu("Select")
        self.SelectMenu.setIcon(QIcon("./image/select.ico"))
        self.SelectX = self.SelectMenu.addAction("X Range")
        #self.SelectX.triggered.connect(self.setSelectionRange)
        self.SelectY = self.SelectMenu.addAction("Y Range")
        #self.SelectY.triggered.connect(self.setSelectionRange)
        self.SelectXY = self.SelectMenu.addAction("XY Area")
        #self.SelectXY.triggered.connect(self.setSelectionRange)
        self.SelectZ = self.SelectMenu.addAction("Z Range")
        #self.SelectZ.triggered.connect(self.setSelectionRange)
        self.SelectT = self.SelectMenu.addAction("T Range")
        #self.SelectT.triggered.connect(self.setSelectionRange)
        self.SelectZT = self.SelectMenu.addAction("ZT Area")
        #self.SelectZT.triggered.connect(self.setSelectionRange)
        self.outputMenu = self.contextMenu.addMenu("Output")
        self.outputMenu.setIcon(QIcon("./image/output.ico"))
        self.Spec_action = self.outputMenu.addAction("Spectrum")
        #self.Spec_action.triggered.connect(self.outputData)
        self.Map_action = self.outputMenu.addAction("Map")
        #self.Map_action.triggered.connect(self.outputData)
        self.XDC_action = self.outputMenu.addAction("XDC")
        self.YDC_action = self.outputMenu.addAction("YDC")
        self.ZDC_action = self.outputMenu.addAction("ZDC")
        self.TDC_action = self.outputMenu.addAction("TDC")

        #init Tool
        self.toolPanel = QGroupBox("Coordinate System")
        self.toolPanel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.toolPanel.setCheckable(True)
        self.toolPanel.setChecked(False)
        self.toolPanel.setStyle(QStyleFactory.create('Fusion'))
        self.toolPanel.toggled.connect(self.begincursor)
        self.X = QDoubleSpinBox()
        self.X.setFixedWidth(85)
        self.X.setDecimals(6)
        self.X.setRange(-1, 1)
        self.X.setSingleStep(0.01)
        self.X.setKeyboardTracking(False)
        self.X.setStyle(QStyleFactory.create('Fusion'))
        self.X.setValue(-1)
        self.X.valueChanged.connect(self.setValueFromSpinBox)
        self.XLabel = QLabel("X:")
        self.XLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.Y = QDoubleSpinBox()
        self.Y.setFixedWidth(85)
        self.Y.setDecimals(6)
        self.Y.setRange(-1, 1)
        self.Y.setSingleStep(0.01)
        self.Y.setKeyboardTracking(False)
        self.Y.setStyle(QStyleFactory.create('Fusion'))
        self.Y.setValue(-1)
        self.Y.valueChanged.connect(self.setValueFromSpinBox)
        self.YLabel = QLabel("Y:")
        self.YLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.Z = QDoubleSpinBox()
        self.Z.setFixedWidth(85)
        self.Z.setDecimals(6)
        self.Z.setRange(-1, 1)
        self.Z.setSingleStep(0.01)
        self.Z.setKeyboardTracking(False)
        self.Z.setStyle(QStyleFactory.create('Fusion'))
        self.Z.setValue(-1)
        self.Z.valueChanged.connect(self.setValueFromSpinBox)
        self.ZLabel = QLabel("Z:")
        self.ZLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.T = QDoubleSpinBox()
        self.T.setFixedWidth(85)
        self.T.setDecimals(6)
        self.T.setRange(-1, 1)
        self.T.setSingleStep(0.01)
        self.T.setKeyboardTracking(False)
        self.T.setStyle(QStyleFactory.create('Fusion'))
        self.T.setValue(-1)
        self.T.valueChanged.connect(self.setValueFromSpinBox)
        self.TLabel = QLabel("T:")
        self.TLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        font = QFont()
        font.setPointSize(12)
        font.setBold(True)
        self.IntLabel = QLabel("Count:")
        self.IntLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.Int = QLabel("0")
        self.Int.setFont(font)
        self.Int.setMinimumWidth(100)
        self.Int.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.Int.setStyleSheet("QLabel {background-color: white;}")
        self.Int.setFrameStyle(QFrame.Panel)
        self.XSlider = QSlider(Qt.Horizontal)
        self.XSlider.setRange(0, 10000)
        self.XSlider.setStyle(QStyleFactory.create('Fusion'))
        self.XSlider.sliderMoved.connect(self.setValueFromSlider)
        self.XSLabel = QLabel("X:")
        self.YSlider = QSlider(Qt.Horizontal)
        self.YSlider.setRange(0, 10000)
        self.YSlider.setStyle(QStyleFactory.create('Fusion'))
        self.YSlider.sliderMoved.connect(self.setValueFromSlider)
        self.YSLabel = QLabel("Y:")
        self.ZSlider = QSlider(Qt.Horizontal)
        self.ZSlider.setRange(0, 10000)
        self.ZSlider.setStyle(QStyleFactory.create('Fusion'))
        self.ZSlider.sliderMoved.connect(self.setValueFromSlider)
        self.ZSLabel = QLabel("Z:")
        self.TSlider = QSlider(Qt.Horizontal)
        self.TSlider.setRange(0, 10000)
        self.TSlider.setStyle(QStyleFactory.create('Fusion'))
        self.TSlider.sliderMoved.connect(self.setValueFromSlider)
        self.TSLabel = QLabel("T:")
        self.XSlice = QSpinBox()
        self.XSlice.setRange(1, 10000)
        self.XSlice.setSingleStep(2)
        self.XSlice.setFixedWidth(50)
        self.XSlice.setKeyboardTracking(False)
        self.XSlice.setStyle(QStyleFactory.create('Fusion'))
        self.XSlice.valueChanged.connect(self.setSlice)
        self.XSliceLabel = QLabel("Slice:")
        self.YSlice = QSpinBox()
        self.YSlice.setRange(1, 10000)
        self.YSlice.setSingleStep(2)
        self.YSlice.setFixedWidth(50)
        self.YSlice.setKeyboardTracking(False)
        self.YSlice.setStyle(QStyleFactory.create('Fusion'))
        self.YSlice.valueChanged.connect(self.setSlice)
        self.YSliceLabel = QLabel("Slice:")
        self.ZSlice = QSpinBox()
        self.ZSlice.setRange(1, 10000)
        self.ZSlice.setSingleStep(2)
        self.ZSlice.setFixedWidth(50)
        self.ZSlice.setKeyboardTracking(False)
        self.ZSlice.setStyle(QStyleFactory.create('Fusion'))
        self.ZSlice.valueChanged.connect(self.setSlice)
        self.ZSliceLabel = QLabel("Slice:")
        self.TSlice = QSpinBox()
        self.TSlice.setRange(1, 10000)
        self.TSlice.setSingleStep(2)
        self.TSlice.setFixedWidth(50)
        self.TSlice.setKeyboardTracking(False)
        self.TSlice.setStyle(QStyleFactory.create('Fusion'))
        self.TSlice.valueChanged.connect(self.setSlice)
        self.TSliceLabel = QLabel("Slice:")
        hbox_tool = QHBoxLayout()
        hbox_tool.addStretch(2)
        hbox_tool.addWidget(self.XLabel)
        hbox_tool.addWidget(self.X)
        hbox_tool.addStretch(1)
        hbox_tool.addWidget(self.YLabel)
        hbox_tool.addWidget(self.Y)
        hbox_tool.addStretch(1)
        hbox_tool.addWidget(self.ZLabel)
        hbox_tool.addWidget(self.Z)
        hbox_tool.addStretch(1)
        hbox_tool.addWidget(self.TLabel)
        hbox_tool.addWidget(self.T)
        hbox_tool.addStretch(1)
        hbox_tool.addWidget(self.IntLabel)
        hbox_tool.addWidget(self.Int)
        hbox_tool.addStretch(2)
        hbox2_tool = QHBoxLayout()
        hbox2_tool.addWidget(self.XSLabel, 0)
        hbox2_tool.addWidget(self.XSlider, 1)
        hbox2_tool.addWidget(self.XSliceLabel, 0)
        hbox2_tool.addWidget(self.XSlice, 0)
        hbox2_tool.addWidget(self.ZSLabel, 0)
        hbox2_tool.addWidget(self.ZSlider, 1)
        hbox2_tool.addWidget(self.ZSliceLabel, 0)
        hbox2_tool.addWidget(self.ZSlice, 0)
        hbox3_tool = QHBoxLayout()
        hbox3_tool.addWidget(self.YSLabel, 0)
        hbox3_tool.addWidget(self.YSlider, 1)
        hbox3_tool.addWidget(self.YSliceLabel, 0)
        hbox3_tool.addWidget(self.YSlice, 0)
        hbox3_tool.addWidget(self.TSLabel, 0)
        hbox3_tool.addWidget(self.TSlider, 1)
        hbox3_tool.addWidget(self.TSliceLabel, 0)
        hbox3_tool.addWidget(self.TSlice, 0)
        vbox_tool = QVBoxLayout()
        vbox_tool.addLayout(hbox_tool)
        vbox_tool.addLayout(hbox2_tool)
        vbox_tool.addLayout(hbox3_tool)
        self.toolPanel.setLayout(vbox_tool)

        #color scale
        self.colorPanel = QGroupBox("Color Scale")
        self.colorPanel.setFixedHeight(100)
        self.colorPanel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.Speccmapmenu = CustomComboBox()
        self.Speccmapmenu.setFixedWidth(120)
        self.Speccmapmenu.setStyle(QStyleFactory.create('Fusion'))
        self.Speccmapmenu.setCurrentText("twilight")
        self.Speccmapmenu.currentIndexChanged.connect(self.changeSpeccmapbyindex)
        self.revSpeccmap = QCheckBox("R")
        self.revSpeccmap.stateChanged.connect(self.reverseSpeccmap)
        self.SpecGammaLabel = QLabel("Spec Gamma:")
        self.SpecGammaLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.SpecGamma = QDoubleSpinBox()
        self.SpecGamma.setFixedWidth(100)
        self.SpecGamma.setDecimals(3)
        self.SpecGamma.setRange(0.05, 20)
        self.SpecGamma.setSingleStep(0.01)
        self.SpecGamma.setValue(1)
        self.SpecGamma.setKeyboardTracking(False)
        self.SpecGamma.valueChanged.connect(self.setGammaFromSpecSpinBox)
        self.SpecGamma.setStyle(QStyleFactory.create('Fusion'))
        self.SpecGSlider = QSlider(Qt.Horizontal)
        self.SpecGSlider.setRange(1000000*np.log(0.05), 1000000*np.log(20))
        self.SpecGSlider.setValue(0)
        self.SpecGSlider.sliderMoved.connect(self.setGammaFromSpecSlider)
        self.SpecGSlider.setStyle(QStyleFactory.create('Fusion'))
        hbox_Speccmap = QHBoxLayout()
        hbox_Speccmap.addWidget(self.Speccmapmenu)
        hbox_Speccmap.addWidget(self.SpecGammaLabel)
        hbox_Speccmap.addWidget(self.SpecGamma)
        hbox_Speccmap.addWidget(self.SpecGSlider)
        hbox_Speccmap.addWidget(self.revSpeccmap)
        self.Mapcmapmenu = CustomComboBox()
        self.Mapcmapmenu.setFixedWidth(120)
        self.Mapcmapmenu.setStyle(QStyleFactory.create('Fusion'))
        self.Mapcmapmenu.setCurrentText("twilight")
        self.Mapcmapmenu.currentIndexChanged.connect(self.changeMapcmapbyindex)
        self.revMapcmap = QCheckBox("R")
        self.revMapcmap.stateChanged.connect(self.reverseMapcmap)
        self.MapGammaLabel = QLabel("Map  Gamma:")
        self.MapGammaLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.MapGamma = QDoubleSpinBox()
        self.MapGamma.setFixedWidth(100)
        self.MapGamma.setDecimals(3)
        self.MapGamma.setRange(0.05, 20)
        self.MapGamma.setSingleStep(0.01)
        self.MapGamma.setValue(1)
        self.MapGamma.setKeyboardTracking(False)
        self.MapGamma.valueChanged.connect(self.setGammaFromMapSpinBox)
        self.MapGamma.setStyle(QStyleFactory.create('Fusion'))
        self.MapGSlider = QSlider(Qt.Horizontal)
        self.MapGSlider.setRange(1000000*np.log(0.05), 1000000*np.log(20))
        self.MapGSlider.setValue(0)
        self.MapGSlider.sliderMoved.connect(self.setGammaFromMapSlider)
        self.MapGSlider.setStyle(QStyleFactory.create('Fusion'))
        hbox_Mapcmap = QHBoxLayout()
        hbox_Mapcmap.addWidget(self.Mapcmapmenu)
        hbox_Mapcmap.addWidget(self.MapGammaLabel)
        hbox_Mapcmap.addWidget(self.MapGamma)
        hbox_Mapcmap.addWidget(self.MapGSlider)
        hbox_Mapcmap.addWidget(self.revMapcmap)
        vbox_colorPanel = QVBoxLayout()
        vbox_colorPanel.addLayout(hbox_Speccmap)
        vbox_colorPanel.addLayout(hbox_Mapcmap)
        self.colorPanel.setLayout(vbox_colorPanel)
        self.colorPanel.setEnabled(False)

        #Layout
        box = QVBoxLayout()
        box.addWidget(self.toolPanel, 0)
        box.addWidget(self.canvas, 1)
        box.addWidget(self.colorPanel, 0)
        self.setLayout(box)

    def loaddata(self, data):
        self.canvas.draw()
        self.GetWhiteBackground()
        #self.selector.set_visible(False)
        self.data = data
        self.Spec = data.data[:,:,0,0]
        self.Map = data.data[0,0,:,:]
        self.XDC = data.data[:,0,0,0]
        self.YDC = data.data[0,:,0,0]
        self.ZDC = data.data[0,0,:,0]
        self.TDC = data.data[0,0,0,:]
        self.X.disconnect()
        self.Y.disconnect()
        self.Z.disconnect()
        self.T.disconnect()
        self.X.setRange(data.xmin, data.xmax)
        self.X.setSingleStep(data.xstep)
        self.Y.setRange(data.ymin, data.ymax)
        self.Y.setSingleStep(data.ystep)
        self.Z.setRange(data.zmin, data.zmax)
        self.Z.setSingleStep(data.zstep)
        self.T.setRange(data.tmin, data.tmax)
        self.T.setSingleStep(data.tstep)
        self.X.valueChanged.connect(self.setValueFromSpinBox)
        self.Y.valueChanged.connect(self.setValueFromSpinBox)
        self.Z.valueChanged.connect(self.setValueFromSpinBox)
        self.T.valueChanged.connect(self.setValueFromSpinBox)
        self.XSlice.setRange(1, self.data.dimension[0])
        self.YSlice.setRange(1, self.data.dimension[1])
        self.ZSlice.setRange(1, self.data.dimension[2])
        self.TSlice.setRange(1, self.data.dimension[3])
        self.initialCoordinate()
        self.updatecolorscale(self.getcurrentcmap('Spec'), 'Spec')
        self.updatecolorscale(self.getcurrentcmap('Map'), 'Map')
        self.updateAxesPosition(True)
        self.colorPanel.setEnabled(True)

    def setTickLabelFont(self, ax, font):
        for tick in ax.get_xticklabels():
            tick.set_fontname(font)
        for tick in ax.get_yticklabels():
            tick.set_fontname(font)

    def initialCoordinate(self):
        newX = 0
        if self.data.xmin*self.data.xmax < 0:
            newX = 0
        else:
            newX = (self.data.xmin+self.data.xmax)/2
        if round(newX, 6) == self.X.value():
            self.X.valueChanged.emit(newX)
        else:
            self.X.setValue(newX)
        newY = 0
        if self.data.ymin*self.data.ymax < 0:
            newY = 0
        else:
            newY = (self.data.ymin+self.data.ymax)/2
        if round(newY, 6) == self.Y.value():
            self.Y.valueChanged.emit(newY)
        else:
            self.Y.setValue(newY)
        newZ = 0
        if self.data.zmin*self.data.zmax < 0:
            newZ = 0
        else:
            newZ = (self.data.zmin+self.data.zmax)/2
        if round(newZ, 6) == self.Z.value():
            self.Z.valueChanged.emit(newZ)
        else:
            self.Z.setValue(newZ)
        newT = 0
        if self.data.tmin*self.data.tmax < 0:
            newT = 0
        else:
            newT = (self.data.tmin+self.data.tmax)/2
        if round(newT, 6) == self.T.value():
            self.T.valueChanged.emit(newT)
        else:
            self.T.setValue(newT)

    def GetBbox(self):
        self.Specbbox = self.ax_Spec.get_window_extent()
        self.Mapbbox = self.ax_Map.get_window_extent()
        self.XDCbbox = self.ax_XDC.get_window_extent()
        self.YDCbbox = self.ax_YDC.get_window_extent()
        self.ZDCbbox = self.ax_ZDC.get_window_extent()
        self.TDCbbox = self.ax_TDC.get_window_extent()

    def GetWhiteBackground(self):
        self.GetBbox()
        self.ax_XDC.redraw_in_frame()
        self.canvas.blit(self.XDCbbox)
        self.ax_YDC.redraw_in_frame()
        self.canvas.blit(self.YDCbbox)
        self.ax_ZDC.redraw_in_frame()
        self.canvas.blit(self.ZDCbbox)
        self.ax_TDC.redraw_in_frame()
        self.canvas.blit(self.TDCbbox)
        self.background_XDC = self.canvas.copy_from_bbox(self.XDCbbox)
        self.background_YDC = self.canvas.copy_from_bbox(self.YDCbbox)
        self.background_ZDC = self.canvas.copy_from_bbox(self.ZDCbbox)
        self.background_TDC = self.canvas.copy_from_bbox(self.TDCbbox)
        self.background_Spec = self.canvas.copy_from_bbox(self.Specbbox)
        self.background_Map = self.canvas.copy_from_bbox(self.Mapbbox)

    def setValueFromSpinBox(self, value):
        if self.sender() == self.X:
            self.setXYValue(value, self.Y.value(), True)
        elif self.sender() == self.Y:
            self.setXYValue(self.X.value(), value, True)
        elif self.sender() == self.Z:
            self.setZTValue(value, self.T.value(), True)
        elif self.sender() == self.T:
            self.setZTValue(self.Z.value(), value, True)

    def setValueFromSlider(self, value):
        if self.sender() == self.XSlider:
            self.X.valueChanged.disconnect()
            xvalue = value*(self.X.maximum()-self.X.minimum())/10000+self.X.minimum()
            self.setXYValue(xvalue, self.Y.value(), False)
            self.X.setValue(xvalue)
            self.X.valueChanged.connect(self.setValueFromSpinBox)
        elif self.sender() == self.YSlider:
            self.Y.valueChanged.disconnect()
            yvalue = value*(self.Y.maximum()-self.Y.minimum())/10000+self.Y.minimum()
            self.setXYValue(self.X.value(), yvalue, False)
            self.Y.setValue(yvalue)
            self.Y.valueChanged.connect(self.setValueFromSpinBox)
        elif self.sender() == self.ZSlider:
            self.Z.valueChanged.disconnect()
            zvalue = value*(self.Z.maximum()-self.Z.minimum())/10000+self.Z.minimum()
            self.setZTValue(zvalue, self.T.value(), False)
            self.Z.setValue(zvalue)
            self.Z.valueChanged.connect(self.setValueFromSpinBox)
        elif self.sender() == self.TSlider:
            self.T.valueChanged.disconnect()
            tvalue = value*(self.T.maximum()-self.T.minimum())/10000+self.T.minimum()
            self.setZTValue(self.Z.value(), tvalue, False)
            self.T.setValue(tvalue)
            self.T.valueChanged.connect(self.setValueFromSpinBox)

    def setXYValue(self, xvalue, yvalue, moveslider):
        if moveslider:
            self.XSlider.setValue((xvalue-self.X.minimum())/(self.X.maximum()-self.X.minimum())*10000)
            self.YSlider.setValue((yvalue-self.Y.minimum())/(self.Y.maximum()-self.Y.minimum())*10000)
        half_wid_xnum = (self.XSlice.value()-1)/2
        half_wid_ynum = (self.YSlice.value()-1)/2
        self.SpecYline1.set_xdata(xvalue-self.data.xstep*half_wid_xnum)
        self.SpecYline2.set_xdata(xvalue+self.data.xstep*half_wid_xnum)
        self.XDCCursor.set_xdata(xvalue)
        self.SpecXline1.set_ydata(yvalue-self.data.ystep*half_wid_ynum)
        self.SpecXline2.set_ydata(yvalue+self.data.ystep*half_wid_ynum)
        self.YDCCursor.set_ydata(yvalue)
        self.Map = self.get_Map(xvalue, yvalue)
        self.XDC = self.get_XDC(yvalue)
        self.YDC = self.get_YDC(xvalue)
        self.ZDC = self.get_ZDC(self.T.value())
        self.TDC = self.get_TDC(self.Z.value())
        self.plotMap(self.getcurrentcmap('Map'), True)
        self.plotXDC()
        self.plotYDC()
        self.plotZDC()
        self.plotTDC()
        self.plotArtist()
        self.setIntensity()

    def setZTValue(self, zvalue, tvalue, moveslider):
        if moveslider:
            self.ZSlider.setValue((zvalue-self.Z.minimum())/(self.Z.maximum()-self.Z.minimum())*10000)
            self.TSlider.setValue((tvalue-self.T.minimum())/(self.T.maximum()-self.T.minimum())*10000)
        half_wid_znum = (self.ZSlice.value()-1)/2
        half_wid_tnum = (self.TSlice.value()-1)/2
        self.MapYline1.set_xdata(zvalue-self.data.zstep*half_wid_znum)
        self.MapYline2.set_xdata(zvalue+self.data.zstep*half_wid_znum)
        self.ZDCCursor.set_xdata(zvalue)
        self.MapXline1.set_ydata(tvalue-self.data.tstep*half_wid_tnum)
        self.MapXline2.set_ydata(tvalue+self.data.tstep*half_wid_tnum)
        self.TDCCursor.set_ydata(tvalue)
        self.Spec = self.get_Spec(zvalue, tvalue)
        self.ZDC = self.get_ZDC(tvalue)
        self.TDC = self.get_TDC(zvalue)
        self.XDC = self.get_XDC(self.Y.value())
        self.YDC = self.get_YDC(self.X.value())
        self.plotSpec(self.getcurrentcmap('Spec'), True)
        self.plotXDC()
        self.plotYDC()
        self.plotZDC()
        self.plotTDC()
        self.plotArtist()
        self.setIntensity()

    def setSlice(self, value):
        if self.sender() == self.XSlice:
            if value % 2 == 0:
                self.XSlice.setValue(value-1)
            else:
                if value == 1:
                    self.SpecYline2.set_visible(False)
                else:
                    self.SpecYline2.set_visible(True)
                half_wid_num = (value-1)/2
                self.SpecYline1.set_xdata(self.X.value()-self.data.xstep*half_wid_num)
                self.SpecYline2.set_xdata(self.X.value()+self.data.xstep*half_wid_num)
                self.Map = self.get_Map(self.X.value(), self.Y.value())
                self.YDC = self.get_YDC(self.X.value())
                self.ZDC = self.get_ZDC(self.T.value())
                self.TDC = self.get_TDC(self.Z.value())
                self.plotMap(self.getcurrentcmap('Map'), True)
                self.plotYDC()
                self.plotZDC()
                self.plotTDC()
                self.plotArtist()
                self.setIntensity()
        elif self.sender() == self.YSlice:
            if value % 2 == 0:
                self.YSlice.setValue(value-1)
            else:
                if value == 1:
                    self.SpecXline2.set_visible(False)
                else:
                    self.SpecXline2.set_visible(True)
                half_wid_num = (value-1)/2
                self.SpecXline1.set_ydata(self.Y.value()-self.data.ystep*half_wid_num)
                self.SpecXline2.set_ydata(self.Y.value()+self.data.ystep*half_wid_num)
                self.Map = self.get_Map(self.X.value(), self.Y.value())
                self.XDC = self.get_XDC(self.Y.value())
                self.ZDC = self.get_ZDC(self.T.value())
                self.TDC = self.get_TDC(self.Z.value())
                self.plotMap(self.getcurrentcmap('Map'), True)
                self.plotXDC()
                self.plotZDC()
                self.plotTDC()
                self.plotArtist()
                self.setIntensity()
        elif self.sender() == self.ZSlice:
            if value % 2 == 0:
                self.ZSlice.setValue(value-1)
            else:
                if value == 1:
                    self.MapYline2.set_visible(False)
                else:
                    self.MapYline2.set_visible(True)
                half_wid_num = (value-1)/2
                self.MapYline1.set_xdata(self.Z.value()-self.data.zstep*half_wid_num)
                self.MapYline2.set_xdata(self.Z.value()+self.data.zstep*half_wid_num)
                self.Spec = self.get_Spec(self.Z.value(), self.T.value())
                self.XDC = self.get_XDC(self.Y.value())
                self.YDC = self.get_YDC(self.X.value())
                self.TDC = self.get_TDC(self.Z.value())
                self.plotSpec(self.getcurrentcmap('Spec'), True)
                self.plotXDC()
                self.plotYDC()
                self.plotTDC()
                self.plotArtist()
                self.setIntensity()
        elif self.sender() == self.TSlice:
            if value % 2 == 0:
                self.TSlice.setValue(value-1)
            else:
                if value == 1:
                    self.MapXline2.set_visible(False)
                else:
                    self.MapXline2.set_visible(True)
                half_wid_num = (value-1)/2
                self.MapXline1.set_ydata(self.T.value()-self.data.tstep*half_wid_num)
                self.MapXline2.set_ydata(self.T.value()+self.data.tstep*half_wid_num)
                self.Spec = self.get_Spec(self.Z.value(), self.T.value())
                self.XDC = self.get_XDC(self.Y.value())
                self.YDC = self.get_YDC(self.X.value())
                self.ZDC = self.get_ZDC(self.T.value())
                self.plotSpec(self.getcurrentcmap('Spec'), True)
                self.plotXDC()
                self.plotYDC()
                self.plotZDC()
                self.plotArtist()
                self.setIntensity()

    def scale2pnt(self, value, scale):
        return (np.abs(scale - value)).argmin()

    def setIntensity(self):
        intensity = self.get_intensity(self.X.value(), self.Y.value(), self.Z.value(), self.T.value())
        if np.isnan(intensity):
            self.Int.setText("NaN")
        elif np.abs(intensity) >= 0.01:
            self.Int.setText("%.2f" % intensity)
        else:
            self.Int.setText("%.2e" % intensity)

    def get_intensity(self, xvalue, yvalue, zvalue, tvalue):
        xidx = self.scale2pnt(xvalue, self.data.xscale)
        yidx = self.scale2pnt(yvalue, self.data.yscale)
        zidx = self.scale2pnt(zvalue, self.data.zscale)
        tidx = self.scale2pnt(tvalue, self.data.tscale)
        half_wid_xnum = int((self.XSlice.value()-1)/2)
        half_wid_ynum = int((self.YSlice.value()-1)/2)
        half_wid_znum = int((self.ZSlice.value()-1)/2)
        half_wid_tnum = int((self.TSlice.value()-1)/2)
        if xidx < half_wid_xnum:
            xminidx = 0
        else:
            xminidx = xidx-half_wid_xnum
        xmaxidx = xidx+half_wid_xnum+1
        if yidx < half_wid_ynum:
            yminidx = 0
        else:
            yminidx = yidx-half_wid_ynum
        ymaxidx = yidx+half_wid_ynum+1
        if zidx < half_wid_znum:
            zminidx = 0
        else:
            zminidx = zidx-half_wid_znum
        zmaxidx = zidx+half_wid_znum+1
        if tidx < half_wid_tnum:
            tminidx = 0
        else:
            tminidx = tidx-half_wid_tnum
        tmaxidx = tidx+half_wid_tnum+1
        return self.data.data[xminidx:xmaxidx, yminidx:ymaxidx, zminidx:zmaxidx, tminidx:tmaxidx].sum()

    def get_Spec(self, zvalue, tvalue):
        zidx = self.scale2pnt(zvalue, self.data.zscale)
        tidx = self.scale2pnt(tvalue, self.data.tscale)
        if self.ZSlice.value() == 1 and self.TSlice.value() == 1:
            return self.data.data[:, :, zidx, tidx]
        else:
            half_wid_znum = int((self.ZSlice.value()-1)/2)
            half_wid_tnum = int((self.TSlice.value()-1)/2)
            zidx_max = zidx+half_wid_znum+1
            tidx_max = tidx+half_wid_tnum+1
            if zidx < half_wid_znum:
                zidx_min = 0
            else:
                zidx_min = zidx-half_wid_znum
            if tidx < half_wid_tnum:
                tidx_min = 0
            else:
                tidx_min = tidx-half_wid_tnum
            array = self.data.data[:, :, zidx_min:zidx_max, tidx_min:tidx_max]
            array = np.sum(array, axis=2)
            array = np.sum(array, axis=2)
            return array

    def get_Map(self, xvalue, yvalue):
        xidx = self.scale2pnt(xvalue, self.data.xscale)
        yidx = self.scale2pnt(yvalue, self.data.yscale)
        if self.XSlice.value() == 1 and self.YSlice.value() == 1:
            return self.data.data[xidx, yidx, :, :]
        else:
            half_wid_xnum = int((self.XSlice.value()-1)/2)
            xidx_max = xidx+half_wid_xnum+1
            if xidx < half_wid_xnum:
                xidx_min = 0
            else:
                xidx_min = xidx-half_wid_xnum
            half_wid_ynum = int((self.YSlice.value()-1)/2)
            yidx_max = yidx+half_wid_ynum+1
            if yidx < half_wid_ynum:
                yidx_min = 0
            else:
                yidx_min = yidx-half_wid_ynum
            array = self.data.data[xidx_min:xidx_max, yidx_min:yidx_max, :, :]
            array = np.sum(array, axis=0)
            array = np.sum(array, axis=0)
            return array

    def get_XDC(self, yvalue):
        yidx = self.scale2pnt(yvalue, self.data.yscale)
        if self.YSlice.value() == 1:
            return self.Spec[:, yidx]
        else:
            half_wid_ynum = int((self.YSlice.value()-1)/2)
            if yidx < half_wid_ynum:
                ystart = 0
            else:
                ystart = yidx - half_wid_ynum
            yend = yidx + half_wid_ynum + 1
            array = self.Spec[:, ystart:yend]
            return np.sum(array, axis=1)

    def get_YDC(self, xvalue):
        xidx = self.scale2pnt(xvalue, self.data.xscale)
        if self.XSlice.value() == 1:
            return self.Spec[xidx, :]
        else:
            half_wid_xnum = int((self.XSlice.value()-1)/2)
            if xidx < half_wid_xnum:
                xstart = 0
            else:
                xstart = xidx - half_wid_xnum
            xend = xidx + half_wid_xnum + 1
            array = self.Spec[xstart:xend, :]
            return np.sum(array, axis=0)

    def get_ZDC(self, tvalue):
        tidx = self.scale2pnt(tvalue, self.data.tscale)
        if self.TSlice.value() == 1:
            return self.Map[:, tidx]
        else:
            half_wid_tnum = int((self.TSlice.value()-1)/2)
            if tidx < half_wid_tnum:
                tstart = 0
            else:
                tstart = tidx - half_wid_tnum
            tend = tidx + half_wid_tnum + 1
            array = self.Map[:, tstart:tend]
            return np.sum(array, axis=1)

    def get_TDC(self, zvalue):
        zidx = self.scale2pnt(zvalue, self.data.zscale)
        if self.ZSlice.value() == 1:
            return self.Map[zidx, :]
        else:
            half_wid_znum = int((self.ZSlice.value()-1)/2)
            if zidx < half_wid_znum:
                zstart = 0
            else:
                zstart = zidx - half_wid_znum
            zend = zidx + half_wid_znum + 1
            array = self.Map[zstart:zend, :]
            return np.sum(array, axis=0)

    def getcurrentcmap(self, which):
        linearIndex = np.linspace(0, 1, 256)
        if which == 'Spec':
            cmap_str = self.Speccmapmenu.currentText()
            if self.revSpeccmap.checkState() == Qt.Checked:
                cmap_str += "_r"
            nonlinearIndex = np.power(linearIndex, self.SpecGamma.value())
        elif which == 'Map':
            cmap_str = self.Mapcmapmenu.currentText()
            if self.revMapcmap.checkState() == Qt.Checked:
                cmap_str += "_r"
            nonlinearIndex = np.power(linearIndex, self.MapGamma.value())
        raw_cmap = cm.get_cmap(cmap_str, 256)
        new_cmap = ListedColormap(raw_cmap(nonlinearIndex))
        return new_cmap

    def updatecolorscale(self, cmap, which):
        if which == 'Spec':
            for img in self.ax_Speccmap.get_images():
                img.remove()
            self.Speccmapimage = self.ax_Speccmap.imshow(self.gradient, cmap=cmap, origin="lower", aspect="auto")
            self.ax_Speccmap.redraw_in_frame()
            self.canvas.blit(self.ax_Speccmap.bbox)
        elif which == 'Map':
            for img in self.ax_Mapcmap.get_images():
                img.remove()
            self.Mapcmapimage = self.ax_Mapcmap.imshow(self.gradient, cmap=cmap, origin="lower", aspect="auto")
            self.ax_Mapcmap.redraw_in_frame()
            self.canvas.blit(self.ax_Mapcmap.bbox)

    def changeSpeccmapbyindex(self, index):
        self.updatecolorscale(self.getcurrentcmap('Spec'), 'Spec')
        self.plotSpec(self.getcurrentcmap('Spec'), True)
        self.plotArtist()

    def changeMapcmapbyindex(self, index):
        self.updatecolorscale(self.getcurrentcmap('Map'), 'Map')
        self.plotMap(self.getcurrentcmap('Map'), True)
        self.plotArtist()

    def setGammaFromSpecSpinBox(self, value):
        self.updatecolorscale(self.getcurrentcmap('Spec'), 'Spec')
        self.plotSpec(self.getcurrentcmap('Spec'), True)
        self.plotArtist()
        self.SpecGSlider.setValue(1000000*np.log(value))

    def setGammaFromSpecSlider(self, value):
        self.SpecGamma.setValue(np.exp(value/1000000))

    def setGammaFromMapSpinBox(self, value):
        self.updatecolorscale(self.getcurrentcmap('Map'), 'Map')
        self.plotMap(self.getcurrentcmap('Map'), True)
        self.plotArtist()
        self.MapGSlider.setValue(1000000*np.log(value))

    def setGammaFromMapSlider(self, value):
        self.MapGamma.setValue(np.exp(value/1000000))

    def reverseSpeccmap(self, state):
        self.updatecolorscale(self.getcurrentcmap('Spec'), 'Spec')
        self.plotSpec(self.getcurrentcmap('Spec'), True)
        self.plotArtist()

    def reverseMapcmap(self, state):
        self.updatecolorscale(self.getcurrentcmap('Map'), 'Map')
        self.plotMap(self.getcurrentcmap('Map'), True)
        self.plotArtist()

    def begincursor(self, on):
        if on:
            self.SpecXline1.set_visible(True)
            self.SpecYline1.set_visible(True)
            self.MapXline1.set_visible(True)
            self.MapYline1.set_visible(True)
            if self.XSlice.value() > 1:
                self.SpecYline2.set_visible(True)
            if self.YSlice.value() > 1:
                self.SpecXline2.set_visible(True)
            if self.ZSlice.value() > 1:
                self.MapYline2.set_visible(True)
            if self.TSlice.value() > 1:
                self.MapXline2.set_visible(True)
            self.XDCCursor.set_visible(True)
            self.YDCCursor.set_visible(True)
            self.ZDCCursor.set_visible(True)
            self.TDCCursor.set_visible(True)
            self.plotXDC()
            self.plotYDC()
            self.plotZDC()
            self.plotArtist()
            self.cid_mouse = self.canvas.mpl_connect('motion_notify_event', self.navigate)
            self.cid_key = self.canvas.mpl_connect('key_press_event', self.navigate)
        else:
            self.SpecXline1.set_visible(False)
            self.SpecYline1.set_visible(False)
            self.MapXline1.set_visible(False)
            self.MapYline1.set_visible(False)
            self.SpecXline2.set_visible(False)
            self.SpecYline2.set_visible(False)
            self.MapXline2.set_visible(False)
            self.MapYline2.set_visible(False)
            self.XDCCursor.set_visible(False)
            self.YDCCursor.set_visible(False)
            self.ZDCCursor.set_visible(False)
            self.TDCCursor.set_visible(False)
            self.plotXDC()
            self.plotYDC()
            self.plotZDC()
            self.plotArtist()
            self.canvas.mpl_disconnect(self.cid_mouse)
            self.canvas.mpl_disconnect(self.cid_key)

    def navigate(self, event):
        if event.inaxes == self.ax_Spec and event.key == "control":
            self.setXYValue(event.xdata, event.ydata, True)
            self.X.valueChanged.disconnect()
            self.Y.valueChanged.disconnect()
            self.X.setValue(event.xdata)
            self.Y.setValue(event.ydata)
            self.X.valueChanged.connect(self.setValueFromSpinBox)
            self.Y.valueChanged.connect(self.setValueFromSpinBox)
        if event.inaxes == self.ax_Map and event.key == "control":
            self.setZTValue(event.xdata, event.ydata, True)
            self.Z.valueChanged.disconnect()
            self.T.valueChanged.disconnect()
            self.Z.setValue(event.xdata)
            self.T.setValue(event.ydata)
            self.Z.valueChanged.connect(self.setValueFromSpinBox)
            self.T.valueChanged.connect(self.setValueFromSpinBox)

    def OnPress(self, event):
        if (event.inaxes == self.ax_Spec or event.inaxes == self.ax_Map) and event.button == 1:
            if event.inaxes == self.ax_Spec:
                selector0 = self.selector_Spec
            elif event.inaxes == self.ax_Map:
                selector0 = self.selector_Map
            if not selector0.visible: #draw selector from nothing
                selector0.moving_state = "draw"
                selector0.origin = (event.xdata, event.ydata)
                self.cid_drawRS = self.canvas.mpl_connect('motion_notify_event', self.OnDrawRS)
            else:
                dist = selector0.nearestCorner(event.x, event.y)
                if dist < 10:
                    selector0.moving_state = "moveHandle"
                    selector0.origin = (event.xdata, event.ydata)
                    self.cid_moveHandle = self.canvas.mpl_connect('motion_notify_event', self.OnMoveHandle)
                else:
                    if selector0.isinRegion(event.xdata, event.ydata): #move the selector
                        selector0.moving_state = "move"
                        selector0.origin = (event.xdata, event.ydata)
                        self.cid_moveRS = self.canvas.mpl_connect('motion_notify_event', self.OnMoveRS)
                    else:          #clear the selector
                        selector0.set_visible(False)
                        self.plotArtist()

    def OnDrawRS(self, event):
        if (event.inaxes == self.ax_Spec or event.inaxes == self.ax_Map) and event.button == 1:
            if event.inaxes == self.ax_Spec:
                selector0 = self.selector_Spec
            elif event.inaxes == self.ax_Map:
                selector0 = self.selector_Map
            if event.xdata != selector0.origin[0] and event.ydata != selector0.origin[1]:
                selector0.set_visible(True)
                selector0.resize(selector0.origin[0], selector0.origin[1], event.xdata, event.ydata)
                self.plotArtist()

    def OnMoveRS(self, event):
        if (event.inaxes == self.ax_Spec or event.inaxes == self.ax_Map) and event.button == 1:
            if event.inaxes == self.ax_Spec:
                selector0 = self.selector_Spec
            elif event.inaxes == self.ax_Map:
                selector0 = self.selector_Map
            xmin, ymin, xmax, ymax = selector0.region
            selector0.resize(xmin+event.xdata-selector0.origin[0], ymin+event.ydata-selector0.origin[1], xmax+event.xdata-selector0.origin[0], ymax+event.ydata-selector0.origin[1])
            self.plotArtist()
            selector0.origin = (event.xdata, event.ydata)

    def OnMoveHandle(self, event):
        if (event.inaxes == self.ax_Spec or event.inaxes == self.ax_Map) and event.button == 1:
            if event.inaxes == self.ax_Spec:
                selector0 = self.selector_Spec
            elif event.inaxes == self.ax_Map:
                selector0 = self.selector_Map
            xmin, ymin, xmax, ymax = selector0.region
            if selector0.active_handle == 0:
                selector0.resize(xmin+event.xdata-selector0.origin[0], ymin+event.ydata-selector0.origin[1], xmax, ymax)
            elif selector0.active_handle == 1:
                selector0.resize(xmin, ymin+event.ydata-selector0.origin[1], xmax, ymax)
            elif selector0.active_handle == 2:
                selector0.resize(xmin, ymin+event.ydata-selector0.origin[1], xmax+event.xdata-selector0.origin[0], ymax)
            elif selector0.active_handle == 3:
                selector0.resize(xmin, ymin, xmax+event.xdata-selector0.origin[0], ymax)
            elif selector0.active_handle == 4:
                selector0.resize(xmin, ymin, xmax+event.xdata-selector0.origin[0], ymax+event.ydata-selector0.origin[1])
            elif selector0.active_handle == 5:
                selector0.resize(xmin, ymin, xmax, ymax+event.ydata-selector0.origin[1])
            elif selector0.active_handle == 6:
                selector0.resize(xmin+event.xdata-selector0.origin[0], ymin, xmax, ymax+event.ydata-selector0.origin[1])
            elif selector0.active_handle == 7:
                selector0.resize(xmin+event.xdata-selector0.origin[0], ymin, xmax, ymax)
            self.plotArtist()
            selector0.origin = (event.xdata, event.ydata)

    def OnRelease(self, event):
        if event.inaxes == self.ax_Spec or event.inaxes == self.ax_Map:
            if event.inaxes == self.ax_Spec:
                selector0 = self.selector_Spec
            elif event.inaxes == self.ax_Map:
                selector0 = self.selector_Map
            if event.button == 1:
                if selector0.moving_state == "draw":
                    self.canvas.mpl_disconnect(self.cid_drawRS)
                elif selector0.moving_state == "move":
                    self.canvas.mpl_disconnect(self.cid_moveRS)
                elif selector0.moving_state == "moveHandle":
                    self.canvas.mpl_disconnect(self.cid_moveHandle)
            if event.button == 3:
                if selector0.visible and selector0.isinRegion(event.xdata, event.ydata):
                    self.CropAction.setEnabled(True)
                    self.SelectMenu.setEnabled(True)
                    if event.inaxes == self.ax_Spec:
                        #self.CropAction.triggered.connect(lambda: self.crop('Spec'))
                        self.SelectX.setEnabled(True)
                        self.SelectY.setEnabled(True)
                        self.SelectXY.setEnabled(True)
                        self.SelectZ.setEnabled(False)
                        self.SelectT.setEnabled(False)
                        self.SelectZT.setEnabled(False)
                    elif event.inaxes == self.ax_Map:
                        #self.CropAction.triggered.connect(lambda: self.crop('Map'))
                        self.SelectX.setEnabled(False)
                        self.SelectY.setEnabled(False)
                        self.SelectXY.setEnabled(False)
                        self.SelectZ.setEnabled(True)
                        self.SelectT.setEnabled(True)
                        self.SelectZT.setEnabled(True)
                else:
                    self.CropAction.setEnabled(False)
                    self.SelectMenu.setEnabled(False)
                self.showContextMenu()
        else:
            if event.button == 3:
                self.CropAction.setEnabled(False)
                self.SelectMenu.setEnabled(False)
                self.showContextMenu()

    def OnKeyPress(self, event):
        if event.key == 'ctrl+a':
            if self.toolPanel.isChecked():
                self.toolPanel.setChecked(False)
            else:
                self.toolPanel.setChecked(True)

    def showContextMenu(self):
        self.contextMenu.move(QCursor.pos())
        self.contextMenu.show()

    def plotSpec(self, cmap, useblit):
        for img in self.ax_Spec.get_images():
            img.remove()
        self.Specimg = self.ax_Spec.imshow(self.Spec.T, cmap=cmap, origin="lower", extent=(self.data.xmin-0.5*self.data.xstep, self.data.xmax+0.5*self.data.xstep, self.data.ymin-0.5*self.data.ystep, self.data.ymax+0.5*self.data.ystep), aspect=self.spec_aspect, interpolation='none')
        visible_flag = self.selector_Spec.visible
        self.selector_Spec.set_visible(False)
        if useblit:
            self.ax_Spec.redraw_in_frame()
            self.canvas.blit(self.Specbbox)
        else:
            pass
        self.background_Spec = self.canvas.copy_from_bbox(self.Specbbox) #this line makes sure that the background will be updated when user change color map
        self.selector_Spec.set_visible(visible_flag)

    def plotMap(self, cmap, useblit):
        for img in self.ax_Map.get_images():
            img.remove()
        self.Mapimg = self.ax_Map.imshow(self.Map.T, cmap=cmap, origin="lower", extent=(self.data.zmin-0.5*self.data.zstep, self.data.zmax+0.5*self.data.zstep, self.data.tmin-0.5*self.data.tstep, self.data.tmax+0.5*self.data.tstep), aspect=self.map_aspect, interpolation='none')
        visible_flag = self.selector_Map.visible
        self.selector_Map.set_visible(False)
        if useblit:
            self.ax_Map.redraw_in_frame()
            self.canvas.blit(self.Mapbbox)
        else:
            pass
        self.background_Map = self.canvas.copy_from_bbox(self.Mapbbox) #this line makes sure that the background will be updated when user change color map
        self.selector_Map.set_visible(visible_flag)

    def plotXDC(self):
        self.resetXDC()
        self.canvas.restore_region(self.background_XDC)
        self.ax_XDC.draw_artist(self.XDCLine)
        self.ax_XDC.draw_artist(self.XDCCursor)
        self.canvas.blit(self.XDCbbox)

    def resetXDC(self):
        mask = np.isnan(self.XDC)
        self.XDCLine.set_data(self.data.xscale[~mask], self.XDC[~mask])
        if len(self.XDC[~mask]) > 1:
            minvalue = min(self.XDC[~mask])
            maxvalue = max(self.XDC[~mask])
            if minvalue == maxvalue:
                minvalue = minvalue - 0.5
                maxvalue = maxvalue + 0.5
        else:
            minvalue = 0
            maxvalue = 1
        self.ax_XDC.set_ybound(lower=minvalue-0.01*(maxvalue-minvalue), upper=maxvalue+0.01*(maxvalue-minvalue))
        self.ax_XDC.set_xbound(lower=self.data.xmin-self.data.xstep*0.5, upper=self.data.xmax+self.data.xstep*0.5)

    def plotYDC(self):
        self.resetYDC()
        self.canvas.restore_region(self.background_YDC)
        self.ax_YDC.draw_artist(self.YDCLine)
        self.ax_YDC.draw_artist(self.YDCCursor)
        self.canvas.blit(self.YDCbbox)

    def resetYDC(self):
        mask = np.isnan(self.YDC)
        self.YDCLine.set_data(self.YDC[~mask], self.data.yscale[~mask])
        if len(self.YDC[~mask]) > 1:
            minvalue = min(self.YDC[~mask])
            maxvalue = max(self.YDC[~mask])
            if minvalue == maxvalue:
                minvalue = minvalue - 0.5
                maxvalue = maxvalue + 0.5
        else:
            minvalue = 0
            maxvalue = 1
        self.ax_YDC.set_xbound(lower=minvalue-0.01*(maxvalue-minvalue), upper=maxvalue+0.01*(maxvalue-minvalue))
        self.ax_YDC.set_ybound(lower=self.data.ymin-self.data.ystep*0.5, upper=self.data.ymax+self.data.ystep*0.5)

    def plotZDC(self):
        self.resetZDC()
        self.canvas.restore_region(self.background_ZDC)
        self.ax_ZDC.draw_artist(self.ZDCLine)
        self.ax_ZDC.draw_artist(self.ZDCCursor)
        self.canvas.blit(self.ZDCbbox)

    def resetZDC(self):
        mask = np.isnan(self.ZDC)
        self.ZDCLine.set_data(self.data.zscale[~mask], self.ZDC[~mask])
        if len(self.ZDC[~mask]) > 1:
            minvalue = min(self.ZDC[~mask])
            maxvalue = max(self.ZDC[~mask])
            if minvalue == maxvalue:
                minvalue = minvalue - 0.5
                maxvalue = maxvalue + 0.5
        else:
            minvalue = 0
            maxvalue = 1
        self.ax_ZDC.set_ybound(lower=minvalue-0.01*(maxvalue-minvalue), upper=maxvalue+0.01*(maxvalue-minvalue))
        self.ax_ZDC.set_xbound(lower=self.data.zmin-self.data.zstep*0.5, upper=self.data.zmax+self.data.zstep*0.5)

    def plotTDC(self):
        self.resetTDC()
        self.canvas.restore_region(self.background_TDC)
        self.ax_TDC.draw_artist(self.TDCLine)
        self.ax_TDC.draw_artist(self.TDCCursor)
        self.canvas.blit(self.TDCbbox)

    def resetTDC(self):
        mask = np.isnan(self.TDC)
        self.TDCLine.set_data(self.TDC[~mask], self.data.tscale[~mask])
        if len(self.TDC[~mask]) > 1:
            minvalue = min(self.TDC[~mask])
            maxvalue = max(self.TDC[~mask])
            if minvalue == maxvalue:
                minvalue = minvalue - 0.5
                maxvalue = maxvalue + 0.5
        else:
            minvalue = 0
            maxvalue = 1
        self.ax_TDC.set_xbound(lower=minvalue-0.01*(maxvalue-minvalue), upper=maxvalue+0.01*(maxvalue-minvalue))
        self.ax_TDC.set_ybound(lower=self.data.tmin-self.data.tstep*0.5, upper=self.data.tmax+self.data.tstep*0.5)

    def plotArtist(self):
        self.canvas.restore_region(self.background_Spec)
        for line in self.ax_Spec.get_lines():
            self.ax_Spec.draw_artist(line)
        for artist in self.selector_Spec.artist:
            self.ax_Spec.draw_artist(artist)
        self.canvas.blit(self.Specbbox)
        self.canvas.restore_region(self.background_Map)
        for line in self.ax_Map.get_lines():
            self.ax_Map.draw_artist(line)
        for artist in self.selector_Map.artist:
            self.ax_Map.draw_artist(artist)
        self.canvas.blit(self.Mapbbox)

    def updateAxesPosition(self, useDraw):
        x_Spec, y_Spec, w_Spec, h_Spec = self.ax_Spec.get_position().bounds
        x_Map, y_Map, w_Map, h_Map = self.ax_Map.get_position().bounds
        x_XDC, y_XDC, w_XDC, h_XDC = self.ax_XDC.get_position().bounds
        x_YDC, y_YDC, w_YDC, h_YDC = self.ax_YDC.get_position().bounds
        x_ZDC, y_ZDC, w_ZDC, h_ZDC = self.ax_ZDC.get_position().bounds
        x_TDC, y_TDC, w_TDC, h_TDC = self.ax_TDC.get_position().bounds
        self.ax_XDC.set_position([x_Spec, y_XDC, w_Spec, h_XDC])
        self.ax_YDC.set_position([x_YDC, y_Spec, w_YDC, h_Spec])
        self.ax_ZDC.set_position([x_Map, y_ZDC, w_Map, h_ZDC])
        self.ax_TDC.set_position([x_TDC, y_Map, w_TDC, h_Map])
        visible_Spec_flag = self.selector_Spec.visible
        visible_Map_flag = self.selector_Map.visible
        self.selector_Spec.set_visible(False)
        self.selector_Map.set_visible(False)
        if useDraw:
            self.canvas.draw()
        self.GetWhiteBackground()
        self.selector_Spec.set_visible(visible_Spec_flag)
        self.selector_Map.set_visible(visible_Map_flag)
        self.plotXDC()
        self.plotYDC()
        self.plotZDC()
        self.plotTDC()
        self.plotArtist()

    def resizeEvent_wrapper(self):
        self.updateAxesPosition(False)


from django.contrib import admin
from django.urls import path ,include

admin.site.site_header = "Kvm3 IceCreams Admin"
admin.site.site_title = "Kvm3 IceCreams Admin Portal"
admin.site.index_title = "Welcome to Kvm3 IceCreams  Researcher Portal"

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('app.urls'))
]


import logging
import pickle
from hashlib import sha1
from pathlib import Path
from typing import Any, Union

import typer
from rich import print
from rich.logging import RichHandler

from gil import paths
from gil.core import Blob, Commit, Sha, Tree
from gil.utils import NoRefException, get_ref, set_ref

FORMAT = "%(message)s"
logging.basicConfig(level=logging.DEBUG, format=FORMAT, datefmt="[%X]", handlers=[RichHandler()])
logger = logging.getLogger(__name__)

app = typer.Typer(help="`gil` is a git-like tool for educational purposes.")

########################################################################################
@app.command()
def init():
    """Create a gil repo."""
    pass
    path = Path.cwd() / ".gil"
    if path.exists():
        logger.warning(f"gil repo at {path} already exists")
        return

    path.mkdir()
    (path / "objects").mkdir()
    (path / "refs").mkdir()
    (path / "refs/tags").mkdir()
    (path / "refs/heads").mkdir()
    (path / "refs/remotes").mkdir()
    with (path / "HEAD").open("w") as f:
        f.write("refs/heads/main")
    logger.info(f"gil repo created in '{path}'")

########################################################################################
# BLOB
@app.command()
def hash_object(path: Path):
    """Hash the object and add it to the repo."""
    assert path.is_file()
    data = path.read_bytes()
    sha = hash_data(data)
    dump_obj(sha, Blob(data), path)
    return sha

@app.command()
def cat_file(sha: str, do_print: bool = True):
    """Read the content of the object with the given sha."""
    path = paths.OBJECTS_DIR / sha
    assert path.is_file()
    with path.open("rb") as f:
        obj = pickle.load(f)
    if do_print:
        print(obj)
    return obj

########################################################################################
# TREE
@app.command()
def hash_tree(path: Path):
    """Hash the tree (recursively) and add it to the repo."""
    assert path.is_dir()
    # collect all the data
    items = []
    for p in path.iterdir():
        if p.name == ".gil":
            continue
        elif p.is_file():
            items.append((hash_object(p), str(p.name)))
        elif p.is_dir():
            items.append((hash_tree(p), str(p.name)))
        else:
            raise Exception("WTF!")

    # create and dump tree object
    items = sorted(items)
    sha = hash_data("".join(sha for sha, _ in items))
    dump_obj(sha, Tree(items), path)
    return sha

########################################################################################
# COMMIT
@app.command()
def snapshot(commit_message: str):
    """Think: git add and git commit"""
    tree_sha = hash_tree(Path("."))

    try:
        prev_commit_sha = get_ref()
        _prev_commit = cat_file(prev_commit_sha, do_print=False)
        if _prev_commit.tree == tree_sha:
            logger.warning("Nothing changed, nothing to commit.")
            return
    except NoRefException:
        prev_commit_sha = ""

    commit = Commit(tree_sha, prev_commit_sha, commit_message)
    commit_sha = hash_data((str(commit.parent) + commit.tree).encode())
    dump_obj(commit_sha, commit, "commit")
    set_ref(commit_sha)

########################################################################################
# MISC
@app.command()
def log():
    """log of all commits"""
    commit_sha = get_ref()
    while commit_sha:
        commit: Commit = cat_file(commit_sha, do_print=False)
        print(f"# {commit_sha}")
        print(commit)
        commit_sha = commit.parent

# GRAPH
@app.command()
def graph():
    from graphviz import Digraph

    dot = Digraph()
    for path in paths.OBJECTS_DIR.iterdir():
        sha = path.name
        obj = cat_file(sha)

        if isinstance(obj, Blob):
            dot.node(sha[:8], shape="box")
        elif isinstance(obj, Tree):
            dot.node(sha[:8], shape="triangle")
            for child_sha, child_name in obj.items:
                dot.edge(sha[:8], child_sha[:8], child_name)
        elif isinstance(obj, Commit):
            dot.node(sha[:8], shape="circle")
            dot.edge(sha[:8], obj.tree[:8], obj.commit_message)
            dot.edge(sha[:8], obj.parent[:8], obj.commit_message)
        else:
            raise ValueError("WTF?")

    dot.render("/tmp/gil.pdf", view=True)

########################################################################################
# UTILS
def dump_obj(sha: Sha, obj: Any, message) -> None:
    dst = paths.OBJECTS_DIR / sha
    if dst.exists():
        logger.warning(f"{sha} --> '{message}' already hashed")
    else:
        with dst.open("wb") as f:
            pickle.dump(obj, f)
        logger.info(f"{sha} --> '{message}' hashed")

def hash_data(data: Union[str, bytes]) -> Sha:
    if isinstance(data, str):
        data = data.encode()
    return sha1(data).hexdigest()

########################################################################################
if __name__ == "__main__":
    app()


import importlib

from easydict import EasyDict as edict

__C = edict()
cfg = __C

__C.MODEL_NAME = ""  # this name would be the result file name
__C.MODULE = ""  # sample: dgl.network  b_global.network

__C.BATCH_SIZE = 32
__C.NUM_WORKERS = 8

__C.LOG_FILE_NAME = ""  # the suffix of log file

__C.MODEL_SAVE_PATH = ""  # auto generated

#
# Dataset
#
__C.DATASET = ""

# Other dataset specific configs should be imported from dataset_config.py

# wandb project name
__C.PROJECT = ""

#
# Training options
#

__C.TRAIN = edict()

# Total epochs
__C.TRAIN.NUM_EPOCHS = 200

# Optimizer type
__C.TRAIN.OPTIMIZER = "SGD"

# Start learning rate
__C.TRAIN.LR = 0.001

# LR Scheduler
__C.TRAIN.LR_SCHEDULER = "cosine"

# Learning rate decay
__C.TRAIN.LR_DECAY = 100.0

# Learning rate decay step (in epochs)
__C.TRAIN.LR_STEP = [10, 20]

# warmup_ratio for Adam Cosine
__C.TRAIN.WARMUP_RATIO = 0.0

# clip_grad
__C.TRAIN.CLIP_GRAD = None

# beta1, beta2 for Adam Optimizer
__C.TRAIN.beta1 = 0
__C.TRAIN.beta2 = 0.9

# weight decay for Adam or SGD
__C.TRAIN.WEIGHT_DECAY = 0.0

# SGD momentum
__C.TRAIN.MOMENTUM = 0.9

# Check val every n epoch
__C.TRAIN.VAL_EVERY = 5

# Visualization during training
__C.TRAIN.VIS = True
__C.TRAIN.VAL_SAMPLE_VIS = 5

# Loss function.
__C.TRAIN.LOSS = ""

#
# Callback
#
__C.CALLBACK = edict()
__C.CALLBACK.MATCHING_TASK = ["trans"]
__C.CALLBACK.CHECKPOINT_MONITOR = "val/loss"
__C.CALLBACK.CHECKPOINT_MODE = "min"

#
# Loss config
#
__C.LOSS = edict()

#
# Evaluation options
#

__C.EVAL = edict()

#
# MISC
#

# Parallel GPU indices ([0] for single GPU)
__C.GPUS = [0]
# Parallel strategy for multiple gpus
__C.PARALLEL_STRATEGY = "ddp"

# Float Precision, 32 for False, 16 for True
__C.FP16 = False

# CUDNN benchmark
__C.CUDNN = False

__C.WEIGHT_FILE = ""

# Output path (for checkpoints, running logs)
__C.OUTPUT_PATH = ""

# The step of iteration to print running statistics.
# The real step value will be the least common multiple of this value and batch_size
__C.STATISTIC_STEP = 100

# random seed used for data loading
__C.RANDOM_SEED = 42

# directory for collecting statistics of results
__C.STATS = ""

def _merge_a_into_b(a, b):
    """Merge config dictionary A into config dictionary B, clobbering the
    options in B whenever they are also specified in A.
    """
    if type(a) is not edict:
        return

    for k, v in a.items():
        # a must specify keys that are in b
        if k not in b:
            raise KeyError("{} is not a valid config key".format(k))

        # the types must match, too
        if type(b[k]) is not type(v):
            if type(b[k]) is float and type(v) is int:
                v = float(v)
            else:
                if k not in ["CLASS"]:
                    raise ValueError(
                        "Type mismatch ({} vs. {}) for config key: {}".format(
                            type(b[k]), type(v), k
                        )
                    )

        # recursively merge dicts
        if type(v) is edict:
            try:
                _merge_a_into_b(a[k], b[k])
            except:
                print("Error under config key: {}".format(k))
                raise
        else:
            b[k] = v

def cfg_from_file(filename):
    """Load a config file and merge it into the default options."""
    import yaml

    with open(filename, "r") as f:
        yaml_cfg = edict(yaml.full_load(f))

    # DONE: for model specific or data specific configs, please define them in the model package
    #  and then load them here
    if "MODULE" in yaml_cfg and "MODEL" not in __C:
        model_cfg_module = ".".join(
            ["model"] + [yaml_cfg.MODULE.split(".")[0]] + ["model_config"]
        )
        # model_cfg_module = 'model.model_config'
        mod = importlib.import_module(model_cfg_module)
        __C["MODEL"] = mod.get_model_cfg()

    if "DATASET" in yaml_cfg and yaml_cfg.DATASET is not None:
        dataset = importlib.import_module("dataset")
        __C["DATA"] = dataset.dataset_cfg[yaml_cfg.DATASET.split(".")[0].upper()]

    _merge_a_into_b(yaml_cfg, __C)

def cfg_from_list(cfg_list):
    """Set config keys via list (e.g., from command line)."""
    from ast import literal_eval

    assert len(cfg_list) % 2 == 0
    for k, v in zip(cfg_list[0::2], cfg_list[1::2]):
        key_list = k.split(".")
        d = __C
        for sub_key in key_list[:-1]:
            assert sub_key in d.keys()
            d = d[sub_key]
        sub_key = key_list[-1]
        assert sub_key in d.keys()
        try:
            value = literal_eval(v)
        except:
            # handle the case when v is a string literal
            value = v
        assert type(value) == type(
            d[sub_key]
        ), "type {} does not match original type {}".format(
            type(value), type(d[sub_key])
        )
        d[sub_key] = value


import numpy as np
import matplotlib.pyplot as plt

def print_cloud(points, l_x, l_y, delta):
    plt.figure()
    plt.scatter(points[:, 0], points[:, 1], s=l_x, alpha=1)

    plt.plot((0, 0), (0, l_y), 'k-', color='r')
    plt.plot((0, l_x), (0, 0), 'k-', color='r')
    plt.plot((0, l_x), (l_y, l_y), 'k-', color='r')
    plt.plot((l_x, l_x), (0, l_y), 'k-', color='r')

    delta_x = l_x * delta
    delta_y = l_y * delta
    plt.plot((delta_x, delta_x), (0, l_y), 'k-', color='r')
    plt.plot((0, l_x), (delta_y, delta_y), 'k-', color='r')
    plt.plot((0, l_x), (l_y - delta_y, l_y - delta_y), 'k-', color='r')
    plt.plot((l_x - delta_x, l_x - delta_x), (0, l_y), 'k-', color='r')

    plt.show()

def uniform_node_clouds(l_x, l_y, delta, n_points):
    xy_min = [0, 0]
    xy_max = [l_x, l_y]

    dot_dist = np.sqrt(l_x * l_y / n_points)

    x_line_qty = int(l_x/dot_dist)
    y_line_qty = int(l_y/dot_dist)

    points = np.random.uniform(low=xy_min, high=xy_max, size=(n_points, 2))
    x_line_points = np.linspace(0, l_x, x_line_qty)
    y_line_points = np.linspace(0, l_y, y_line_qty)

    x_lines = (0, delta * l_x, (1 - delta) * l_x, l_x)
    y_lines = (0, delta * l_y, (1 - delta) * l_y, l_y)

    for i in range(0, 4):
        x_line = np.concatenate((x_line_points[:, np.newaxis], np.repeat(x_lines[i], x_line_qty)[:, np.newaxis]), axis=1)
        y_line = np.concatenate((np.repeat(y_lines[i], y_line_qty)[:, np.newaxis], y_line_points[:, np.newaxis]), axis=1)

        points = np.concatenate((points, x_line))
        points = np.concatenate((points, y_line))

    return points


# -*- coding: utf-8 -*-
from __future__ import annotations

import smtplib

from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from matplotlib.backends.backend_pdf import PdfPages
from pathlib import Path
from tempfile import TemporaryDirectory

SIGNATURE = (
    '
Name
\n'
    "
Company
\n"
    "
Address
\n"
    "
City & Zip
\n"
    "
Office: (000) 000-0000
\n"
    "
Cell: (111) 111-1111
\n"
    "
user@company.com
\n"
)

class EmailMsg:
    def __init__(self, recipient_list, subject, signature=SIGNATURE):
        self.sender = "user@company.com"
        self.subject = subject
        self.recipient_list = recipient_list
        self.signature = signature
        self.attachments = []
        self.images = []
        self.text = []

    def send(self):
        msg = self.construct_msg()
        with smtplib.SMTP("smtp.company.com") as mailer:
            server_response = smtplib.SMTP.ehlo(mailer)
            mailer.sendmail(msg["From"], self.recipient_list, msg.as_string())

    def construct_msg(self):
        msg = MIMEMultipart()
        msg["Subject"] = self.subject
        msg["From"] = self.sender
        for attachment in self.attachments:
            msg.attach(attachment)
        for display in self.images:
            msg.attach(display)
        all_text = "

".join(self.text)
        all_text += "

" + self.signature
        msg.attach(MIMEText(all_text, "html"))
        return msg

    def convert_plots_to_attachment(self, figure_name, figures):
        if not isinstance(figures, (list, tuple)):
            figures = [figures]
        with TemporaryDirectory() as temp_dir:
            dir_path = Path(str(temp_dir))
            file = dir_path / "plots.pdf"
            with PdfPages(file) as pdf_file:
                for figure in figures:
                    pdf_file.savefig(figure, dpi=300, bbox_inches="tight")
            self.attach_file(figure_name, file, "pdf")

    def attach_file(self, attachment_name, file, file_type):
        with file.open("rb") as f:
            attachment = MIMEApplication(f.read(), _subtype=file_type)
        attachment.add_header(
            "Content-Disposition", "attachment", filename=attachment_name
        )
        self.attachments.append(attachment)

    def add_image(self, figure_id, figure):
        with TemporaryDirectory() as temp_dir:
            dir_path = Path(str(temp_dir))
            file = dir_path / "image.png"
            figure.savefig(file, dpi=150, bbox_inches="tight")
            fp = open(file, "rb")
            try:
                attachment = MIMEImage(fp.read())
                attachment.add_header("Content-ID", "<%s>" % figure_id)
                attachment.add_header(
                    "Content-Disposition", "inline; filename=image.png"
                )
            except:
                pass
            fp.close()
        self.add_text(f'

')
        self.images.append(attachment)

    def add_text(self, text):
        self.text.append(text)


def max_squence(arr):
    #print(sum(listi))
    #return [sum(listi[n:n+4]) for n in listi[:-4]]
    list1 = []
    ss = list(enumerate(arr))
    print(ss)
    for i in ss[:-3]:
        #print(ss[i[0]][0])
        list1.append(ss[ss[i[0]][0]][1]+ss[ss[i[0]][0]+1][1]+ss[ss[i[0]][0]+2][1]+ss[ss[i[0]][0]+3][1])
    print(list1)
    return (max(list1))

print(max_squence([-2, 1, -3, 4, -1, 2, 1, -5, 4, 7, -10]))
#0 1 2 6 -3 2


import os

def get_input():
    inputfile = "./input/i" + os.path.basename(__file__)[0:2] + ".txt"
    data = []

    with open(inputfile, "r") as f:
        for line in f.readlines():
            if line == "\n":
                continue
            entry = line.strip("\n").split()
            data.append([entry[0], int(entry[1])])
    return data

def move(pos, dir):
    if dir == 'L' or dir == 'R':
        pos[0] += 1 if dir == 'R' else -1
    else:
        pos[1] += 1 if dir == 'D' else -1
    return pos

def adjust_t(head, tail):
    if abs(head[0] - tail[0]) > 1 or abs(head[1] - tail[1]) > 1:
        if head[0] == tail[0]:
            tail[1] += 1 if tail[1] < head[1] else -1
        elif head[1] == tail[1]:
            tail[0] += 1 if tail[0] < head[0] else -1
        else:
            tail[1] += 1 if tail[1] < head[1] else -1
            tail[0] += 1 if tail[0] < head[0] else -1
    return tail

if __name__ == "__main__":
    data = get_input()
    visited = set()

    knots = []
    for _ in range(0, 10):
        knots.append([0, 0])

    visited.add(tuple(knots[9]))
    for m in data:
        for _ in range(0, m[1]):
            knots[0] = move(knots[0], m[0])
            for i in range(0, 9):
                knots[i+1] = adjust_t(knots[i], knots[i+1])
            visited.add(tuple(knots[9]))
    print(len(visited))


import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="eigensheep",
    version="1.0.0",
    author="Kevin Kwok",
    author_email="antimatter15@gmail.com",
    description="Run Jupyter cells in AWS Lambda for massively parallel experimentation",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/antimatter15/eigensheep",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 2",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Development Status :: 3 - Alpha",
        "Framework :: Jupyter",
        "Topic :: Scientific/Engineering",
        "Intended Audience :: Science/Research",
        "Intended Audience :: Developers"
    ],
    install_requires=[
        'tqdm',
        'boto3',
        'ipython',
        'ipywidgets'
    ],
    extras_require={
        ':python_version == "2.7"': ['futures']
    }
)


import os
import logging

import click
import pickle
import pandas as pd

# LOGGING
log_format = logging.Formatter("%(asctime)s - [%(filename)s %(funcName)s] - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)  # create logger
logger.setLevel(logging.DEBUG)  # logger level
ch = logging.StreamHandler()  # console handler
ch.setFormatter(log_format)  # format
logger.addHandler(ch)

# DATA
TARGET = "condition"
# FILENAMES
DATA_FILENAME = "data.csv"
MODEL_FILENAME = "model.pkl"
PREDS_FILENAME = "predictions.csv"

@click.command("predict")
@click.option("--input-dir")
@click.option("--output-dir")
@click.option("--model-dir")
def predict(input_dir: str, output_dir: str, model_dir: str):
    logger.info("predicting")

    # is data exist?
    data_path = os.path.join(input_dir, DATA_FILENAME)
    if not os.path.exists(data_path):
        raise ValueError(f"data not found: {data_path}")
    logger.info(f"data exists: {data_path}")
    # is model exist?
    model_path = os.path.join(model_dir, MODEL_FILENAME)
    if not os.path.exists(model_path):
        raise ValueError(f"model not found: {model_path}")
    logger.info(f"model exist: {model_path}")

    # load data
    data = pd.read_csv(data_path)
    # load model
    with open(model_path, "rb") as file:
        model = pickle.load(file)
    # predict
    preds = model.predict(data)
    preds = pd.DataFrame({TARGET: preds})

    os.makedirs(output_dir, exist_ok=True)
    preds_dir = os.path.join(output_dir, PREDS_FILENAME)
    preds.to_csv(preds_dir)

    logger.info(f"predictions are ready: {preds_dir}")

if __name__ == '__main__':
    predict()


import os
import re
from ctypes import *
from FFxivPythonTrigger.memory.res import ntdll, kernel32
from FFxivPythonTrigger.memory.process import CURRENT_PROCESS_HANDLER

class SYSTEM_HANDLE(Structure):
    _fields_ = [
        ("ProcessId", c_ushort),
        ("CreatorBackTraceIndex", c_ushort),
        ("ObjectTypeIndex", c_byte),
        ("HandleAttributes", c_byte),
        ("HandleValue", c_ushort),
        ("Object", c_void_p),
        ("AccessMask", c_ulong),
    ]

def close_mutex():
    require_length = c_ulong(0)
    nt_status = ntdll.NtQuerySystemInformation(16, 0, 0, byref(require_length))
    while nt_status == 0xC0000004:
        buffer = (c_ubyte * require_length.value)()
        nt_status = ntdll.NtQuerySystemInformation(16, buffer, require_length, byref(require_length))
    if nt_status != 0:
        raise Exception("NtQuerySystemInformation failed with status code: 0x{:08X}".format(nt_status))

    handle_count = cast(buffer, POINTER(c_int64))[0]
    handles = cast(cast(buffer, c_void_p).value + 8, POINTER(SYSTEM_HANDLE * handle_count))[0]
    cnt = 0
    for handle in handles:
        if handle.ProcessId != os.getpid(): continue
        duplicate_handle = c_void_p()
        if not kernel32.DuplicateHandle(
                CURRENT_PROCESS_HANDLER,
                handle.HandleValue,
                CURRENT_PROCESS_HANDLER,
                byref(duplicate_handle),
                0, False, 2
        ): continue
        require_length = c_ulong(1024)
        buffer_2 = (c_ubyte * require_length.value)()
        nt_status = ntdll.NtQueryObject(duplicate_handle, 1, buffer_2, require_length, byref(require_length))
        if nt_status != 0: continue
        name = bytes(buffer_2[16:]).decode('utf16', 'ignore').rstrip('\0')
        if re.search(r'6AA83AB5-BAC4-4a36-9F66-A309770760CB_ffxiv_game\d+', name):
            kernel32.CloseHandle(handle.HandleValue)
            cnt += 1
        kernel32.CloseHandle(duplicate_handle)
    return cnt


from .categories import create_category, get_user_categories
from .get_transactions import get_user_transactions
from .session import get_csrf_token, save_user_session_key

__all__ = [
    'save_user_session_key',
    'get_user_transactions',
    'get_user_categories',
    'create_category',
    'get_csrf_token',
]


"""
스마트폰 다이얼 키는 아래와 같다
1 2 3
4 5 6
7 8 9
* 0 #

이 키패드에서 왼손과 오른손의 엄지손가락만을 이용할 것이며,
1,4,7,*을 누를 땐 왼손 엄지손가락 /  3,6,9,# 을 누를 땐 오른손 엄지손가락만을 이용한다.
그 외인 2,5,8,0 을 누를 땐 가깝게 위치한 손가락으로 누른다.
이때 거리는, 칸을 기준으로 계산한다 (대각선 x)
거리가 같다면 오른손잡이인지 왼손잡이인지로 나눈다
입력 매개변수 numbers: 누를 키패드 정보, hand: 왼손잡이?오른손잡이?
"""

#나의 풀이

def solution(numbers,hand):

    keypad=[[1,2,3],[4,5,6],[7,8,9],[10,0,10]] #2차원 배열을 통해 접근한다
    answer=""
    l=(3,0) # 왼손 엄지손가락의 시작 위치는 * 이다
    r=(3,2) #오른손 엄지손가락의 시작 위치는 # 이다
    if hand=="right": hand="R" # 밑에 코드를 위해서 바꿔준다
    if hand=="left": hand="L"

    for n in numbers:
        # 누를 키패드 번호의 위치를 파악한다
        willPress=list((i,j) for i in range(len(keypad)) for j in range(len(keypad[i])) if keypad[i][j]==n)[0] #list없이 출력하면 값이 나오지 않는다.
        # 리스트 컴프리헨션으로, 리스트로 감싸줘야 한다. 이때 i와 j를 튜플 하나로 묶어줬기 때문에(원소 하나), 결과적으로 list((i,j))[0]을 출력하면 튜플이 나오는 것이다. [(0,1)][0]=(0,1)

        if n in [1,4,7]: # 거리와 상관 없이 왼손 엄지손가락으로 누르는 경우
            answer+="L"
            l=willPress
        if n in [3,6,9]: # 거리와 상관 없이 오른손 엄지손가락으로 누르는 경우
            answer+="R"
            r=willPress
        if n in [2,5,8,0]: #2,5,8,0을 눌러야 할 때 (거리를 따져야 할 때)
            if answer=="" and hand=="R":
                answer+="R" #아직 빈 배열이라면? 오른손잡이인 경우
                r=willPress
                continue
            if answer=="" and hand=="L":
                answer+="L" #아직 빈 배열이라면? 왼손잡이인 경우
                l=willPress
                continue # 밑의 연산이 진행되면 안 된다
            """
            생각해보니 빈 배열을 고려하는 건 불필요한 코드이다. 왜냐하면 시작 위치를 for문 밖에서 지정해줬기 때문이다
            """

            # 빈 배열이 아닐 때(이전에 키패드를 누른 경험이 있음)
            if abs(willPress[0]-l[0])+abs(willPress[1]-l[1])>abs(willPress[0]-r[0])+abs(willPress[1]-r[1]):  # 오른손이 더 가까울 때 (=오른쪽의 거리가 더 짧을 때)
                answer+="R"
                r=willPress
            if abs(willPress[0]-l[0])+abs(willPress[1]-l[1])<abs(willPress[0]-r[0])+abs(willPress[1]-r[1]): #왼손이 더 가까울 때
                answer+="L"
                l=willPress
            if abs(willPress[0]-l[0])+abs(willPress[1]-l[1])==abs(willPress[0]-r[0])+abs(willPress[1]-r[1]): #왼손과 오른손 각각 거리가 같을 때
                answer+=hand # right를 R, left를 l로 바꾼 이유이다
                if hand=="R":
                    r=willPress
                if hand=="L":
                    l=willPress

    return answer

"""
    테스트 1 〉	통과 (0.01ms, 10.2MB)
    테스트 2 〉	통과 (0.01ms, 10.2MB)
    테스트 3 〉	통과 (0.01ms, 10.2MB)
    테스트 4 〉	통과 (0.01ms, 10.3MB)
    테스트 5 〉	통과 (0.01ms, 10.4MB)
    테스트 6 〉	통과 (0.02ms, 10.2MB)
    테스트 7 〉	통과 (0.04ms, 10.2MB)
    테스트 8 〉	통과 (0.07ms, 10.3MB)
    테스트 9 〉	통과 (0.06ms, 10.2MB)
    테스트 10 〉	통과 (0.06ms, 10.2MB)
    테스트 11 〉	통과 (0.15ms, 10.3MB)
    테스트 12 〉	통과 (0.13ms, 10.3MB)
    테스트 13 〉	통과 (0.27ms, 10.3MB)
    테스트 14 〉	통과 (0.56ms, 10.4MB)
    테스트 15 〉	통과 (1.39ms, 10.2MB)
    테스트 16 〉	통과 (1.41ms, 10.2MB)
    테스트 17 〉	통과 (2.69ms, 10.2MB)
    테스트 18 〉	통과 (2.55ms, 10.4MB)
    테스트 19 〉	통과 (2.68ms, 10.2MB)
    테스트 20 〉	통과 (2.63ms, 10.3MB)
"""

키패드 누르기_2020카카오.py


import matplotlib.pyplot as plt
import numpy as np
import math
import random

class Part2:
    def __init__(self, t=50, y=0.7, separation=25, n=50, chi_squared=13.09051):
        # CONST
        self.T = t
        self.Y = y
        self.SEPARATION = separation
        self.N = n
        self.CHI_SQUARED = chi_squared
        # VARS
        self.x = np.arange(0, self.T, 0.1)
        self.y = [0] * self.T * 10
        self.separateY = [-1, 1]
        self.separateX = np.arange(0, self.T, self.T / self.SEPARATION)
        # Computing vars
        self.flow = self.flows2flow(self.generate())
        [self.countInRange, self.uniqueList] = self.catch_in_interval()
        self.lambda_t = sum(self.flow) / sum(self.countInRange)
        self.theoreticalN = self.theoretical()

    # Генерим из первой части 50 потоков
    def generate(self):
        iterations = []

        for i in range(0, self.T):
            t = 0
            i = 0
            times = []
            while t < self.T:
                y = random.uniform(0, 1)
                x = math.log((1 - y), math.e) / (-self.Y)
                u = x
                t += u
                i += 1

                if t < self.T:
                    rounded_t = round(t, 1)
                    if rounded_t not in times:
                        times.append(rounded_t)

            iterations.append(times)

        return iterations

    # Картинка
    def figure(self):
        plt.plot(self.x, self.y)
        for sepX in self.separateX:
            plt.plot([sepX] * 2, self.separateY)

        plt.margins(0, 5)
        plt.ylabel('y')
        plt.xlabel('x')

        plt.plot(self.flow, [0] * len(self.flow), 'ro', markersize=2)
        plt.show()

    # Получаем количество попаданий в интервал
    def catch_in_interval(self):
        # Левая границы
        left = 0
        # Правая границы
        right = left + self.T / self.SEPARATION
        # Уникальные
        u = None
        # Число попаданий
        c = []

        for i in range(0, self.SEPARATION):
            c.append(len(list(filter(lambda x: left < x < right, self.flow))))
            u = list(range(0, 10))

            # Переход к следующему отрезку
            # левая стала правой
            left = right
            # Правая
            right = left + self.T / self.SEPARATION

            self.flow[:] = [f / 10 for f in self.flow]

        return [c, u]

    # Все в один поток
    @staticmethod
    def flows2flow(iterations):
        a = []
        for x in iterations:
            a += x
        return a

    # Получаем n теоритическое
    def theoretical(self):
        n_theories = []
        n_sum = sum(self.countInRange)

        for n in self.uniqueList:
            p = pow(self.lambda_t, n) / math.factorial(n) * pow(math.e, -self.lambda_t)
            n_theories.append(p * n_sum)

        self.uniqueList[:] = [n - n / self.SEPARATION for n in n_theories]
        return n_theories

    # Получаем хи квадрат
    def chi_squared(self):
        chi = 0
        for count, n in zip(self.uniqueList, self.theoreticalN):
            chi += pow((count - n), 2) / n
        return chi

    def hypothesis(self):
        return self.chi_squared() < self.CHI_SQUARED

laba3 = Part2()
# print(laba3.flow)
print('lambda теориритическое: ' + str(laba3.lambda_t))
print('N теоритическое: ' + str(laba3.theoreticalN))
print('Хи квадрат: ' + str(laba3.chi_squared()))
if laba3.hypothesis():
    print('Гипотеза о пуассоновском потоке принимается')
else:
    print('Гипотеза о пуассоновском потоке отвергается')
laba3.figure()


"""
Solution for Instant Insanity puzzle - https://en.wikipedia.org/wiki/Instant_Insanity
"""

from enum import Enum, auto

class Faces(Enum):
    TOP = auto()
    LEFT = auto()
    BACK = auto()
    RIGHT = auto()
    FRONT = auto()
    BOTTOM = auto()

    def rotate_faces(self, face_list):
        rotated_faces = []
        rotated_faces.extend(face_list)
        return rotated_faces

    def face_permutations(self):
        fp = []
        orig = list(Faces)
        # Keep top and bottom same
        fp.extend(self.rotate_faces(orig))
        # Flip top and bottom
        # Move left to top
        # Move right to top
        # Move front to top
        # Move back to top
        return fp

Color = Enum('Color', ['RED', 'YELLOW', 'GREEN', 'BLUE'])

def find_orientations(cube):
    orientations = []
    fp = Faces.face_permutations()
    # for p in fp:
    #
    return orientations

print(dir(Color))
print(dir(Faces))

cubes = [dict(zip(list(Faces), [Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.RED, Color.BLUE])),
         dict(zip(list(Faces), [Color.RED, Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.GREEN])),
         dict(zip(list(Faces), [Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.YELLOW])),
         dict(zip(list(Faces), [Color.RED, Color.BLUE, Color.YELLOW, Color.YELLOW, Color.GREEN, Color.GREEN]))]
print(cubes)

for d in cubes:
    cube_colors = [(f.name, c.name) for f, c in d.items()]
    print(cube_colors)

print(list(Faces))
print(Faces(1))


import pyttsx3
import PyPDF2

book = open('sql.pdf', 'rb')
audio = pyttsx3.init()
pdfReader = PyPDF2.PdfFileReader(book)

total_pages = pdfReader.numPages
print(total_pages)

for page in range(total_pages):
    page = pdfReader.getPage(page)
    text = page.extractText()
    audio.say(text)
    audio.runAndWait()


"""
Common gamedata utilities
"""

import logging

import mlbv.mlbam.common.config as config
import mlbv.mlbam.common.util as util

LOG = logging.getLogger(__name__)

def get_feedtype_keystring(feedtype_map):
    reverse_list = list()
    for longkey in feedtype_map:
        reverse_list.append("{}:{}".format(feedtype_map[longkey], longkey))
    return ", ".join(reverse_list)

def convert_feedtype_to_short(feedtype, feedtype_map):
    if feedtype in feedtype_map:
        return feedtype_map[feedtype]
    return feedtype

def convert_to_long_feedtype(feed, feedtype_map):
    if feed in feedtype_map:
        return feed
    for feedtype in feedtype_map:
        if feedtype_map[feedtype] == feed:
            return feedtype
    return feed

def is_fav(game_rec):
    if "favourite" in game_rec:
        return game_rec["favourite"]
    if config.CONFIG.parser["favs"] is None or config.CONFIG.parser["favs"] == "":
        return False
    for fav in util.get_csv_list(config.CONFIG.parser["favs"]):
        if fav in (game_rec["away"]["abbrev"], game_rec["home"]["abbrev"]):
            return True
    return False

def apply_filter(game_rec, arg_filter, filters=None):
    """Returns the game_rec if the game matches the filter, or if no filtering is active."""
    if arg_filter == "favs":
        arg_filter = config.CONFIG.parser["favs"]
    elif filters and arg_filter in filters:
        arg_filter = filters[arg_filter]
    elif not arg_filter:
        return game_rec

    # apply the filter
    for team in util.get_csv_list(arg_filter):
        if team in (game_rec["away"]["abbrev"], game_rec["home"]["abbrev"]):
            return game_rec

    # no match
    return None


#Please refer to the README File for the full formulas and explanation

import time #To Calculate the execution time
import numpy as np #To deal with Math
import pandas as pd #To handle the data's part
import scipy.optimize as opt

strt = time.time() #Calculate the time

#------------------------------------------------------------

def sigmoid(z):
    return 1/(1+np.exp(-z) )

#------------------------------------------------------------

def costfunc(thetas,x,y):

    thetas = np.matrix(thetas)
    x = np.matrix(x)
    y = np.matrix(y)

    first = np.multiply( -y ,np.log( sigmoid( np.dot(x, thetas.T) )  )   )
    second = np.multiply( (1-y)  , np.log(  1 - ( sigmoid( np.dot(x, thetas.T) )  )   )  )
    c = np.sum( first - second ) / len(x)

    return c

#------------------------------------------------------------

def Gradientdes( thetas, x, y):

    thetas = np.matrix(thetas)
    x = np.matrix(x)
    y = np.matrix(y)

    parameters = int(thetas.ravel().shape[1])

    grd =  np.zeros(parameters)
    pred = sigmoid( x.dot( thetas.T ) )

    for e in range(parameters):

         term = np.multiply( ( pred - y) ,x[: , e] )
         grd[e] =  ( 1/len(x) )     *   np.sum(term)

    return grd

#------------------------------------------------------------

def predc(thetas,x):
    classif = sigmoid( x * thetas.T )
    e = [ 1 if i >= 0.5 else 0 for i in classif ]
    return e

#------------------------------------------------------------

#Import the Dataset file, The txt file
datas = pd.read_csv(r'C:\Users\NADY\Desktop\dsc.txt', header = None , names=['Xdata0','Xdata1','Ydata'] ) #Write your path here

datas.insert(0,'Ones',1)

#We have the data, So, I want to choose specific columns
cols = datas.shape[1]
x = datas.iloc[:,0:cols-1]
y = datas.iloc[:,cols-1:cols]

x = np.array(x.values)
y = np.array(y.values)
thetas =np.zeros( x.shape[1] )

#--------------------

print('\n The Cost Function before optimization',costfunc(thetas, x, y),'\n')

results = opt.fmin_tnc(func = costfunc, x0 = thetas , fprime= Gradientdes, args=(x,y)  )
print(results)

#--------------------

endt = time.time()

costafteropti = costfunc(results[0], x, y)
print('\nThe Cost Function before optimization\n',costafteropti)

newvalues = predc( np.matrix( results[0] ) , x)
print( '\nThe Expected Values \n', newvalues,'\n' )

#--------------------

correctansrs = [ 1 if (a == 1 and b == 1) or (a == 0 and b == 0) else 0 for (a,b) in zip(y,newvalues)]
print('The Correct Answers are 1 wrong are 0\n',correctansrs)

accuracy = (sum(correctansrs) * 100 )/len(correctansrs)

print( f'\nacc =  {accuracy}% \n' )

print(f'\nThe Execution Time is : {endt-strt} Seconds' )


# packing & unpacking ex

"""
패킹은 인자로 받은 여러개의 값을 하나의 객체로 합쳐서 받을 수 있도록 한다.
1. tuple 형태 = 위치인자 패킹 * 한개를 매개변수 앞에 붙여서 사용한다.
2. dictionary 형태 = 위치인자 패킹 ** 두개를 매개변수 앞에 붙여서 사용한다.

언패킹은 여러개의 객체를 포함하고 있는 하나의 객체를 풀어준다.
동일하게 위치인자를 unpacking 하는 경우는 * 를, 키워드인자를 unpacking하는 경우 ** 를 사용# 다.
"""

# 이런식으로 매개변수 앞에 * 하나를 붙이면 매개변수로 보낸 모든 객체들을 하나의 객체로 관리한다.
def func(*args):
    print(args)
    print(type(args))

# (1, 2, 3, 4, 5, 6, 'a', 'b')
# <class 'tuple'>
func(1, 2, 3, 4, 5, 6, 'a', 'b')

def kwpacking(**kwargs):
    print(kwargs)
    print(type(kwargs))

# {'a': 1, 'b': 2, 'c': 3}
# <class 'dict'>
kwpacking(a=1, b=2, c=3)

# unpacking

def sum(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
# sum(numbers) # error

# [1, 2, 3]을 인자로 보낼때, *을 붙이면 unpacking이 발생 한다.
print(sum(*numbers))

# unpacking 순서
"""
1. sum(*numbers)
2. sum(*[1, 2, 3])
3. sum(1, 2, 3)
"""

# 위치인자를 unpacking 할때는 위에 예에서는 list 타입이였지만, Container 객체라면 다 가능하다.
# set타입과 dict타입은 순서정보를 가지고 있지 않기 때문에 결과가 다를 수 있다.
sum(*'abc') # 'abc'
sum(*(4, 5, 6)) # 15
sum(*{'가', '나', '다'}) # '나다가'
sum(*{'치킨': 3, '피자': 12, '음료수': 10}) # '치킨피자음료수'

# 동일한 방식으로 키워드인자로 unpacking 할 수 있습니다. unpacking 하기 위해서는
# 인자가 key 와 인자로 구성되어 있는 mapping 타입, 즉 dict 가 필요하다.
def cal(first, op, second):
    if op == '+':
        return first + second
    if op == '/':
        return first / second
    if op == '-':
        return first - second
    if op == '*':
        return first * second

prob = {
  'first': 12,
  'second': 34,
  'op': '*'
}

cal(**prob) # 결과 : 408

# unpack 동작

"""
1. cal(**prob)
2. cal(prob = {
  'first': 12,
  'second': 34,
  'op': '*'
})
3. cal(first=12, second=34, op='*')
"""

# 만약 비어있는 인자를 unpacking를 하면 무시한다.
# 이러한 특성이 있기 때문에 함수의 packing과 unpacking을 이용하여,
# 다음과 같이 어떠한 함수에도 반응하는 함수를 작성할 수 있다.

# 함수와 함수에 인자들을 받아서 시작전 알림과 함께 함수를 실행시켜주는 함수
def start(func, *args, **kwargs):
    print("함수를 시작")
    return func(*args, **kwargs)

# 실행할 함수를 인자로 받고, 그 함수를 실행할 때 넣을 위치인자와 키워드인자를 넣는다.
start(print, '안녕하세요', '파이썬 꿀잼!', sep='~~ ')


# --------------
# Code starts here
# Create the lists
class_1 = ['Geoffrey Hinton','Andrew Ng','Sebastian Raschka','Yoshua Bengio']
class_2 = ['Hilary Mason','Carla Gentry','Corinna Cortes']

# Concatenate both the strings
new_class = class_1 + class_2
print("New Class: ", new_class, end='\n')

# Append the list
new_class.append('Peter Warden')

# Print updated list
print("After Adding Peter: ", new_class, end='\n')

# Remove the element from the list
new_class.remove('Carla Gentry')

# Print the list
print("After Removing Carla: ", new_class, end='\n')

# Create the Dictionary for Geoffrey Hinton
courses={'Math':65,'English':70,'History':80,'French':70,'Science':60}
print("Marks Obtained by Geoffrey Hinton: ", courses, end='\n')

# Slice the dict and stores  the all subjects marks in variable
math = courses['Math']
english = courses['English']
history = courses['History']
french = courses['French']
science = courses['Science']

# Store the all the subject in one variable `Total`
total = sum(courses.values())

# Print the total
print("Total Marks of Geoffrey Hinton: ", total, end='\n')

# Insert percentage formula
percentage = ( total * 100 ) / 500

# Print the percentage
print("Percentage of Geoffrey Hinton: ", percentage, end='\n')

# Create the Dictionary
mathematics={'Geoffrey Hinton':78,'Andrew Ng':95,'Sebastian Raschka':65,'Yoshua Benjio':50,'Hilary Mason':70,'Corrina Cortes':66,'Peter Wrden':75}

# Given string
max_marks_scored = max(mathematics.values())
print ("Maximum Marks in Mathematics: ", max_marks_scored, end='\n')

# topper = list(mathematics.keys())[list(mathematics.values()).index(max_marks_scored)]
topper = max(mathematics, key = mathematics.get)
print("Topper in Mathematics: ", topper, end='\n')

# Create variable first_name
first_name = topper.split()[0]

# Create variable Last_name and store last two element in the list
last_name = topper.split()[-1]

# Concatenate the string
full_name = last_name + " " + first_name

# print the full_name

print("Full Name of Topper: ", full_name, end='\n')
# print the name in upper case
certificate_name = full_name.upper()
print("Certificate Name of Topper: ", certificate_name, end='\n')

# Code ends here


def get_bmi(name, weight, height):
    bmi = weight / pow(height * 0.01, 2)

    print("BMI is", format(bmi, ".2f"))

    print(name, "is", end=' ')

    if bmi < 18.5:
        print("Underweight")
    elif bmi < 25:
        print("Normal")
    elif bmi < 30:
        print("Overweight")
    else:
        print("Obese")

name = input("Enter Name: ")
weight = float(input("Enter weight in Kg: "))
height = float(input("Enter height in cm: "))

get_bmi(name, weight, height)


import logging

import flask
from flask import Flask, render_template, json

from classes.iso3166 import ISO3166

app = Flask(__name__)

app.config.update(
    DEBUG=True,
    SERVER_NAME="isoapi.com:5000"
)

@app.route('/')
@app.route('/<name>')
def hello_world(name=None):
    return render_template('hello.html', name=name)

"""
For subdomains
"""
headers_get = {
    'Content-Type' : 'application/json;charset=utf-8',
    'Access-Control-Allow-Origin' : '*',
    'Access-Control-Allow-Methods' : 'GET',
    'Access-Control-Allow-Headers' : 'Accept, X-Requested-With'
}

resp = flask.Response()
resp.headers = headers_get

@app.route('/', subdomain="api")
def hello_api():
    return "Hello API"

@app.route('/iso3166/all', subdomain="api")
def get_iso3166_all():
    iso3166 = ISO3166()
    resp.data = json.dumps(iso3166.countries)
    return resp

@app.route('/iso3166/alpha2/<alpha2>', subdomain='api')
def get_iso3166_by_alpha2(alpha2):
    iso3166 = ISO3166()
    resp.data = json.dumps(iso3166.filter_by_alpha2(alpha2))
    return resp

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser(description='Development Server Help')
    parser.add_argument("-d", "--debug", action="store_true", dest="debug_mode",
                        help="run in debug mode (for use with PyCharm)", default=False)
    parser.add_argument("-p", "--port", dest="port",
                        help="port of server (default:%(default)s)", type=int, default=5000)

    cmd_args = parser.parse_args()
    app_options = {"port": cmd_args.port}

    if cmd_args.debug_mode:
        app_options["debug"] = True
        app_options["use_debugger"] = False
        app_options["use_reloader"] = False

    app.run(**app_options)