#$Id$

from decimal import Decimal
_d100 = Decimal(100)
#def Procent(x): return Decimal(x) / _d100

#table = [   #ot     #min    #% gornicata
#            (0,        0,    0 ), #lambda dohod: 0 ),
#            (180,      0,   20 ), #lambda dohod: Procent(20)*(dohod-180) ),
#            (600,     80,   24 ), #lambda dohod: 80 + Procent(24)*(dohod-600) ),
#        ]

def _dod( dohod, table):
    last = None
    for row in table:
        if dohod < row[0]: break
        last = row
    return last[1] + last[2]/_d100 * ( dohod - last[0])

# vim:ts=4:sw=4:expandtab


from random import choices
import numpy as np
import matplotlib.pyplot as plt

class Transition:
    def __init__(self, state, action, reward, next_state):
        self.state = state
        self.action = action
        self.reward = reward
        self.next_state = next_state

        self.next_transition = None

class ReplayBuffer:
    def __init__(
        self,
        env,
        epsilon_decay,
        n_expert_trajectories,
        expert_policy,
        n_step_td,
        prioritized_buffer,
        weight_occurencies,
        prioritized_replay_rl_exploration=0.001,
        prioritized_replay_expert_exploration=1,
        prioritized_replay_exponent=0.4,
        importance_sampling=0.6,
    ):
        self.env = env
        self.epsilon_decay = epsilon_decay

        self.buffer_expert = []
        self.buffer_rl = []

        if n_expert_trajectories > 0:  # i.e with Demonstration
            self.collect_expert_trajectories(n_expert_trajectories, expert_policy)

        self.n_sted_td = n_step_td
        self.prioritized_buffer = prioritized_buffer
        self.weight_occurencies = weight_occurencies
        self.prioritized_replay_expert_exploration = prioritized_replay_expert_exploration
        self.prioritized_replay_rl_exploration = prioritized_replay_rl_exploration
        self.prioritized_replay_exponent = prioritized_replay_exponent
        self.importance_sampling = importance_sampling

        self.last_collected_transition = None
        self.last_sampled_transition = None

        self.intial_state_collected = False

        self.td_losses = [[None for _ in range(self.env.A)] for _ in range(self.env.S)]

    def collect_expert_trajectories(self, n_trajectories, policy):
        for idx_sample in range(n_trajectories):
            self.env.state = choices(self.env._states)[0]
            if self.env.state == self.env.initial_state_distribution:
                self.intial_state_collected = True

            first_transition = True
            terminal = False

            while not terminal:
                action = policy[self.env.state]
                state = self.env.state

                next_state, reward, terminal, _ = self.env.step(action)

                self.buffer_expert.append(Transition(state, action, reward, next_state))

                if not first_transition:
                    self.buffer_expert[-2].next_transition = self.buffer_expert[-1]

                first_transition = False

    def collect_rl_transition(self, Q):
        if self.last_collected_transition is None:
            self.env.state = choices(self.env._states)[0]
            if not self.intial_state_collected:
                self.env.state = self.env.initial_state_distribution
                self.intial_state_collected = True

        state = self.env.state

        if np.random.random() < self.epsilon_decay(len(self.buffer_rl) + len(self.buffer_expert)):
            action = np.random.choice(self.env._actions)
        else:
            action = np.argmax([Q[state, action] for action in self.env._actions])

        next_state, reward, terminal, _ = self.env.step(action)

        self.buffer_rl.append(Transition(state, action, reward, next_state))

        if self.last_collected_transition is not None:
            self.buffer_rl[-2].next_transition = self.buffer_rl[-1]

        if not terminal:
            self.last_collected_transition = self.buffer_rl[-1]
        else:
            self.last_collected_transition = None

    def sample_a_transition(self):
        if self.prioritized_buffer:
            list_td_losses = []
            number_occurences = np.zeros((self.env.S, self.env.A))

            for transition in self.buffer_expert:
                number_occurences[transition.state, transition.action] += 1
                if self.td_losses[transition.state][transition.action] is None:
                    list_td_losses.append(None)
                else:
                    list_td_losses.append(
                        (
                            np.abs(self.td_losses[transition.state][transition.action])
                            + self.prioritized_replay_expert_exploration
                        )
                        ** self.prioritized_replay_exponent
                    )

            for transition in self.buffer_rl:
                number_occurences[transition.state, transition.action] += 1
                if self.td_losses[transition.state][transition.action] is None:
                    list_td_losses.append(None)
                else:
                    list_td_losses.append(
                        (
                            np.abs(self.td_losses[transition.state][transition.action])
                            + self.prioritized_replay_rl_exploration
                        )
                        ** self.prioritized_replay_exponent
                    )

            td_losses_array = np.array(list_td_losses)
            max_td_losses = np.amax(td_losses_array, where=td_losses_array != None, initial=1)
            probabilities = np.where(
                td_losses_array == None, max_td_losses + 10, td_losses_array
            )  # +10 to force sampling the samples that were never visited.

            # Divide by the number of occurencies
            if self.weight_occurencies:
                for idx_transition, transition in enumerate(self.buffer_expert + self.buffer_rl):
                    probabilities[idx_transition] /= number_occurences[transition.state, transition.action]

            probabilities /= np.sum(probabilities)
        else:
            probabilities = np.ones(len(self.buffer_expert) + len(self.buffer_rl)) / (
                len(self.buffer_expert) + len(self.buffer_rl)
            )

        idx_transition = choices(range(len(probabilities)), probabilities)[0]

        if idx_transition < len(self.buffer_expert):
            return (
                self.buffer_expert[idx_transition],
                True,
                1 / (len(probabilities) * probabilities[idx_transition]) ** self.importance_sampling,
            )
        else:
            return (
                self.buffer_rl[idx_transition - len(self.buffer_expert)],
                False,
                1 / (len(probabilities) * probabilities[idx_transition]) ** self.importance_sampling,
            )

    def sample_n_transitions(self):
        first_transition, is_expert, weight = self.sample_a_transition()

        self.last_sampled_transition = first_transition
        transitions = [first_transition]
        n_transition = 1

        while n_transition < self.n_sted_td and not transitions[-1].next_transition is None:
            transitions.append(transitions[-1].next_transition)
            n_transition += 1

        return transitions, is_expert, weight

    def display_statistics(self, transitions):
        number_occurences = np.zeros(self.env.S)

        for transition in transitions:
            number_occurences[transition.state] += 1

        img = self.env.get_layout_img(number_occurences)
        plt.figure()
        plt.title("Statistics on occurences")
        plt.imshow(img)
        plt.show()

    def display_rl_statistics(self):
        number_occurences = np.zeros(self.env.S)

        for transition in self.buffer_rl:
            number_occurences[transition.state] += 1

        print("Max occurences", np.max(number_occurences))
        img = self.env.get_layout_img(number_occurences)
        plt.figure()
        plt.title("Statistics on rl occurences")
        plt.imshow(img)
        plt.show()


"""
This is a Python3 PyQt5 firmware upload GUI for the SparkFun RTK products - based on ESP32 esptool.exe

MIT license

Please see the LICENSE.md for more details

"""

# import action things - the .syntax is used since these are part of the package
from .au_worker import AUxWorker
from .au_action import AxJob
from .au_act_esptool import AUxEsptoolDetectFlash, AUxEsptoolUploadFirmware, AUxEsptoolResetESP32

import darkdetect
import sys
import os
import os.path
import platform

import serial

from time import sleep

from typing import Iterator, Tuple

from PyQt5.QtCore import QSettings, QProcess, QTimer, Qt, QIODevice, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtWidgets import QWidget, QLabel, QComboBox, QGridLayout, \
    QPushButton, QApplication, QLineEdit, QFileDialog, QPlainTextEdit, \
    QAction, QActionGroup, QMenu, QMenuBar, QMainWindow, QMessageBox
from PyQt5.QtGui import QCloseEvent, QTextCursor, QIcon, QFont
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo

_APP_NAME = "RTK Firmware Uploader"

# sub folder for our resource files
_RESOURCE_DIRECTORY = "resource"

#https://stackoverflow.com/a/50914550
def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, _RESOURCE_DIRECTORY, relative_path)

def get_version(rel_path: str) -> str:
    try:
        with open(resource_path(rel_path), encoding='utf-8') as fp:
            for line in fp.read().splitlines():
                if line.startswith("__version__"):
                    delim = '"' if '"' in line else "'"
                    return line.split(delim)[1]
            raise RuntimeError("Unable to find version string.")
    except:
        raise RuntimeError("Unable to find _version.py.")

_APP_VERSION = get_version("_version.py")

# ----------------------------------------------------------------
# hack to know when a combobox menu is being shown. Helpful if contents
# of list are dynamic -- like serial ports.

class AUxComboBox(QComboBox):

    popupAboutToBeShown = pyqtSignal()

    def showPopup(self):
        self.popupAboutToBeShown.emit()
        super().showPopup()

#----------------------------------------------------------------
# ux_is_darkmode()
#
# Helpful function used during setup to determine if the Ux is in
# dark mode
_is_darkmode = None
def ux_is_darkmode() -> bool:
    global _is_darkmode

    if _is_darkmode is not None:
        return _is_darkmode

    osName = platform.system()

    if osName == "Darwin":
        _is_darkmode = darkdetect.isDark()

    elif osName == "Windows":
        # it appears that the Qt interface on Windows doesn't apply DarkMode
        # So, just keep it light
        _is_darkmode = False
    elif osName == "Linux":
        # Need to check this on Linux at some pont
        _is_darkmod = False

    else:
        _is_darkmode = False

    return _is_darkmode

# Setting constants
SETTING_PORT_NAME = 'port_name'
SETTING_FILE_LOCATION = 'file_location'
#SETTING_PARTITION_LOCATION = 'partition_location'
SETTING_BAUD_RATE = 'baud'

def gen_serial_ports() -> Iterator[Tuple[str, str, str]]:
    """Return all available serial ports."""
    ports = QSerialPortInfo.availablePorts()
    return ((p.description(), p.portName(), p.systemLocation()) for p in ports)

# noinspection PyArgumentList

class MainWidget(QWidget):
    """Main Widget."""

    sig_message = pyqtSignal(str)
    sig_finished = pyqtSignal(int, str, int)

    def __init__(self, parent: QWidget = None) -> None:
        super().__init__(parent)

        self.flashSize = 0

        # File location line edit
        self.file_label = QLabel(self.tr('Firmware File:'))
        self.fileLocation_lineedit = QLineEdit()
        self.file_label.setBuddy(self.fileLocation_lineedit)
        self.fileLocation_lineedit.setEnabled(False)
        self.fileLocation_lineedit.returnPressed.connect(self.on_browse_btn_pressed)

        # Browse for new file button
        self.browse_btn = QPushButton(self.tr('Browse'))
        self.browse_btn.setEnabled(True)
        self.browse_btn.pressed.connect(self.on_browse_btn_pressed)

        # # Partition file location line edit
        # self.partition_label = QLabel(self.tr('Partition File:'))
        # self.partitionFileLocation_lineedit = QLineEdit()
        # self.partition_label.setBuddy(self.partitionFileLocation_lineedit)
        # self.partitionFileLocation_lineedit.setEnabled(False)
        # self.partitionFileLocation_lineedit.returnPressed.connect(self.on_partition_browse_btn_pressed)

        # # Browse for new file button
        # self.partition_browse_btn = QPushButton(self.tr('Browse'))
        # self.partition_browse_btn.setEnabled(True)
        # self.partition_browse_btn.pressed.connect(self.on_partition_browse_btn_pressed)

        # Port Combobox
        self.port_label = QLabel(self.tr('COM Port:'))
        self.port_combobox = AUxComboBox()
        self.port_label.setBuddy(self.port_combobox)
        self.update_com_ports()
        self.port_combobox.popupAboutToBeShown.connect(self.on_port_combobox)

        # Reset Button
        self.reset_btn = QPushButton(self.tr('Reset ESP32'))
        self.reset_btn.clicked.connect(self.tera_term_reset)

        # Baudrate Combobox
        self.baud_label = QLabel(self.tr('Baud Rate:'))
        self.baud_combobox = QComboBox()
        self.baud_label.setBuddy(self.baud_combobox)
        self.update_baud_rates()

        # Upload Button
        myFont=QFont()
        myFont.setBold(True)
        self.upload_btn = QPushButton(self.tr('  Upload Firmware  '))
        self.upload_btn.setFont(myFont)
        self.upload_btn.clicked.connect(self.on_upload_btn_pressed)

        # Messages Bar
        self.messages_label = QLabel(self.tr('Status / Warnings:'))

        # Messages Window
        self.messageBox = QPlainTextEdit()
        color =  "C0C0C0" if ux_is_darkmode() else "424242"
        self.messageBox.setStyleSheet("QPlainTextEdit { color: #" + color + ";}")
        self.messageBox.setReadOnly(True)
        self.messageBox.clear()

        # Arrange Layout
        layout = QGridLayout()

        layout.addWidget(self.file_label, 1, 0)
        layout.addWidget(self.fileLocation_lineedit, 1, 1)
        layout.addWidget(self.browse_btn, 1, 2)

        # layout.addWidget(self.partition_label, 2, 0)
        # layout.addWidget(self.partitionFileLocation_lineedit, 2, 1)
        # layout.addWidget(self.partition_browse_btn, 2, 2)

        layout.addWidget(self.port_label, 2, 0)
        layout.addWidget(self.port_combobox, 2, 1)
        layout.addWidget(self.reset_btn, 2, 2)

        layout.addWidget(self.baud_label, 3, 0)
        layout.addWidget(self.baud_combobox, 3, 1)
        layout.addWidget(self.upload_btn, 3, 2)

        layout.addWidget(self.messages_label, 4, 0)
        layout.addWidget(self.messageBox, 5, 0, 5, 3)

        self.setLayout(layout)

        self.settings = QSettings()
        #self._clean_settings() # This will delete all existing settings! Use with caution!
        self._load_settings()

        self.setWindowTitle( _APP_NAME + " - " + _APP_VERSION)

        # setup our background worker thread ...

        # connect the signals from the background processor to callback
        # methods/slots. This makes it thread safe
        self.sig_message.connect(self.appendMessage)
        self.sig_finished.connect(self.on_finished)

        # Create our background worker object, which also will do work in it's
        # own thread.
        self._worker = AUxWorker(self.on_worker_callback)

        # add the actions/commands for this app to the background processing thread.
        # These actions are passed jobs to execute.
        self._worker.add_action(AUxEsptoolDetectFlash(), AUxEsptoolUploadFirmware(), AUxEsptoolResetESP32())

    #--------------------------------------------------------------
    # callback function for the background worker.
    #
    # It is assumed that this method is called by the background thread
    # so signals and used to relay the call to the GUI running on the
    # main thread

    def on_worker_callback(self, *args): #msg_type, arg):

        # need a min of 2 args (id, arg)
        if len(args) < 2:
            self.writeMessage("Invalid parameters from the uploader.")
            return

        msg_type = args[0]
        if msg_type == AUxWorker.TYPE_MESSAGE:
            self.sig_message.emit(args[1])
        elif msg_type == AUxWorker.TYPE_FINISHED:
            # finished takes 3 args - status, job type, and job id
            if len(args) < 4:
                self.writeMessage("Invalid parameters from the uploader.");
                return;

            self.sig_finished.emit(args[1], args[2], args[3])

    @pyqtSlot(str)
    def appendMessage(self, msg: str) -> None:
        if msg.startswith("\r"):
            self.messageBox.moveCursor(QTextCursor.StartOfLine, QTextCursor.KeepAnchor)
            self.messageBox.cut()
            self.messageBox.insertPlainText(msg[1:])
        else:
            self.messageBox.insertPlainText(msg)
        self.messageBox.ensureCursorVisible()
        self.messageBox.repaint()

        if msg.find("Detected flash size: 4MB") >= 0:
            self.flashSize = 4
        elif msg.find("Detected flash size: 8MB") >= 0:
            self.flashSize = 8
        elif msg.find("Detected flash size: 16MB") >= 0:
            self.flashSize = 16
        elif msg.find("Detected flash size: ") >= 0:
            self.flashSize = 0

    @pyqtSlot(str)
    def writeMessage(self, msg: str) -> None:
        self.messageBox.moveCursor(QTextCursor.End)
        #self.messageBox.ensureCursorVisible()
        self.messageBox.appendPlainText(msg)
        self.messageBox.ensureCursorVisible()
        self.messageBox.repaint()
        #QApplication.processEvents()

    #--------------------------------------------------------------
    # on_finished()
    #
    #  Slot for sending the "on finished" signal from the background thread
    #
    #  Called when the backgroudn job is finished and includes a status value
    @pyqtSlot(int, str, int)
    def on_finished(self, status, action_type, job_id) -> None:

        # If the flash detection is finished, trigger the upload
        if action_type == AUxEsptoolDetectFlash.ACTION_ID:
            self.writeMessage("Flash detection complete. Uploading firmware...")
            self.do_upload()

        # If the upload is finished, trigger a reset
        elif action_type == AUxEsptoolUploadFirmware.ACTION_ID:
            self.writeMessage("Firmware upload complete. Resetting ESP32...")
            self.esptool_reset()

        # re-enable the UX
        else:
            self.writeMessage("Reset complete...")
            self.disable_interface(False)

    # --------------------------------------------------------------
    # on_port_combobox()
    #
    # Called when the combobox pop-up menu is about to be shown
    #
    # Use this event to dynamically update the displayed ports
    #
    @pyqtSlot()
    def on_port_combobox(self):
        self.update_com_ports()

    def _load_settings(self) -> None:
        """Load settings on startup."""
        port_name = self.settings.value(SETTING_PORT_NAME)
        if port_name is not None:
            index = self.port_combobox.findData(port_name)
            if index > -1:
                self.port_combobox.setCurrentIndex(index)

        lastFile = self.settings.value(SETTING_FILE_LOCATION)
        if lastFile is not None:
            self.fileLocation_lineedit.setText(lastFile)

        # lastFile = self.settings.value(SETTING_PARTITION_LOCATION)
        # if lastFile is not None:
        #     self.partitionFileLocation_lineedit.setText(lastFile)
        # else:
        #     self.partitionFileLocation_lineedit.setText(resource_path("RTK_Surveyor.ino.partitions.bin"))

        baud = self.settings.value(SETTING_BAUD_RATE)
        if baud is not None:
            index = self.baud_combobox.findData(baud)
            if index > -1:
                self.baud_combobox.setCurrentIndex(index)

    def _save_settings(self) -> None:
        """Save settings on shutdown."""
        self.settings.setValue(SETTING_PORT_NAME, self.port)
        self.settings.setValue(SETTING_FILE_LOCATION, self.theFileName)
        # self.settings.setValue(SETTING_PARTITION_LOCATION, self.thePartitionFileName)
        self.settings.setValue(SETTING_BAUD_RATE, self.baudRate)

    def _clean_settings(self) -> None:
        """Clean (remove) all existing settings."""
        self.settings.clear()

    def show_error_message(self, msg: str) -> None:
        """Show a Message Box with the error message."""
        QMessageBox.critical(self, QApplication.applicationName(), str(msg))

    def update_com_ports(self) -> None:
        """Update COM Port list in GUI."""
        previousPort = self.port # Record the previous port before we clear the combobox

        self.port_combobox.clear()

        index = 0
        indexOfPrevious = -1
        for desc, name, sys in gen_serial_ports():
            longname = desc + " (" + name + ")"
            self.port_combobox.addItem(longname, sys)
            if(sys == previousPort): # Previous port still exists so record it
                indexOfPrevious = index
            index = index + 1

        if indexOfPrevious > -1: # Restore the previous port if it still exists
            self.port_combobox.setCurrentIndex(indexOfPrevious)

    def update_baud_rates(self) -> None:
        """Update baud rate list in GUI."""
        # Highest speed first so code defaults to that
        # if settings.value(SETTING_BAUD_RATE) is None
        self.baud_combobox.clear()
        self.baud_combobox.addItem("921600", 921600)
        self.baud_combobox.addItem("460800", 460800)
        self.baud_combobox.addItem("115200", 115200)

    @property
    def port(self) -> str:
        """Return the current serial port."""
        return str(self.port_combobox.currentData())

    @property
    def baudRate(self) -> str:
        """Return the current baud rate."""
        return str(self.baud_combobox.currentData())

    @property
    def theFileName(self) -> str:
        """Return the file name."""
        return self.fileLocation_lineedit.text()

    # @property
    # def thePartitionFileName(self) -> str:
    #     """Return the partition file name."""
    #     return self.partitionFileLocation_lineedit.text()

    def closeEvent(self, event: QCloseEvent) -> None:
        """Handle Close event of the Widget."""
        try:
            self._save_settings()
        except:
            pass

        # shutdown the background worker/stop it so the app exits correctly
        self._worker.shutdown()

        event.accept()

    def on_browse_btn_pressed(self) -> None:
        """Open dialog to select bin file."""
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(
            None,
            "Select Firmware to Upload",
            "",
            "Firmware Files (*.bin);;All Files (*)",
            options=options)
        if fileName:
            self.fileLocation_lineedit.setText(fileName)

    # def on_partition_browse_btn_pressed(self) -> None:
    #     """Open dialog to select partition bin file."""
    #     options = QFileDialog.Options()
    #     fileName, _ = QFileDialog.getOpenFileName(
    #         None,
    #         "Select Partition File",
    #         "",
    #         "Parition Files (*.bin);;All Files (*)",
    #         options=options)
    #     if fileName:
    #         self.partitionFileLocation_lineedit.setText(fileName)

    #--------------------------------------------------------------
    # disable_interface()
    #
    # Enable/Disable portions of the ux - often used when a job is running
    #
    def disable_interface(self, bDisable=False):

        self.upload_btn.setDisabled(bDisable)
        self.reset_btn.setDisabled(bDisable)

    def on_upload_btn_pressed(self) -> None:
        """Get ready to upload the firmware. First, detect the flash size"""
        portAvailable = False
        for desc, name, sys in gen_serial_ports():
            if (sys == self.port):
                portAvailable = True
        if (portAvailable == False):
            self.writeMessage("Port No Longer Available")
            return

        try:
            self._save_settings() # Save the settings in case the command fails
        except:
            pass

        self.flashSize = 0

        self.writeMessage("Detecting flash size\n\n")

        command = []
        command.extend(["--chip","esp32"])
        command.extend(["--port",self.port])
        command.extend(["--baud",self.baudRate])
        command.extend(["--before","default_reset","--after","no_reset"])
        command.extend(["flash_id"])

        # Create a job and add it to the job queue. The worker thread will pick this up and
        # process the job. Can set job values using dictionary syntax, or attribute assignments
        #
        # Note - the job is defined with the ID of the target action
        theJob = AxJob(AUxEsptoolDetectFlash.ACTION_ID, {"command":command})

        # Send the job to the worker to process
        self._worker.add_job(theJob)

        self.disable_interface(True)

    def do_upload(self) -> None:
        """Upload the firmware"""
        portAvailable = False
        for desc, name, sys in gen_serial_ports():
            if (sys == self.port):
                portAvailable = True
        if (portAvailable == False):
            self.writeMessage("Port No Longer Available")
            self.disable_interface(False)
            return

        fileExists = False
        try:
            f = open(self.theFileName)
            fileExists = True
        except IOError:
            fileExists = False
        finally:
            if (fileExists == False):
                self.writeMessage("File Not Found")
                self.disable_interface(False)
                return
            f.close()

        # fileExists = False
        # try:
        #     f = open(self.thePartitionFileName)
        #     fileExists = True
        # except IOError:
        #     fileExists = False
        # finally:
        #     if (fileExists == False):
        #         self.writeMessage("File Not Found")
        #         return
        #     f.close()

        try:
            self._save_settings() # Save the settings in case the command fails
        except:
            pass

        if self.flashSize == 0:
            self.writeMessage("Flash size not detected! Defaulting to 16MB\n")
            self.flashSize = 16
        else:
            self.writeMessage("Flash size is " + str(self.flashSize) + "MB\n")

        thePartitionFileName = ''
        firmwareSizeCorrect = True
        if self.flashSize == 16:
            thePartitionFileName = resource_path("RTK_Surveyor_Partitions_16MB.bin")
            # if self.theFileName.find("16MB") < 0:
            #     firmwareSizeCorrect = False
        else:
            thePartitionFileName = resource_path("RTK_Surveyor_Partitions_4MB.bin")
            # if self.theFileName.find("4MB") < 0:
            #     firmwareSizeCorrect = False

        if firmwareSizeCorrect == False:
            reply = QMessageBox.warning(self, "Firmware size mismatch", "Do you want to continue?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.No:
                self.disable_interface(False)
                return

        sleep(1.0);
        self.writeMessage("Uploading firmware\n")

        command = []
        #command.extend(["--trace"]) # Useful for debugging
        command.extend(["--chip","esp32"])
        command.extend(["--port",self.port])
        command.extend(["--baud",self.baudRate])
        command.extend(["--before","default_reset","--after","no_reset","write_flash","-z","--flash_mode","dio","--flash_freq","80m","--flash_size","detect"])
        command.extend(["0x1000",resource_path("RTK_Surveyor.ino.bootloader.bin")])
        command.extend(["0x8000",thePartitionFileName])
        command.extend(["0xe000",resource_path("boot_app0.bin")])
        command.extend(["0x10000",self.theFileName])

        #print("python esptool.py %s\n\n" % " ".join(command)) # Useful for debugging - cut and paste into a command prompt

        # Create a job and add it to the job queue. The worker thread will pick this up and
        # process the job. Can set job values using dictionary syntax, or attribute assignments
        #
        # Note - the job is defined with the ID of the target action
        theJob = AxJob(AUxEsptoolUploadFirmware.ACTION_ID, {"command":command})

        # Send the job to the worker to process
        self._worker.add_job(theJob)

        self.disable_interface(True) # Redundant... Interface is still disabled from flash detect

    def esptool_reset(self) -> None:
        """Tell the ESP32 to reset/restart"""
        portAvailable = False
        for desc, name, sys in gen_serial_ports():
            if (sys == self.port):
                portAvailable = True
        if (portAvailable == False):
            self.writeMessage("Port No Longer Available")
            self.disable_interface(False)
            return

        try:
            self._save_settings() # Save the settings in case the command fails
        except:
            pass

        sleep(1.0);
        self.writeMessage("Resetting ESP32\n")

        # ---- The esptool method -----

        command = []
        command.extend(["--chip","esp32"])
        command.extend(["--port",self.port])
        command.extend(["--before","default_reset","run"])

        # Create a job and add it to the job queue. The worker thread will pick this up and
        # process the job. Can set job values using dictionary syntax, or attribute assignments
        #
        # Note - the job is defined with the ID of the target action
        theJob = AxJob(AUxEsptoolResetESP32.ACTION_ID, {"command":command})

        # Send the job to the worker to process
        self._worker.add_job(theJob)

        self.disable_interface(True)

    def tera_term_reset(self) -> None:
        """Reset the ESP32 the TeraTerm way"""
        portAvailable = False
        for desc, name, sys in gen_serial_ports():
            if (sys == self.port):
                portAvailable = True
        if (portAvailable == False):
            self.writeMessage("Port No Longer Available")
            return

        try:
            self._save_settings() # Save the settings in case the command fails
        except:
            pass

        self.writeMessage("Resetting ESP32\n")

        # ---- The pySerial method -----

        self.disable_interface(True)

        sleep(0.1)

        try:
            ser = serial.Serial()
            ser.port = self.port
            ser.setDTR(False) # DTR High
            ser.setRTS(False) # RTS High
            with ser as s:
                s.setRTS(True) # RTS Low - before DTR
                s.setDTR(True) # DTR Low - after RTS
                sleep(1.0)
                self.writeMessage("Waiting for reset to complete")
                sleep(1.0)
                self.writeMessage("Waiting for reset to complete")
                sleep(1.0)
                self.writeMessage("Waiting for reset to complete")
                sleep(1.0)
                self.writeMessage("Waiting for reset to complete\n")
                sleep(1.0)
        except:
            self.writeMessage("Could not open serial port\n")
            self.disable_interface(False)
            return

        self.writeMessage("Reset complete...")
        self.disable_interface(False)

def startUploaderGUI():
    """Start the GUI"""
    from sys import exit as sysExit
    app = QApplication([])
    app.setOrganizationName('SparkFun Electronics')
    app.setApplicationName(_APP_NAME + ' - ' + _APP_VERSION)
    app.setWindowIcon(QIcon(resource_path("RTK.png")))
    app.setApplicationVersion(_APP_VERSION)
    w = MainWidget()
    w.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    startUploaderGUI()


import sys,time
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import numpy as np
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt

def predictor(fileName, ticker, column, t, graphFile):
    timeInMin=int(datetime.now().hour)*60 + int(datetime.now().minute) #converts the current time to minutes

    data = pd.read_csv(infoFileName)
    dataFrame=data.loc[data['Ticker']==ticker] #locates all the data for the passed in ticker

    X_axis= dataFrame[[column]] #stores the data fo the column (latestValue/latestPrice) of the passed in ticker
    Y_axis=dataFrame['Time'].str.split(':').apply([lambda a: int(a[0])*60+int(a[1])]) #puts in the time in minutes into Y

    xTrain, xTest, yTrain, yTest = train_test_split(Y_axis,X_axis, test_size = 0.3, random_state = 0)

    regr = LinearRegression()

    regr.fit(xTrain,yTrain)                                     #fits the linear regression line
    #Code above was influenced from https://stackabuse.com/linear-regression-in-python-with-scikit-learn/

    for time in range(timeInMin, timeInMin+t):            #goes through new range of times we will predict
        b = plt.scatter(time, regr.predict([[time]]), color='red') #plots each predicted value on the graph

    c = plt.scatter(xTrain,yTrain, color = 'green') #plots observed value
    a = plt.plot(xTrain, regr.predict(xTrain), color = 'blue',) #creates a line of best fit
    plt.xlabel('Time(min)')
    plt.ylabel(column)
    plt.legend((c,b),('Observed data', 'Predicted data'))
    plt.savefig(graphFile)

if __name__ == "__main__":
    ticker = sys.argv[1].upper() #converts the ticker to uppercase
    infoFileName = sys.argv[2]
    graphFileName = sys.argv[3]
    column = sys.argv[4]
    time = int(sys.argv[5])
    predictor(infoFileName,ticker,column,time,graphFileName)


#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  :UKF_6d_KV.py
# @Time      :2022/10/13 1:45 AM
# @Author    :Kinddle

import numpy as np
import matplotlib.pyplot as plt
import numpy.linalg

plt.rcParams['font.sans-serif'] = ['Heiti TC']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
# ukf

def sigmas(X,P,c):
    A = c * np.linalg.cholesky(P).transpose()
    Y = X[:,np.zeros([X.shape[0]],dtype=int)]
    return np.c_[X,Y+A,Y-A]

def ut(fun,Xsigma,Wm,Wc,n,COV):
    LL = np.size(Xsigma,1)  # 样本个数
    Xmeans = np.zeros([n,1])
    Xsigma_pre = np.zeros([n,LL])
    for k in range(LL):
        Xsigma_pre[:,k,None]=fun(Xsigma[:,k,None])
        Xmeans += Wm[k] * Xsigma_pre[:,k,None]
    Xdiv = Xsigma_pre - Xmeans
    P = Xdiv.dot(np.diag(Wc)).dot(Xdiv.transpose()) + COV
    return Xmeans,Xsigma_pre,P,Xdiv

def ukf(ffun,X,P,hfun,Z,Q,R):
    L = X.shape[0]
    m = Z.shape[0]
    alpha = 1e-2
    ki =0
    beta = 2
    rambda = alpha**2 * (L+ki) - L
    c = L + rambda
    Wm = np.c_[rambda/c, np.zeros([1,2*L])+0.5/c][0]
    Wc = Wm
    Wc[0] += 1-alpha**2+beta
    c = np.sqrt(c)

    # 获得点集
    Xsigmaest = sigmas(X,P,c)
    # 一步预测
    X1means,X1,P1,X2 = ut(ffun,Xsigmaest,Wm,Wc,L,Q)
    Zpre,Z1,Pzz,Z2 = ut(hfun,X1,Wm,Wc,m,R)
    Pxz = X2.dot(np.diag(Wc)).dot(Z2.transpose())
    K = Pxz.dot(np.linalg.inv(Pzz))
    X = X1means + K.dot(Z-Zpre)
    P = P1 - K.dot(Pxz.transpose())
    return X,P

# ---------参数设定---------
n = 6
t = 0.5
Q = np.diag([1, 1, 0.01, 0.01, 0.0001, 0.0001])
R = np.diag([100, 1e-6])
Phi = np.array([[1, 0, t, 0, t ** 2 / 2, 0],
                [0, 1, 0, t, 0, t ** 2 / 2],
                [0, 0, 1, 0, t, 0],
                [0, 0, 0, 1, 0, t],
                [0, 0, 0, 0, 1, 0],
                [0, 0, 0, 0, 0, 1], ])
Xstation = np.array([[0], [0]])
Func_f = lambda x_arr:np.dot(Phi,x_arr)
Func_h = lambda x_arr:np.array([np.sqrt((x_arr[0]-Xstation[0])**2+(x_arr[1]-Xstation[1])**2),
                                np.arctan2(x_arr[1],x_arr[0])])
# s0 = np.array([1000,5000,10,50,2,-4])
s0 = np.array([1000,5000,10,-40,2,4])
x0 = s0[:,None] + np.sqrt(Q).dot(np.random.randn(n,1))

P0 = np.diag([100,100,1,1,0.1,0.1])

N = 50 # 仿真步数

Xukf = np.zeros([n,N])
X = np.zeros([n,N])
Z = np.zeros([2,N])

X[:,0] = s0
for i in range(1,N):
    X[:,i,None] = Func_f(X[:,i-1,None]) + np.sqrt(Q).dot(np.random.randn(6,1))

ux = x0
# ukf
for k in range(N):
    Z[:,k,None] = Func_h(X[:,k,None]) + np.sqrt(R).dot(np.random.randn(2,1))
    Xukf[:, k, None], P0 = ukf(Func_f,ux,P0,Func_h,Z[:,k,None],Q,R)
    ux = Xukf[:, k, None]

# ----误差分析----

Err_ukf_s = np.sqrt(np.sum((X - Xukf)[[0, 1], :] ** 2, axis=0))
Err_ukf_v = np.sqrt(np.sum((X - Xukf)[[2, 3], :] ** 2, axis=0))
Err_ukf_a = np.sqrt(np.sum((X - Xukf)[[4, 5], :] ** 2, axis=0))

plt.figure()
plt.subplot(2, 2, 1)
plt.plot(X[0], X[1], label="real")
plt.plot(Xukf[0], Xukf[1], label="Est")
plt.legend()
plt.subplot(2, 2, 2)
plt.plot(Err_ukf_s, label="s_Err")
plt.legend()
plt.subplot(2, 2, 3)
plt.plot(Err_ukf_v, label="v_Err")
plt.legend()
plt.subplot(2, 2, 4)
plt.plot(Err_ukf_a, label="a_Err")
plt.legend()
plt.show()


#!/usr/bin/env python

"""
Chris' solution to the grid printing Exercise.

Note that we only did the basics of loops, and you can
do all this without any loops at all, so that's what I did.

Note also that there is more than one way to skin a cat --
   or code a function
"""

def print_grid_trivial():
    """
    Did anyone come up with the most trivial possible solution?

    Note that this may the the wy to go, oif this all you need to do:
      print something specific once. Why write fancy code for that?
    """
    print("""
+ - - - - + - - - - +
|         |         |
|         |         |
|         |         |
|         |         |
+ - - - - + - - - - +
|         |         |
|         |         |
|         |         |
|         |         |
+ - - - - + - - - - +
""")

def print_grid(size):
    """
    print a 2x2 grid with a total size of size

    :param size: total size of grid -- it will be rounded if not one more than
        a multiple of 2
    """
    number = 2
    box_size = int((size - 1) // 2)  # size of one grid box: integer division
    print("box_size:", box_size)
    # top row
    top = ('+ ' + '- ' * box_size) * number + '+' + '\n'
    middle = ('| ' + ' ' * 2 * box_size) * number + '|' + '\n'

    row = top + middle * box_size

    grid = row * number + top

    print(grid)

def print_grid2(number, size):
    """
    print a number x number grid with each box of size width and height

    :param number: number of grid boxes (row and column)

    :param size: size of each grid box
    """
    # top row
    top = ('+ ' + '- ' * size) * number + '+' + '\n'
    middle = ('| ' + ' ' * 2 * size) * number + '|' + '\n'

    row = top + middle * size

    grid = row * number + top

    print(grid)

def print_grid3(size):
    """
    same as print_grid, but calling print_grid2 to do the work
    """
    number = 2
    box_size = (size - 1) // 2  # size of one grid box: note integer divsion!
    print_grid2(number, box_size)

print_grid_trivial()

print_grid(11)
print_grid(7)

print_grid2(3, 3)
print_grid2(3, 5)

print_grid3(11)


from flask import Flask, render_template, session, redirect, request
import random

app = Flask(__name__)
app.secret_key = "not telling you"

@app.route('/')
def make_random():
    session['number'] = random.randint(1, 100)
    session['attempts'] = 0
    return render_template('index.html')

@app.route('/result', methods=['POST'])
def compare_results():
    number = int(request.form['guess'])
    if number > session['number']:
        text = "Too High"
        color = "red"
    elif number < session['number']:
        text = "Too Low"
        color = "red"
    else:
        text = f"{str(number)} was the correct answer"
        color = "green"
    if session['attempts'] == 5 and number!= session['number']:
        return 'YOU LOSE'
    session['attempts'] += 1
    return render_template('index.html', text=text, color=color, attempts = session['attempts'])

@app.route('/destroy-session', methods=['POST'])
def destroy():
    session.clear()
    return redirect('/')

if __name__ == ('__main__'):
    app.run(debug=True)


import datetime
import numpy as np
import pandas as pd
import scipy as sp
import scipy.optimize as sco
import statsmodels.api as sm
from scipy.optimize import curve_fit
from scipy.optimize import leastsq as least_squares

import albio.algo_holtwinters as ht
import albio.series_stat as a_s
import albio.forecast as a_f

#-------------------------series-class----------------------------

def standardConf():
    return {"obs_time":0,"decay":[1],"hist_adj": 0.8,"model": "holt"
            ,"res":[14,0.03,0.01,0.02,0.15,0.12,0.13,0.11,0.22]
            ,"holt": [5,0.2,0.1,0.05,0.8]
            ,"poly": [-0.26,-0.043,-1.24,0.0024,-1.6e-06,3.6e-10]
            ,"response": [1.37,1.09,-0.57,0.023,0.110]
            ,"autocor": [0.095,-1.01,-0.40,0.15,8.26,1.0,1.0,1.0,1.0]
            ,"freq": [10.38,5.19]
            ,"arma": [4,0,0]
            ,"sin": [0.,1.,0.03,0.31,2.80,1.0,1.0,1.0,1.0]
    }

class series:
    """statistical properties and forecast of series"""

    def __init__(y, t=[None], conf=None, isPlot=False):
        """analyze time series"""
        ny = len(y)
        if t[0] == None:
            t0 = datetime.datetime.today()-datetime.timedelta(ny)
            t = [t0+datetime.timedelta(x) for x in range(ny)]
        if conf == None:
            conf = standardConf()
        week = [x.isocalendar()[1] for x in t]
        month = [x.month for x in t]
        year = [x.isocalendar()[0] for x in t]
        ser = pd.DataFrame({"y":y,"t":t,"week":week,"month":month,"year":year})
        ser.loc[:,"ts"] = [x.timestamp() for x in t]
        sWeek = ser[['ts','y','week']].groupby(["week"]).agg(np.mean)
        s = ser.iloc[0]
        s1 = pd.DataFrame({'ts':s['ts']-1,'y':s['y']},index=[s['week']])
        s = ser.iloc[-1]
        s2 = pd.DataFrame({'ts':s['ts']+1,'y':s['y']},index=[s['week']])
        sWeek = pd.concat([s1,sWeek,s2])
        sMont = ser[['ts','y','month']].groupby(["month"]).agg(np.mean)
        sYear = ser[['ts','y','year']].groupby(["year"]).agg(np.mean)
        ser = ser.merge(sWeek[['y']],on="week" ,how="left",suffixes=["","_week"])
        ser = ser.merge(sMont[['y']],on="month",how="left",suffixes=["","_month"])
        ser = ser.merge(sYear[['y']],on="year" ,how="left",suffixes=["","_year"])
        ser.loc[:,"roll"] = a_s.serSmooth(ser['y'],4,11)
        ser.loc[:,"e_av"] = ser['y'].ewm(halflife=1).mean()
        s2 = pd.DataFrame({"week":s['week'],'ts':s['ts'],'y':s['y']})
        ser['inte'] = sp.interpolate.interp1d(sWeek['ts'],sWeek['y'],kind="cubic")(ser['ts'])
        ser['deri'] = ser['y'] - ser['y'].shift()
        ser['diff'] = ser['y'] - ser['e_av']
        ser['rema'] = ser['y'] - ser['roll']
        ser['hist'] = ser['y'] - ser['inte']
        ser['adju'] = ( (ser['hist']-ser['hist'].min())/(ser['hist'].max()-ser['hist'].min()) + .5)*conf['hist_adj']
        ser.drop(columns={"week","month","year"},inplace=True)
        ser.replace(float('nan'),0.,inplace=True)
        self.ser = ser
        self.sWeek = sWeek
        if isPlot:
            plt.bar( ser['t'],ser['y_year'],label="yearly",alpha=0.1)
            plt.bar( ser['t'],ser['y_month'],label="monthly",alpha=0.1)
            plt.bar( ser['t'],ser['y_week'],label="weekly",alpha=0.1)
            plt.plot(ser['t'],ser['y'],label="series",linewidth=2)
            plt.plot(ser['t'],ser['roll'],label="rolling average",linewidth=1)
            plt.plot(ser['t'],ser['e_av'],label="average",linewidth=1)
            plt.plot(ser['t'],ser['inte'],label="interpolate week",linewidth=1)
            plt.legend()
            plt.xticks(rotation=15)
            plt.show()
            plt.plot(ser['t'],ser['deri'],label="derivative",linewidth=1)
            plt.plot(ser['t'],ser['diff'],label="remainder exp",linewidth=1)
            plt.plot(ser['t'],ser['rema'],label="remainder roll",linewidth=1)
            plt.plot(ser['t'],ser['hist'],label="historical week",linewidth=1)
            plt.legend()
            plt.xticks(rotation=15)
            plt.show()

    def trendFluct(self, n_ahead=14):
        """predict the signal decomposing the trend from the fluctuations"""
        ser = self.ser
        t1, y1, pol = a_f.trendFluct(ser['t'],ser['t'],ser['y'],n=14,conf=conf)
        return t1, y1, pol

##---------------------------series-preprocessing------------------------

##---------------------------forecast-methods----------------------------

def serLsq(sDay, nAhead, x0, hWeek):
    nFit = sDay.shape[0]  # if int(x0['obs_time']) <= 14 else int(x0['obs_time'])
    predS, x0 = getHistory(sDay, nAhead, x0, hWeek)
    predS = predS.tail(nFit + nAhead)
    freqP = x0['freq']
    res_lsq = least_squares(ser_sin_min, x0['lsq'], args=(sDay.t, sDay.stat, x0['freq']))  # loss='soft_l1',f_scale=0.1,
    x0['lsq'] = [x for x in res_lsq[0]]
    predS['lsq'] = ser_sin(res_lsq[0], predS.t, x0['freq'])  # fun(res_robust.x,t_test)
    sDay['resid'] = sDay['y'] - ser_sin(res_lsq[0], sDay.t, x0['freq']) / sDay['hist'] - ser_poly(x0['poly'], sDay[
        't'])  # lm.predict(sDay)
    rSquare = (sDay['resid'].tail(x0['res'][0]) - sDay['resid'].tail(x0['res'][0]).mean()) ** 2
    x0['res'][1] = rSquare.sum()
    x0['res'][2] = rSquare.sum() / sDay['y'].tail(x0['res'][0]).sum()
    # predS['pred'] = (predS['lsq'] + lm.predict(predS))*predS['hist']*x0['hist_adj']
    predS['pred'] = ser_sin(res_lsq[0], predS.t, x0['freq']) * sDay['hist'] + ser_poly(x0['poly'], predS['t'])
    predS = predS.drop(predS.index[0])
    return predS, x0

def bestArima(sDay, nAhead, x0, hWeek):
    dta = sDay['y']
    dta.index = [pd.datetime.strptime(str(x)[0:10], '%Y-%m-%d') for x in dta.index]
    t_line = [float(calendar.timegm(x.utctimetuple())) / 1000000 for x in dta.index]
    t_line1 = [float(calendar.timegm(x.utctimetuple())) / 1000000 for x in hWeek.index]
    sExog = pd.DataFrame({'y': sp.interpolate.interp1d(t_line1, hWeek.y, kind="cubic")(t_line)})
    grid = (slice(1, 4, 1), slice(1, 2, 1), slice(1, 3, 1))

    def objfunc(order, endog, exog):
        fit = sm.tsa.ARIMA(endog, order).fit(trend="c", method='css-mle', exog=exog)
        return fit.aic

    par = sco.brute(objfunc, grid, args=(dta, sExog), finish=None)
    return par

def serArma(sDay, nAhead, x0, hWeek):
    predS, x0 = getHistory(sDay, nAhead, x0, hWeek)
    dta = sDay['y']
    dta.index = [pd.datetime.strptime(str(x)[0:10], '%Y-%m-%d') for x in dta.index]
    sDay.index = dta.index
    t_line = [float(calendar.timegm(x.utctimetuple())) / 1000000 for x in dta.index]
    t_line1 = [float(calendar.timegm(x.utctimetuple())) / 1000000 for x in hWeek.index]
    sExog = pd.DataFrame({'y': sp.interpolate.interp1d(t_line1, hWeek.y, kind="cubic")(t_line)})
    # par = bestArima(dta,sExog)
    sExog.index = dta.index
    result = sm.tsa.ARIMA(dta, (x0['arma'][0], x0['arma'][1], x0['arma'][2])).fit(trend="c", method='css-mle',
                                                                                exog=sExog)
    predT = [str(dta.index[0])[0:10], str(dta.index[len(dta) - 1])[0:10]]
    histS = pd.DataFrame({'pred': result.predict(start=predT[0], end=predT[1])})
    # predT = [str(dta.index[0])[0:10],str(dta.index[len(dta)-1]+datetime.timedelta(days=nAhead))[0:10]]
    predS = predS[0:(len(dta) - 1)]
    predS['pred'] = result.predict(start=predT[0], end=predT[1])
    # predS = pd.DataFrame({'pred':result.predict(start=predT[0],end=predT[1])})
    # predS.index = [dta.index[0]+datetime.timedelta(days=x) for x in range(0,len(dta)+nAhead)]
    # predS['t'] = [float(calendar.timegm(x.utctimetuple()))/1000000 for x in predS.index]
    # predS['hist'] = sp.interpolate.interp1d(t_line1,hWeek.y,kind="cubic")(predS['t'])
    # predS['hist'] = predS['hist']/predS['hist'].mean()
    # predS['pred'] = predS['pred']*predS['hist']
    predS['trend'] = ser_poly(x0['poly'], predS.t)
    predS['y'] = sDay['y']
    predS['pred'] = (predS['pred'] * predS['hist'] + predS['trend'])
    x0['response'] = [x for x in result.params]
    sDay['resid'] = sDay['y'] - predS['pred'][0:sDay.shape[0]]
    rSquare = (sDay['resid'].tail(x0['res'][0]) - sDay['resid'].tail(x0['res'][0]).mean()) ** 2
    x0['res'][1:2] = [rSquare.sum(), rSquare.sum() / sDay['y'].tail(x0['res'][0]).sum()]
    return predS, x0
    # plt.plot(dta,'-k',label="series")
    # plt.plot(sExog,label="exo")
    # plt.plot(hWeek.y,label="hist")
    # plt.plot(predS,'-b',label="pred")
    # plt.legend()
    # plt.show()
    # steps = 1
    # tsa.arima_model._arma_predict_out_of_sample(res.params,steps,res.resid,res.k_ar,res.k_ma,res.k_trend,res.k_exog,endog=dta, exog=None, start=len(dta))

def SerBayes(sDay, nAhead, x0, hWeek):
    import pydlm
    dta = sDay['y']
    dta.index = [pd.datetime.strptime(str(x)[0:10], '%Y-%m-%d') for x in dta.index]
    t_line = [float(calendar.timegm(x.utctimetuple())) / 1000000 for x in dta.index]
    dta.index = t_line
    model = pydlm.dlm(dta)
    model = model + pydlm.trend(degree=1, discount=0.98, name='a', w=10.0)
    model = model + pydlm.dynamic(features=[[v] for v in t_line], discount=1, name='b', w=10.0)
    model = model + pydlm.autoReg(degree=3, data=dta.values, name='ar3', w=1.0)
    allStates = model.getLatentState(filterType='forwardFilter')
    model.evolveMode('independent')
    model.noisePrior(2.0)
    model.fit()
    model.plot()
    model.turnOff('predict')
    model.plotCoef(name='a')
    model.plotCoef(name='b')
    model.plotCoef(name='ar3')

def serHolt(sDay, nAhead, x0, hWeek):
    predS, x0 = getHistory(sDay, nAhead, x0, hWeek)
    Y = [x for x in sDay.y]
    ##Yht, alpha, beta, gamma, rmse = ht.additive([x for x in sDay.y],int(x0[0]),nAhead,x0[1],x0[2],x0[3])
    nAv = int(x0['holt'][0]) if int(x0['holt'][0]) > 1 else 5
    Yht, alpha, beta, gamma, rmse = ht.additive([x for x in sDay.y], x0['holt'][0], nAhead, x0['holt'][1],
                                                x0['holt'][2], x0['holt'][3])
    sDay['resid'] = sDay['y'] - Yht[0:sDay.shape[0]]
    x0['holt'] = [x0['holt'][0], alpha, beta, gamma, rmse]
    nLin = sDay.shape[0] + nAhead
    t_test = np.linspace(sDay['t'][0], sDay['t'][sDay.shape[0] - 1] + sDay.t[nAhead] - sDay.t[0], nLin)
    # predS = pd.DataFrame({'t':t_test},index=[sDay.index[0]+datetime.timedelta(days=x) for x in range(nLin)])
    predS['pred'] = Yht
    # predS['hist'] = sp.interpolate.interp1d(hWeek.t,hWeek.y,kind="cubic")(predS['t'])
    # predS['hist'] = predS['hist']/predS['hist'].mean()
    # predS['pred'] = predS['pred']*predS['hist']*x0['hist_adj']
    # predS['trend'] = ser_poly(x0['poly'],predS.t)
    # predS['trend'].ix[0:(sDay.shape[0]-nFit)] = predS['trend'][sDay.shape[0]-nFit]
    predS['lsq'] = 0
    predS['y'] = sDay['y']
    sDay['resid'] = sDay['y'] - predS['pred'][0:sDay.shape[0]]
    rSquare = (sDay['resid'].tail(x0['res'][0]) - sDay['resid'].tail(x0['res'][0]).mean()) ** 2
    x0['res'][1] = rSquare.sum()
    x0['res'][2] = rSquare.sum() / sDay['y'].tail(x0['res'][0]).sum()
    return predS, x0

def serAuto(sDay, nAhead, x0, hWeek):
    predS, x0 = getHistory(sDay, nAhead, x0, hWeek)
    todayD = datetime.datetime.today()
    todayD = todayD.replace(hour=0, minute=0, second=0, microsecond=0)
    dta = pd.DataFrame({'y': sDay.y})
    dta['day'] = sDay.index.weekday
    phase = dta.head(int(x0['obs_time'])).groupby(['day']).mean()
    phase['std'] = dta.groupby(['day']).std()['y']
    phase = phase.sort_values(['y'], ascending=False)
    phase['csum'] = phase['y'].cumsum() / phase['y'].sum()
    phaseN = phase.index[0] - todayD.weekday()
    r, q, p = sm.tsa.acf(sDay['y'].tail(phaseN + int(x0['obs_time'])).squeeze(), qstat=True)
    popt, pcov = curve_fit(ser_exp, np.array(range(0, 6)), r[0:6] - min(r), p0=(x0['decay'][0]))
    X = np.array(range(0, r.size, 7))
    popt1, pcov1 = curve_fit(ser_exp, X, r[X], p0=(x0['decay'][0]))
    autD = pd.DataFrame({'r': r, 'exp': ser_exp(range(0, r.size), popt), 'exp1': ser_exp(range(0, r.size), popt1)})
    x0['decay'] = [x for x in popt]
    wN = 0
    sY = np.random.normal(phase['y'].head(1), dta.y.std())
    for i in predS.index:
        wN = 6 - np.abs(phase.index[0] - i.weekday())
        wN = wN + 1 if wN < 6 else 0
        if (wN == 0):
            sY = np.random.normal(phase['y'].head(1), dta.y.std() / 2)
        sY = sY * (1 + predS['hist'][i] * x0['hist_adj'])
        predS.loc[i, 'pred'] = sY * ser_exp(float(wN), popt)

    predS['pred'] = serSmooth(predS['pred'], 16, 5)
    sDay['resid'] = sDay['y'] - predS['pred'][0:sDay.shape[0]]
    freqP = x0['freq']
    res_lsq = least_squares(ser_fun_min, x0['lsq'], args=(sDay['t'], sDay['resid'], x0['freq']))
    predS['lsq'] = ser_sin(res_lsq[0], predS['t'], x0['freq'])  # fun(res_robust.x,t_test)
    x0['lsq'][0:res_lsq[0].size] = res_lsq[0]
    predS['pred2'] = predS['pred']
    predS['pred'] = predS['pred'] + predS['lsq']
    sDay['resid'] = sDay['y'] - predS['pred'][0:sDay.shape[0]]
    rSquare = (sDay['resid'].tail(x0['res'][0]) - sDay['resid'].tail(x0['res'][0]).mean()) ** 2
    x0['res'][1] = rSquare.sum()
    x0['res'][2] = rSquare.sum() / sDay['y'].tail(x0['res'][0]).sum()
    # sDay.to_csv('tmpAuto1.csv')
    # predS.to_csv('tmpAuto2.csv')
    # autD.to_csv('tmpAuto3.csv')
    return predS, x0


# for https://leetcode.com/problems/integer-to-english-words/

class Solution:
    def numberToWords(self, num: int) -> str:
        """
        Converts a non-negative integer num to its English word equivalent.

        Example: num = 123
        Output: 'One Hundred Twenty Three'

        Takes a single non-negative integer, num, and returns a string.
        """
        if num == 0:
            return 'Zero'
        digits = [
            '',  # blank string in 0 index to improve readability
            'One',  # since now digits[1] == 'One'
            'Two',
            'Three',
            'Four',
            'Five',
            'Six',
            'Seven',
            'Eight',
            'Nine',
            'Ten',
            'Eleven',
            'Twelve',
            'Thirteen',
            'Fourteen',
            'Fifteen',
            'Sixteen',
            'Seventeen',
            'Eighteen',
            'Nineteen'
        ]
        # Next two could be part of big list technically but I don't think
        # it makes sense to do so.
        tens = [
            '',  # blank strings in 0 and 1 index for the same reason
            '',
            'Twenty',
            'Thirty',
            'Forty',
            'Fifty',
            'Sixty',
            'Seventy',
            'Eighty',
            'Ninety',
        ]
        scales = [
            '',  # Not for readability per se but so scale can start at 0
            'Thousand',
            'Million',
            'Billion'
        ]
        scale = 0  # increments upward
        results = []  # container for results
        while num > 0:
            current_chunk_words = []   # container for current chunk's words
            # Process the chunk by hundreds, then tens, then ones
            # adding the relevant words to current container
            # First hundreds, using modulo and floor division
            current_chunk = num % 1000  # lop off a three digit chunk
            hundreds_chunk = current_chunk // 100
            if hundreds_chunk > 0:
                current_chunk_words.append(digits[hundreds_chunk])
                current_chunk_words.append('Hundred')  # not worth a list entry
            # Then tens, again using modulo and floor division to separate
            current_chunk = current_chunk % 100
            tens_chunk = current_chunk // 10
            if tens_chunk != 1:  # Everything but the teens
                if tens_chunk:
                    current_chunk_words.append(tens[tens_chunk])
                # Processing ones like hundreds and tens, note that
                # this doesn't happen in the teens case
                ones_chunk = current_chunk % 10
                if ones_chunk:
                    current_chunk_words.append(digits[ones_chunk])
            elif tens_chunk == 1:  # 11-19 are a special case
                current_chunk_words.append(digits[current_chunk])
            # Now add the large_number/million/billion if applicable,
            # turn it into a string, and add it to results
            if current_chunk_words:
                if scale:
                    current_chunk_words.append(scales[scale])
                current_chunk_words = ' '.join(current_chunk_words)
                results.append(current_chunk_words)
            # Now we cut the number down by 1000, up the scale
            # marker and execute again, repeating until empty
            num = num // 1000
            scale += 1
        # This leaves results a list of correct strings for the three-digit
        # chunks of the int, but in reverse order. So assuming the int wasn't 0
        # we reverse results, and return a joined string of it. If the original
        # int was 0 then whoops. That check was originally down here but
        # sanitizing the input earlier was more performant.
        return ' '.join(reversed(results))


def get_fields(fields, obj):
    obs_dict = {}
    for fld in fields:
        if isinstance(fld, (list, tuple)):
            fld, name = fld
        else:
            name = fld
        if callable(fld):
            val = fld(obj)
        else:
            links = fld.split('__')
            val = obj
            for lnk in links:
                val = getattr(val, lnk)
                if callable(val):
                    val = val()
        obs_dict[name] = val
    return obs_dict

class Resource(object):

    def __init__(self, queryset=None):
        self.queryset = queryset

    def eval(self):

        # Were we given something?
        objs = getattr(self, 'queryset', None)
        if objs is None:
            objs = self.model.objects.all()

        # Is it a queryset, or an object?
        if not isinstance(objs, self.model):
            values = objs.values(*getattr(self, 'fields', []))
            extras = getattr(self, 'extras', None)
            if extras:
                for o, v in zip(objs, values):
                    v.update(get_fields(extras, o))
        else:
            values = {}
            for field in getattr(self, 'fields', []):
                values[field] = getattr(objs, field, None)

        return values


import numpy as np
import keras
from keras.preprocessing.image import array_to_img
import warnings
import datetime
import optparse
import os, errno
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input

class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'

    def __init__(self, image_file_list, im_num, text_vec, image_vec_dict, sim_dict, bert_dict,labels, max_seq_length=20, batch_size=32,
                 n_classes=2, shuffle=False):
        'Initialization'
        # self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.image_file_list = image_file_list
        self.text_vec = text_vec
        self.image_vec_dict = image_vec_dict
        self.im_num = im_num
        self.sim_dict = sim_dict
        self.bert_dict = bert_dict
        self.n_classes = n_classes
        self.shuffle = shuffle
        self.max_seq_length = max_seq_length
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.ceil(len(self.image_file_list) / float(self.batch_size)))

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        #print(" index starts at: "+str(index * self.batch_size) +" ends at: "+str((index + 1) * self.batch_size))
        start = index * self.batch_size
        end = (index + 1) * self.batch_size
        if(end > len(self.image_file_list)):
            #print(" index starts at: " + str(start) + " ends at: " + str(end))
            end = len(self.image_file_list)

        temp_indexes = self.indexes[start:end]
        #print(temp_indexes)
        # Generate data
        images1_batch, images2_batch, images3_batch, images4_batch,images5_batch, text_batch, sim_batch, bert_batch, y = self.__data_generation(temp_indexes)

        return [images1_batch, images2_batch, images3_batch,images4_batch, images5_batch, text_batch, sim_batch, bert_batch], y

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.image_file_list))
        #print(" indexes len: "+str(len(self.indexes)))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, indexes):
        'Generates data containing batch_size samples'
        # Initialization
        y = np.empty((len(indexes),self.n_classes), dtype=int)
        text_batch = np.empty((len(indexes), self.max_seq_length), dtype=int)
        images1_batch = np.empty([len(indexes), 1, 1000])
        images2_batch = np.empty([len(indexes), 1, 1000])
        images3_batch = np.empty([len(indexes), 1, 1000])
        images4_batch = np.empty([len(indexes), 1, 1000])
        images5_batch = np.empty([len(indexes), 1, 1000])
        sim_batch = np.empty([len(indexes), 1, self.im_num])
        bert_batch = np.empty([len(indexes), 1, 768])

        # Generate data
        for i, index in enumerate(indexes):
            try:
                if(index <= len(self.image_file_list)):
                    image_file_name1 = str(self.image_file_list[index][0])
                    news_ids = image_file_name1.split('_')[0]+'_'+ image_file_name1.split('_')[1]
                    sim = self.sim_dict[news_ids][:self.im_num]
                    bert = self.bert_dict[news_ids]
                    sim_batch[i, :, :]=np.array(sim)
                    bert_batch[i, :, :]=np.array(bert)  #albert.tolist()[0]

                    if len(self.image_file_list[index]) == 5:
                        image_file_name2 = str(self.image_file_list[index][1])
                        image_file_name3 = str(self.image_file_list[index][2])
                        image_file_name4 = str(self.image_file_list[index][3])
                        image_file_name5 = str(self.image_file_list[index][4])
                    elif len(self.image_file_list[index])==4:
                        image_file_name2 = str(self.image_file_list[index][1])
                        image_file_name3 = str(self.image_file_list[index][2])
                        image_file_name4 = str(self.image_file_list[index][3])
                        image_file_name5 = ' '

                    elif len(self.image_file_list[index])==3:
                        image_file_name2 = str(self.image_file_list[index][1])
                        image_file_name3 = str(self.image_file_list[index][2])
                        image_file_name4 = ' '
                        image_file_name5 = ' '

                    elif len(self.image_file_list[index])==2:
                        image_file_name2 = str(self.image_file_list[index][1])
                        image_file_name3 = ' '
                        image_file_name4 = ' '
                        image_file_name5 = ' '

                    else:
                        image_file_name2 = ' '
                        image_file_name3 = ' '
                        image_file_name4 = ' '
                        image_file_name5 = ' '

                    if(image_file_name1 in self.image_vec_dict):
                        # if(image_file_name=="image_null"):
                        #     img = np.zeros([1, 224, 224, 3])
                        # else:
                        img = self.image_vec_dict[image_file_name1]
                        images1_batch[i, :, :] = img
                        #images1_batch[i, :, :, :] = img
                        # Store class
                        #print(img)
                        y[i] = self.labels[index]
                        text_batch[i] = self.text_vec[index]

                        print('img:::::::::::::::::::', img)
                        print('sim:::::::::::::::::::', np.array(sim))
                        print('text:::::::::::::::::::', np.array(albert))
                        print('label::::::::::::::::::', self.labels[index])

                    else:
                        y[i] = self.labels[index]
                        text_batch[i] = self.text_vec[index]
                        img = np.zeros([1, 1000])
                        images1_batch[i, :, :] = img

                    if(image_file_name2 in self.image_vec_dict):
                        img = self.image_vec_dict[image_file_name2]
                        images2_batch[i, :, :] = img
                        # Store class
                    else:
                        img = np.zeros([1, 1000])
                        images2_batch[i, :, :] = img
                    if(image_file_name3 in self.image_vec_dict):
                        img = self.image_vec_dict[image_file_name3]
                        images3_batch[i, :, :] = img
                        # Store class
                    else:
                        img = np.zeros([1, 1000])
                        images3_batch[i, :, :] = img

                    if (image_file_name4 in self.image_vec_dict):

                        img = self.image_vec_dict[image_file_name3]
                        images4_batch[i, :, :] = img
                        # Store class
                    else:
                        img = np.zeros([1, 1000])
                        images4_batch[i, :, :] = img

                    if (image_file_name5 in self.image_vec_dict):
                        img = self.image_vec_dict[image_file_name3]
                        images5_batch[i, :, :] = img
                    else:
                        img = np.zeros([1, 1000])
                        images5_batch[i, :, :] = img
                else:
                    print("Exception in indexing in image list less "+str(index)+" " +str(self.image_file_list))
            except Exception as e:
                print("Exception in data generation.")
                print(e)
        if self.im_num == 1:
            return images1_batch, text_batch, sim_batch, bert_batch, y
        elif self.im_num == 2:
            return images1_batch, images2_batch, text_batch, sim_batch, bert_batch, y
        elif self.im_num == 3:
            return images1_batch, images2_batch, images3_batch, text_batch, sim_batch, bert_batch, y
        elif self.im_num == 4:
            return images1_batch, images2_batch, images3_batch, images4_batch, text_batch, sim_batch, bert_batch, y
        elif self.im_num == 5:
            return images1_batch, images2_batch, images3_batch, images4_batch, images5_batch, text_batch, sim_batch, bert_batch, y


import matplotlib.pyplot as plt
from HPSOGWO import HPSOGWO
from GWO import GWO
import benchmarks
from PSO import PSO

function_to_be_used = benchmarks.F5

s = GWO(function_to_be_used)
s.opt()
x1 = s.return_result()

d = HPSOGWO(function_to_be_used)
d.opt()
x2 = d.return_result()

pso = PSO(function_to_be_used)
pso.random_init()
pso.start()
x3 = pso.return_result()

# PLOT
plt.figure()
plt.plot(x1)
plt.plot(x2)
plt.plot(x3)
plt.grid()
plt.legend(["GWO", "HPSOGWO", "PSO"], loc="upper right")
plt.title("Comparision of HPSOGWO with PSO and GWO")
plt.xlabel("Number of Iterations")
plt.ylabel("Best Score")
plt.show()


class Solution(object):
    def getHint(self, secret, guess):
        """
        :type secret: str
        :type guess: str
        :rtype: str
        """
        remain = {}
        bulls = 0
        glist = list(guess)
        for i in range(len(secret)):
            if secret[i] == glist[i]:
                bulls += 1
                glist[i] = ' '
            elif remain.has_key(secret[i]):
                remain[secret[i]] += 1
            else:
                remain[secret[i]] = 1
        cows = 0
        for c in glist:
            if remain.has_key(c) and remain[c] > 0:
                cows += 1
                remain[c] -= 1
        return str(bulls) + "A" + str(cows) + "B"


import argparse
import sys

parser = argparse.ArgumentParser()

parser.add_argument('-o', # Name of option
                dest='outfile', # Variable name to store option (optional)
                help='output file name', # Help text (optional)
                )
parser.add_argument('-a', # Name of option short form
                    dest='infile_a', # Variable name to store option (optional)
                    help='Input file name', # Help text (optional)
                    )

parser.add_argument('-b', # Name of option short form
                    dest='infile_b', # Variable name to store option (optional)
                    help='Input file name', # Help text (optional)
                    )
parser.add_argument('-stdout',
                    action='store_true',
                    default = False,
                    )
args = parser.parse_args() # Parse arguments

with open(args.outfile, mode="wt") as bed_intersect:
    with open(args.infile_a,mode="r") as bed_a:
        with open(args.infile_b,mode="r") as bed_b: # Create file handle
            for index_a, line_a in enumerate(bed_a):
                bed_b.seek(0)
                for index_b, line_b in enumerate(bed_b): # Iterate line by line through the file
                    col_a = line_a.strip().split('\t')  #make tuple of columns
                    chr_a = col_a[0]
                    start_a = int(col_a[1])
                    end_a = int(col_a[2])
                    col_b = line_b.strip().split('\t')  #make tuple of columns
                    chr_b = col_b[0]
                    start_b = int(col_b[1])
                    end_b = int(col_b[2])

                    if chr_a == chr_b:
                            if start_a >= start_b and start_a <= end_b:
                                bed_intersect.write(f'{chr_a}\t{start_a}\t{end_a}\n')
                                if args.stdout == True:
                                    sys.stdout.write(f'{chr_a}\t{start_a}\t{end_a}\n')
                                break
                            elif start_b >= start_a and start_b <= end_a:
                                bed_intersect.write(f'{chr_b}\t{start_b}\t{end_b}\n')
                                if args.stdout == True:
                                    sys.stdout.write(f'{chr_b}\t{start_b}\t{end_b}\n')


#coding=utf-8
__author__ = 'xiyuanbupt'
# e-mail : xywbupt@gmail.com
from linkedlist.listNode import ListNode

'''
83. Remove Duplicates from Sorted List   Add to List QuestionEditorial Solution  My Submissions
Total Accepted: 153073
Total Submissions: 396107
Difficulty: Easy
Contributors: Admin
Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.

'''

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):

    # 68.25%
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head:
            return head

        res = ListNode(head.val)
        curr = res
        curr_val = head.val
        head = head.next
        while head:
            if head.val != curr_val:
                curr.next = ListNode(head.val)
                curr = curr.next
                curr_val = head.val
            head = head.next
        return res

    def recursionDelete(self, head):
        if not head:
            return head
        curr = head.next
        while curr and curr.val == head.val:
            curr = curr.next
        head.next = self.recursionDelete(curr)
        return head