import collections
import datetime
import logging

import pajbot.models
from pajbot.modules import BaseModule
from pajbot.modules import ModuleType
from pajbot.modules.basic import BasicCommandsModule

log = logging.getLogger(__name__)

class DebugModule(BaseModule):

    ID = __name__.split('.')[-1]
    NAME = '!debug'
    DESCRIPTION = 'Debug commands and users'
    CATEGORY = 'Feature'
    ENABLED_DEFAULT = True
    MODULE_TYPE = ModuleType.TYPE_ALWAYS_ENABLED
    PARENT_MODULE = BasicCommandsModule

    def debug_command(self, **options):
        message = options['message']
        bot = options['bot']
        source = options['source']

        if message and len(message) > 0:
            try:
                id = int(message)
            except Exception:
                id = -1

            command = False

            if id == -1:
                potential_cmd = ''.join(message.split(' ')[:1]).lower()
                if potential_cmd in bot.commands:
                    command = bot.commands[potential_cmd]
            else:
                for key, potential_cmd in bot.commands.items():
                    if potential_cmd.id == id:
                        command = potential_cmd
                        break

            if not command:
                bot.whisper(source.username, 'No command found with the given parameters.')
                return False

            data = collections.OrderedDict()
            data['id'] = command.id
            data['level'] = command.level
            data['type'] = command.action.type if command.action is not None else '???'
            data['cost'] = command.cost
            data['cd_all'] = command.delay_all
            data['cd_user'] = command.delay_user
            data['mod_only'] = command.mod_only

            if data['type'] == 'message':
                data['response'] = command.action.response
            elif data['type'] == 'func' or data['type'] == 'rawfunc':
                data['cb'] = command.action.cb.__name__

            bot.whisper(source.username, ', '.join(['%s=%s' % (key, value) for (key, value) in data.items()]))
        else:
            bot.whisper(source.username, 'Usage: !debug command (COMMAND_ID|COMMAND_ALIAS)')
            return False

    def debug_user(self, **options):
        message = options['message']
        bot = options['bot']
        source = options['source']

        if message and len(message) > 0:
            username = message.split(' ')[0].strip().lower()
            user = bot.users.find(username)

            if user is None:
                bot.whisper(source.username, 'No user with this username found.')
                return False

            data = collections.OrderedDict()
            data['id'] = user.id
            data['level'] = user.level
            data['num_lines'] = user.num_lines
            data['points'] = user.points
            data['last_seen'] = user.last_seen.strftime('%Y-%m-%d %H:%M:%S %Z')
            try:
                data['last_active'] = user.last_active.strftime('%Y-%m-%d %H:%M:%S %Z')
            except:
                pass
            data['ignored'] = user.ignored
            data['banned'] = user.banned
            data['tokens'] = user.tokens

            bot.whisper(source.username, ', '.join(['%s=%s' % (key, value) for (key, value) in data.items()]))
        else:
            bot.whisper(source.username, 'Usage: !debug user USERNAME')
            return False

    def debug_tags(self, **options):
        message = options['message']
        bot = options['bot']
        source = options['source']

        if message and len(message) > 0:
            username = message.split(' ')[0].strip().lower()
            user = bot.users.find(username)

            if user is None:
                bot.whisper(source.username, 'No user with this username found.')
                return False

            data = collections.OrderedDict()
            user_tags = user.get_tags()

            if len(user_tags) == 0:
                bot.whisper(source.username, 'This user does not have any tags')
            else:
                for tag in user_tags:
                    data[tag] = datetime.datetime.fromtimestamp(user_tags[tag]).strftime('%Y-%m-%d')

                bot.whisper(source.username, '{} have the following tags: '.format(user.username_raw) + ', '.join(['%s until %s' % (key, value) for (key, value) in data.items()]))
        else:
            bot.whisper(source.username, 'Usage: !debug user USERNAME')
            return False

    def load_commands(self, **options):
        self.commands['debug'] = pajbot.models.command.Command.multiaction_command(
                level=100,
                delay_all=0,
                delay_user=0,
                default=None,
                commands={
                    'command': pajbot.models.command.Command.raw_command(self.debug_command,
                        level=250,
                        description='Debug a command',
                        examples=[
                            pajbot.models.command.CommandExample(None, 'Debug a command',
                                chat='user:!debug command ping\n'
                                'bot>user: id=210, level=100, type=message, cost=0, cd_all=10, cd_user=30, mod_only=False, response=Snusbot has been online for $(tb:bot_uptime)',
                                description='').parse(),
                            ]),
                    'user': pajbot.models.command.Command.raw_command(self.debug_user,
                        level=250,
                        description='Debug a user',
                        examples=[
                            pajbot.models.command.CommandExample(None, 'Debug a user',
                                chat='user:!debug user snusbot\n'
                                'bot>user: id=123, level=100, num_lines=45, points=225,  last_seen=2016-04-05 17:56:23 CEST, last_active=2016-04-05 17:56:07 CEST, ignored=False, banned=False, tokens=0',
                                description='').parse(),
                            ]),
                    'tags': pajbot.models.command.Command.raw_command(self.debug_tags,
                        level=100,
                        delay_all=0,
                        delay_user=5,
                        description='Debug tags for a user',
                        examples=[
                            pajbot.models.command.CommandExample(None, 'Debug tags for a user',
                                chat='user:!debug tags pajbot\n'
                                'bot>user: pajbot have the following tags: pajlada_sub until 2016-04-28',
                                description='').parse(),
                            ])
                    })


from picamera import PiCamera
import numpy as np
import matplotlib.pyplot as plt

Camera = PiCamera()                                                                      # Initialize Camera
ImageSize = (1920, 1080)                                                                 # Full HD
CameraResolution = (int(16*np.floor(ImageSize[1]/32)),int(16*np.floor(ImageSize[0]/32))) # Adjust resolution
Camera.resolution = (CameraResolution[1],CameraResolution[0])                            # Define Resolution
Camera.zoom = (0.3, 0.7, 0.3, 0.3)                                                       # Zoom in Object
RGBImage = np.empty((CameraResolution[0],CameraResolution[1],3),dtype=np.uint8)          # Preallocate Image
x,y = np.meshgrid(np.arange(np.shape(RGBImage)[1]),np.arange(0,np.shape(RGBImage)[0]))   # Setup 2x2
while True:
    try:
        input("Press enter to capture a RGB Component Plot or press CTRL+C to exit'")
        Camera.capture(RGBImage,'rgb')                                                   # Capture RGB image
        fig,axn = plt.subplots(2,2,sharex=True,sharey=True)                              # Setup 2x2 plot grid
        fig.set_size_inches(9,7)                                                         # Set plot size
        axn[0,0].pcolormesh(x,y,RGBImage[:,:,0],cmap='gray')                             # Get R Image Data
        axn[0,1].pcolormesh(x,y,RGBImage[:,:,1],cmap='gray')                             # Get G Image Data
        axn[1,0].pcolormesh(x,y,RGBImage[:,:,2],cmap='gray')                             # Get B Image Data
        axn[1,1].imshow(RGBImage,label='Full Color')                                     # Get RGB Image Data
        axn[0,0].title.set_text('Red')                                                   # Set plot 1 Title
        axn[0,1].title.set_text('Green')                                                 # Set plot 2 Title
        axn[1,0].title.set_text('Blue')                                                  # Set plot 3 Title
        axn[1,1].title.set_text('All')                                                   # Set plot 4 Title
        print('Plotting images...')
        plt.imshow(RGBImage)                                                             # Display as Image
        RGBImage = np.empty((CameraResolution[0],CameraResolution[1],3),dtype=np.uint8)  # Clear Memory
        plt.savefig('Component_plot.png',dpi=150)                                        # Save Component Plot
        plt.show()                                                                       # Show Image
        plt.close()
    except KeyboardInterrupt:                                                            # Press CTRL+C to exit
        break


#! /usr/bin/env python3
"""
Script to compare outputs of find-cpu-hogs.sh

Alex Shires
14-05-2020
"""
import logging
import os
import sys
from typing import Dict

import pandas as pd
from matplotlib import pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import seaborn as sns
import numpy as np

from cpu_utils import get_file, process_df, process_names

logger = logging.getLogger(__name__)
logging.basicConfig(level=10)

if __name__ == '__main__':

    file1 = sys.argv[1]
    file2 = sys.argv[2]
    logger.debug(f"comparsiong {file1} and {file2}")

    df1 = get_file(file1)
    df2 = get_file(file2)

    df1_dict = process_df(df1)
    df2_dict = process_df(df2)

    legend1 = file1[:-4].split("_")[1]
    legend2 = file2[:-4].split("_")[1]

    with PdfPages(f"cpu_comparison_of_{legend1}_{legend2}.pdf") as pdf:
        for process_name in df1_dict.keys():
            cpu_ave_data1 = df1_dict[process_name].rolling(window=40).mean()
            if cpu_ave_data1.shape[0] == 0:
                continue
            else:
                cpu_ave_data1.plot(label=process_name)
        plt.xlabel("Time")
        plt.ylabel("total CPU usage (%)")
        plt.legend(prop={'size': 6})
        plt.title(f"Process CPU average - rolling {legend1}")
        plt.tight_layout()
        pdf.savefig()
        plt.clf()
        # rolling 2
        for process_name in df2_dict.keys():
            cpu_ave_data2 = df2_dict[process_name].rolling(window=40).mean()
            if cpu_ave_data2.shape[0] == 0:
                continue
            else:
                cpu_ave_data2.plot(label=process_name)
        plt.xlabel("Time")
        plt.ylabel("total CPU usage (%)")
        plt.legend(prop={'size': 6})
        plt.title(f"Process CPU average - rolling {legend2}")
        plt.tight_layout()
        pdf.savefig()
        plt.clf()
        # histograms
        for process_name in process_names:
            if process_name not in df1_dict.keys() or process_name not in df2_dict.keys():
                continue
            cpu_ave_data1 = df1_dict[process_name]
            cpu_ave_data2 = df2_dict[process_name]
            if cpu_ave_data1.shape[0] == 0 or cpu_ave_data2.shape[0] == 0:
                continue
            cpu_ave_data1.hist(bins=50, label=legend1, alpha=0.5, density=True)
            cpu_ave_data2.hist(bins=50, label=legend2, alpha=0.5, density=True)
            plt.xlabel(f"% CPU usage")
            plt.ylabel("frequency of usage")
            plt.legend()
            plt.title(f"Histogram of {process_name} measurements")
            pdf.savefig()
            plt.tight_layout()
            plt.clf()


from copy import deepcopy
from typing import Dict, List

from gsy_framework.constants_limits import FLOATING_POINT_TOLERANCE
from gsy_framework.sim_results.results_abc import ResultsBaseClass
from gsy_framework.utils import (add_or_create_key,
                                 area_name_from_area_or_ma_name,
                                 convert_pendulum_to_str_in_dict,
                                 datetime_str_to_ui_formatted_datetime_str,
                                 round_floats_for_ui,
                                 ui_str_to_pendulum_datetime)

traded_energy_profile_example = {
    "area_uuid1": {
        "sold_energy": {
            "trade_seller1": {
                "accumulated": {
                    "time_slot1": 0,
                    "time_slot2": 0
                },
                "trade_buyer1": {
                    "time_slot1": 0,
                    "time_slot2": 0
                },
                "trade_buyer2": {
                    "time_slot1": 0,
                    "time_slot2": 0
                }
            }
        },
        "bought_energy": {
            "trade_buyer1": {
                "accumulated": {
                    "time_slot1": 0,
                    "time_slot2": 0
                },
                "trade_seller1": {
                    "time_slot1": 0
                }
            }
        }
    }
}

class EnergyTradeProfile(ResultsBaseClass):
    """
    Total energy traded for each market and energy asset and their penalty for not trading
    their required energy.
    """
    def __init__(self, should_export_plots: bool):
        self.traded_energy_profile: traded_energy_profile_example = {}
        self.traded_energy_current: traded_energy_profile_example = {}
        self.should_export_plots: bool = should_export_plots

    def update(self, area_result_dict=None, core_stats=None, current_market_slot=None):
        if not self._has_update_parameters(
                area_result_dict, core_stats, current_market_slot):
            return
        current_market_slot = datetime_str_to_ui_formatted_datetime_str(current_market_slot)
        self.traded_energy_current = {}
        self._populate_area_children_data(area_result_dict, core_stats, current_market_slot)

    def _populate_area_children_data(self, area_result_dict, core_stats, current_market_slot):
        if area_result_dict.get("children") is not None:
            for child in area_result_dict["children"]:
                self._populate_area_children_data(child, core_stats, current_market_slot)
            if self.should_export_plots:
                self._update_sold_bought_energy(area_result_dict, core_stats, current_market_slot)
            else:
                self._update_current_energy_trade_profile(
                    area_result_dict, core_stats, current_market_slot
                )

    def _update_current_energy_trade_profile(self, area_result_dict, core_stats,
                                             current_market_slot):
        if current_market_slot is not None:
            self.traded_energy_current[area_result_dict["uuid"]] = {
                "sold_energy": {}, "bought_energy": {}
            }
            self._calculate_devices_sold_bought_energy(
                self.traded_energy_current[area_result_dict["uuid"]],
                area_result_dict,
                core_stats,
                current_market_slot
            )
            self._round_energy_trade_profile(self.traded_energy_current)

    def _update_sold_bought_energy(self, area_result_dict, core_stats, current_market_slot):
        if current_market_slot is not None:
            area_name = area_result_dict["name"]
            self.traded_energy_current[area_name] = {"sold_energy": {}, "bought_energy": {}}
            self._calculate_devices_sold_bought_energy(
                self.traded_energy_current[area_name], area_result_dict,
                core_stats, current_market_slot)

            traded_energy_current_name = {area_name: self.traded_energy_current[area_name]}
            self.traded_energy_profile = self.merge_results_to_global(
                traded_energy_current_name, self.traded_energy_profile,
                [current_market_slot])

    @staticmethod
    def _calculate_devices_sold_bought_energy(res_dict, area_result_dict, core_stats,
                                              current_market_slot):
        if area_result_dict["uuid"] not in core_stats:
            return
        if core_stats[area_result_dict["uuid"]] == {}:
            return
        area_core_trades = EnergyTradeProfile._get_trades_from_core_stats(
            core_stats, area_result_dict["uuid"])
        for trade in area_core_trades:
            trade_seller = area_name_from_area_or_ma_name(trade["seller"]["name"])
            trade_buyer = area_name_from_area_or_ma_name(trade["buyer"]["name"])

            if trade_seller not in res_dict["sold_energy"]:
                res_dict["sold_energy"][trade_seller] = {"accumulated": {}}
            if trade_buyer not in res_dict["sold_energy"][trade_seller]:
                res_dict["sold_energy"][trade_seller][trade_buyer] = {}
            trade_energy = trade["energy"]
            if trade_energy > FLOATING_POINT_TOLERANCE:
                add_or_create_key(res_dict["sold_energy"][trade_seller]["accumulated"],
                                  current_market_slot, trade_energy)
                add_or_create_key(res_dict["sold_energy"][trade_seller][trade_buyer],
                                  current_market_slot, trade_energy)
            if trade_buyer not in res_dict["bought_energy"]:
                res_dict["bought_energy"][trade_buyer] = {"accumulated": {}}
            if trade_seller not in res_dict["bought_energy"][trade_buyer]:
                res_dict["bought_energy"][trade_buyer][trade_seller] = {}
            if trade_energy > FLOATING_POINT_TOLERANCE:
                add_or_create_key(res_dict["bought_energy"][trade_buyer]["accumulated"],
                                  current_market_slot, trade_energy)
                add_or_create_key(res_dict["bought_energy"][trade_buyer][trade_seller],
                                  current_market_slot, trade_energy)

    @staticmethod
    def _round_energy_trade_profile(energy_profile: Dict):
        for area_energy_mapping in energy_profile.values():
            for sold_bought in ("sold_energy", "bought_energy"):
                if sold_bought not in area_energy_mapping:
                    continue
                for trades_mapping in area_energy_mapping[sold_bought].values():
                    for trades_timestamps in trades_mapping.values():
                        for timestamp in trades_timestamps.keys():
                            trades_timestamps[timestamp] = round_floats_for_ui(
                                trades_timestamps[timestamp])
        return energy_profile

    @staticmethod
    def _add_sold_bought_lists(trades_profile: Dict):
        for trades_mapping in trades_profile.values():
            for sold_bought in ("sold_energy", "bought_energy"):
                trades_mapping[sold_bought + "_lists"] = (
                    dict((key, {}) for key in trades_mapping[sold_bought].keys()))
                for node in trades_mapping[sold_bought].keys():
                    trades_mapping[sold_bought + "_lists"][node]["slot"] = (
                        list(trades_mapping[sold_bought][node]["accumulated"].keys()))
                    trades_mapping[sold_bought + "_lists"][node]["energy"] = (
                        list(trades_mapping[sold_bought][node]["accumulated"].values()))

    @staticmethod
    def _convert_timestamp_strings_to_datetimes(profile: Dict) -> Dict:
        out_dict = {}
        for key in profile.keys():
            out_dict[key] = {}
            for sold_bought in ("sold_energy", "bought_energy"):
                if sold_bought not in profile[key]:
                    continue
                out_dict[key][sold_bought] = {}
                for dev in profile[key][sold_bought].keys():
                    out_dict[key][sold_bought][dev] = {}
                    for target in profile[key][sold_bought][dev].keys():
                        out_dict[key][sold_bought][dev][target] = {}
                        for timestamp_str in profile[key][sold_bought][dev][target].keys():
                            datetime_obj = ui_str_to_pendulum_datetime(timestamp_str)
                            out_dict[key][sold_bought][dev][target][datetime_obj] = (
                                profile[key][sold_bought][dev][target][timestamp_str])
        return out_dict

    @staticmethod
    def merge_results_to_global(market_results: Dict, global_results: Dict, slot_list: List):
        if not global_results:
            global_trade = market_results
            return global_trade
        for area_uuid in market_results:
            if global_results.get(area_uuid, {}) == {}:
                global_results[area_uuid] = {"sold_energy": {}, "bought_energy": {}}
            for sold_bought in market_results[area_uuid]:
                for target_area in market_results[area_uuid][sold_bought]:
                    if target_area not in global_results[area_uuid][sold_bought]:
                        global_results[area_uuid][sold_bought][target_area] = {}
                    for source_area in market_results[area_uuid][sold_bought][target_area]:
                        if source_area not in global_results[area_uuid][sold_bought][target_area]:
                            global_results[area_uuid][sold_bought][target_area][source_area] = (
                                {i: 0 for i in slot_list})
                        global_results[area_uuid][sold_bought][target_area][source_area].update(
                            market_results[area_uuid][sold_bought][target_area][source_area]
                        )
        return global_results

    def restore_area_results_state(self, area_dict: Dict, last_known_state_data: Dict):
        pass

    @property
    def plot_results(self) -> Dict:
        """Return the energy trade profile data to be plotted."""
        traded_profile_for_plot = self._convert_timestamp_strings_to_datetimes(
                deepcopy(self.traded_energy_profile)
        )
        self._add_sold_bought_lists(traded_profile_for_plot)
        return traded_profile_for_plot

    @property
    def raw_results(self) -> str:
        return convert_pendulum_to_str_in_dict(
            self.traded_energy_profile, {}, ui_format=True)

    @property
    def ui_formatted_results(self) -> str:
        return convert_pendulum_to_str_in_dict(
            self.traded_energy_current, {}, ui_format=True)

    def memory_allocation_size_kb(self) -> float:
        return self._calculate_memory_allocated_by_objects([
            self.traded_energy_current, self.traded_energy_profile
        ])


from dynamixel_sdk import *                    # Uses Dynamixel SDK library

##  ML, MX, MH   #############################
# Control table address
ADDR_PRO_TORQUE_ENABLE      = 64               # Control table address is different in Dynamixel model
ADDR_PRO_GOAL_VEL           = 112
ADDR_PRO_GOAL_POS           = 116
ADDR_PRO_GOAL_POSVEL        = 112

ADDR_PRO_PRESENT_POS        = 132
ADDR_PRO_MOVING             = 122

# Data Byte Length
LEN_PRO_GOAL_POS            = 4
LEN_PRO_GOAL_VEL            = 4
LEN_PRO_GOAL_POSVEL         = 8

LEN_PRO_PRESENT_POS         = 4
LEN_PRO_MOVING              = 1

# Protocol version
PRO_PROTOCOL_VERSION         = 2.0               # See which protocol version is used in the Dynamixel

##  AX, MX   #############################
# Control table address
ADDR_AXMX_TORQUE_ENABLE      = 24               # Control table address is different in Dynamixel model
ADDR_AXMX_GOAL_VEL           = 32
ADDR_AXMX_GOAL_POS           = 30
ADDR_AXMX_GOAL_POSVEL        = 30

ADDR_AXMX_PRESENT_POS        = 36
ADDR_AXMX_MOVING             = 46

# Data Byte Length
LEN_AXMX_GOAL_POS            = 2
LEN_AXMX_GOAL_VEL            = 2
LEN_AXMX_GOAL_POSVEL         = 4

LEN_AXMX_PRESENT_POS         = 2
LEN_AXMX_MOVING              = 1

# Protocol version
AXMX_PROTOCOL_VERSION        = 1.0               # See which protocol version is used in the Dynamixel

# Default setting
BAUDRATE                    = 1000000            # Dynamixel default baudrate : 57600
DEVICENAME                  = "COM5"            # Check which port is being used on your controller
                                                # ex) Windows: "COM1"   Linux: "/dev/ttyUSB0" Mac: "/dev/tty.usbserial-*"
TORQUE_ENABLE               = 1                 # Value for enabling the torque
TORQUE_DISABLE              = 0                 # Value for disabling the torque
TYPE_PRO_P2                 = 2.0
TYPE_AXMX_P1                = 1.0

class motorLLC():
    def __init__(self):
        self.motorNo = 2
        self.IDs = [1, 2]
        self.motorType = [2.0, 2.0]
        self.baudrate = BAUDRATE
        self.device = DEVICENAME

        self.type_PRO_P2_used = False
        self.type_AXMX_P1_used = False

        for ii in range(0, self.motorNo):
            if self.motorType[ii] == TYPE_PRO_P2:
                self.type_PRO_P2_used = True
            if self.motorType[ii] == TYPE_AXMX_P1:
                self.type_AXMX_P1_used = True

    def set_motor_IDs(self, motorNo, IDs, type):
        if (motorNo == len(IDs)) and (motorNo == len(type)):
            self.motorNo = motorNo
            self.IDs = IDs
            self.motorType = type

            self.type_PRO_P2_used = False
            self.type_AXMX_P1_used = False

            for ii in range(0, self.motorNo):
                if self.motorType[ii] == TYPE_PRO_P2:
                    self.type_PRO_P2_used = True
                if self.motorType[ii] == TYPE_AXMX_P1:
                    self.type_AXMX_P1_used = True

        else:
            print("Motor Number is not same")

    def set_baudrate(self, baudrate):
        self.baudrate = baudrate

    def set_devicename(self, devicename):
        self.device = devicename

    def open(self):
        # Initialize PortHandler instance
        self.portHandler = PortHandler(self.device)

        if self.type_AXMX_P1_used:
            # Initialize PacketHandler instance
            self.packetHandlerP1 = PacketHandler(AXMX_PROTOCOL_VERSION)

            self.groupSyncWriteP1_pos = GroupSyncWrite(self.portHandler, self.packetHandlerP1, ADDR_AXMX_GOAL_POS, LEN_AXMX_GOAL_POS)
            self.groupSyncWriteP1_posvel = GroupSyncWrite(self.portHandler, self.packetHandlerP1, ADDR_AXMX_GOAL_POSVEL, LEN_AXMX_GOAL_POSVEL)

            # AX motor cannot use GroupBulkRead function, instead read2ByteTXRX needs to be used.
            #self.groupBulkReadP1_pos = GroupBulkRead(self.portHandler, self.packetHandlerP1)
            #self.groupBulkReadP1_moving = GroupBulkRead(self.portHandler, self.packetHandlerP1)

        if self.type_PRO_P2_used:
            # Initialize PacketHandler instance
            self.packetHandlerP2 = PacketHandler(PRO_PROTOCOL_VERSION)

            self.groupSyncWriteP2_pos = GroupSyncWrite(self.portHandler, self.packetHandlerP2, ADDR_PRO_GOAL_POS, LEN_PRO_GOAL_POS)
            self.groupSyncWriteP2_posvel = GroupSyncWrite(self.portHandler, self.packetHandlerP2, ADDR_PRO_GOAL_POSVEL, LEN_PRO_GOAL_POSVEL)

            self.groupBulkReadP2_pos = GroupBulkRead(self.portHandler, self.packetHandlerP2)
            self.groupBulkReadP2_moving = GroupBulkRead(self.portHandler, self.packetHandlerP2)

        # Add parameter storage for Dynamixel present position value
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                dxl_addparam_result = self.groupBulkReadP2_pos.addParam(motorID, ADDR_PRO_PRESENT_POS, LEN_PRO_PRESENT_POS)
                if dxl_addparam_result != True:
                    print("[ID:%03d] groupBulkRead addparam failed_POS" % motorID)
                    quit()
                dxl_addparam_result = self.groupBulkReadP2_moving.addParam(motorID, ADDR_PRO_MOVING, LEN_PRO_MOVING)
                if dxl_addparam_result != True:
                    print("[ID:%03d] groupBulkRead addparam failed_MOVING" % motorID)
                    quit()
            #else:   #if self.motorType[ii] == TYPE_AXMX_P1:
                #dxl_addparam_result = self.groupBulkReadP1_pos.addParam(motorID, ADDR_AXMX_PRESENT_POS, LEN_AXMX_PRESENT_POS)
                #if dxl_addparam_result != True:
                #    print("[ID:%03d] groupBulkRead addparam failed_POS" % motorID)
                #    quit()
                #dxl_addparam_result = self.groupBulkReadP1_moving.addParam(motorID, ADDR_AXMX_MOVING, LEN_AXMX_MOVING)
                #if dxl_addparam_result != True:
                #    print("[ID:%03d] groupBulkRead addparam failed_MOVING" % motorID)
                #    quit()

        # Open port
        if self.portHandler.openPort():
            print("Succeeded to open the port")
        else:
            print("Failed to open the port")
            quit()

        # Set port baudrate
        if self.portHandler.setBaudRate(BAUDRATE):
            print("Succeeded to change the baudrate")
        else:
            print("Failed to change the baudrate")
            quit()

    def torque_enable(self):
        # Enable Dynamixel#1 Torque
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                dxl_comm_result, dxl_error = self.packetHandlerP2.write1ByteTxRx(self.portHandler, motorID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % self.packetHandlerP2.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % self.packetHandlerP2.getRxPacketError(dxl_error))
                else:
                    print("Dynamixel#%d has been successfully connected" % motorID)
            else:  # if self.motorType[ii] == TYPE_AXMX_P1:
                dxl_comm_result, dxl_error = self.packetHandlerP1.write1ByteTxRx(self.portHandler, motorID, ADDR_AXMX_TORQUE_ENABLE, TORQUE_ENABLE)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % self.packetHandlerP1.getRxPacketError(dxl_error))
                else:
                    print("Dynamixel#%d has been successfully connected" % motorID)

    def cvtToLongWord(self, pos):
        posi = int(pos)
        return [DXL_LOBYTE(DXL_LOWORD(posi)), DXL_HIBYTE(DXL_LOWORD(posi)), DXL_LOBYTE(DXL_HIWORD(posi)), DXL_HIBYTE(DXL_HIWORD(posi))]

    def cvtToWord(self, pos):
        posi = int(pos)
        return [DXL_LOBYTE(posi), DXL_HIBYTE(posi)]

    def moveTo(self, positions_pulse):
        if self.motorNo != len(positions_pulse):
            print("Motor Number is not same")
            quit()

        # Allocate goal position value into byte array
        dxl_goal_position = []
        for ii in range(0, self.motorNo):
            pos = positions_pulse[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                dxl_goal_position.append(self.cvtToLongWord(pos))
            else: #if self.motorType[ii] == TYPE_AXMX_P1:
                dxl_goal_position.append(self.cvtToWord(pos))

        # Add Dynamixel#1 goal position value to the Syncwrite parameter storage
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                dxl_addparam_result = self.groupSyncWriteP2_pos.addParam(motorID, dxl_goal_position[ii])
                if dxl_addparam_result != True:
                    print("[ID:%03d] groupSyncWriteP2_pos addparam failed" % motorID)
                    quit()
            else:    #if self.motorType[ii] == TYPE_AXMX_P1:
                dxl_addparam_result = self.groupSyncWriteP1_pos.addParam(motorID, dxl_goal_position[ii])
                if dxl_addparam_result != True:
                    print("[ID:%03d] groupSyncWriteP1_pos addparam failed - Ln208" % motorID)
                    quit()

        # Syncwrite goal position
        if self.type_AXMX_P1_used:
            dxl_comm_result = self.groupSyncWriteP1_pos.txPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))
            # Clear syncwrite parameter storage
            self.groupSyncWriteP1_pos.clearParam()

        if self.type_PRO_P2_used:
            dxl_comm_result = self.groupSyncWriteP2_pos.txPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % self.packetHandlerP2.getTxRxResult(dxl_comm_result))
            # Clear syncwrite parameter storage
            self.groupSyncWriteP2_pos.clearParam()

    def moveTo_wVel_pps(self, positions_pulse, velocities_pps):
        pulse_per_rotation = 4096.0
        unit_of_rpm = 0.229
        min_to_sec = 60.0

        coeff_pps_to_dxlrpm = min_to_sec/pulse_per_rotation/unit_of_rpm

        vel_rpm = []
        for ii in range(0, len(velocities_pps)):
            vel_rpm.append(velocities_pps[ii]*coeff_pps_to_dxlrpm)

        self.moveTo_wVel_rpm(positions_pulse, vel_rpm)

    # the unit of velocity (dxlrpm) is 0.229 rev/min.
    def moveTo_wVel_rpm(self, positions_pulse, velocities_dxlrpm):
        if self.motorNo != len(positions_pulse):
            print("Motor Number is not same as length of positions")
            quit()

        if self.motorNo != len(velocities_dxlrpm):
            print("Motor Number is not same as length of velocities")
            quit()

        # Allocate goal position value into byte array
        dxl_goalP2_velpos = []
        dxl_goalP1_posvel = []
        for ii in range(0, self.motorNo):
            if self.motorType[ii] == TYPE_PRO_P2:
                if abs(velocities_dxlrpm[ii])<10:
                    if velocities_dxlrpm[ii] < 0:
                        velpos = self.cvtToLongWord(-10)
                    else:
                        velpos = self.cvtToLongWord(10)
                else:
                    velpos = self.cvtToLongWord(velocities_dxlrpm[ii])
                velpos.extend(self.cvtToLongWord(positions_pulse[ii]))
                dxl_goalP2_velpos.append(velpos)

            else:   #if self.motorType[ii] == TYPE_AXMX_P1:
                posvel = self.cvtToWord(positions_pulse[ii])
                if abs(velocities_dxlrpm[ii]) < 10:
                    if velocities_dxlrpm[ii] < 0:
                        posvel.extend(self.cvtToWord(-10))
                    else:
                        posvel.extend(self.cvtToWord(10))
                else:
                    posvel.extend(self.cvtToWord(velocities_dxlrpm[ii]))
                dxl_goalP1_posvel.append(posvel)

        # Add Dynamixel's goal position value to the Syncwrite parameter storage
        ii_P1 = 0
        ii_P2 = 0
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                dxl_addparam_result = self.groupSyncWriteP2_posvel.addParam(motorID, dxl_goalP2_velpos[ii_P2])
                ii_P2 += 1
                if dxl_addparam_result != True:
                    print("[ID:%03d] groupSyncWriteP2_posvel addparam failed" % motorID)
                    quit()
            else:   #if self.motorType[ii] == TYPE_AXMX_P1:
                dxl_addparam_result = self.groupSyncWriteP1_posvel.addParam(motorID, dxl_goalP1_posvel[ii_P1])
                ii_P1 += 1
                if dxl_addparam_result != True:
                    print("[ID:%03d] groupSyncWriteP1_posvel addparam failed" % motorID)
                    quit()

        if self.type_PRO_P2_used:
            # Syncwrite goal position
            dxl_comm_result = self.groupSyncWriteP2_posvel.txPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % self.packetHandlerP2.getTxRxResult(dxl_comm_result))
            # Clear syncwrite parameter storage
            self.groupSyncWriteP2_posvel.clearParam()

        if self.type_AXMX_P1_used:
            # Syncwrite goal position
            dxl_comm_result = self.groupSyncWriteP1_posvel.txPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))
            # Clear syncwrite parameter storage
            self.groupSyncWriteP1_posvel.clearParam()

    def readPos(self):
        # Syncread present position
        #if self.type_AXMX_P1_used:
        #    dxl_comm_result = self.groupBulkReadP1_pos.txRxPacket()
        #    if dxl_comm_result != COMM_SUCCESS:
        #        print("%s - Ln319" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))

        if self.type_PRO_P2_used:
            dxl_comm_result = self.groupBulkReadP2_pos.txRxPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s - Ln324" % self.packetHandlerP2.getTxRxResult(dxl_comm_result))

        dxl_present_pos = []
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                # Check if groupbulkread data of Dynamixel is available
                dxl_getdata_result = self.groupBulkReadP2_pos.isAvailable(motorID, ADDR_PRO_PRESENT_POS, LEN_PRO_PRESENT_POS)
                if dxl_getdata_result != True:
                    print("[ID:%03d] groupSyncRead getdata failed - Ln333" % motorID)
                    quit()
                # Get Dynamixel present position value
                dxl_present_pos.append(self.groupBulkReadP2_pos.getData(motorID, ADDR_PRO_PRESENT_POS, LEN_PRO_PRESENT_POS))

            else:   #if self.motorType[ii] == TYPE_AXMX_P1:
                p_pos, dxl_comm_result, dxl_error = self.packetHandlerP1.read2ByteTxRx(self.portHandler, motorID,
                                                                                ADDR_AXMX_PRESENT_POS)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % self.packetHandlerP1.getRxPacketError(dxl_error))
                dxl_present_pos.append(p_pos)
                # Check if groupbulkread data of Dynamixel is available
                #dxl_getdata_result = self.groupBulkReadP1_pos.isAvailable(motorID, ADDR_AXMX_PRESENT_POS, LEN_AXMX_PRESENT_POS)
                #if dxl_getdata_result != True:
                #    print("[ID:%03d] groupSyncRead getdata failed - Ln342" % motorID)
                #    quit()
                # Get Dynamixel present position value

                #dxl_present_pos.append(self.groupBulkReadP1_pos.getData(motorID, ADDR_AXMX_PRESENT_POS, LEN_AXMX_PRESENT_POS))
        return dxl_present_pos

    def readMoving(self):
        # Syncread present position
        if self.type_AXMX_P1_used:
            dxl_comm_result = self.groupBulkReadP1_moving.txRxPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))

        if self.type_PRO_P2_used:
            dxl_comm_result = self.groupBulkReadP2_moving.txRxPacket()
            if dxl_comm_result != COMM_SUCCESS:
                print("%s" % self.packetHandlerP2.getTxRxResult(dxl_comm_result))

        dxl_moving_status = []
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                # Check if groupbulkread data of Dynamixel is available
                dxl_getdata_result = self.groupBulkReadP2_moving.isAvailable(motorID, ADDR_PRO_MOVING, LEN_PRO_MOVING)
                if dxl_getdata_result != True:
                    print("[ID:%03d] groupSyncRead getdata failed - Ln366" % motorID)
                    quit()
                # Get Dynamixel present position value

                dxl_moving_status.append(self.groupBulkReadP2_pos.getData(motorID, ADDR_PRO_MOVING, LEN_PRO_MOVING))
            else:  #  if self.motorType[ii] is TYPE_AXMX_P1:
                moving_status, dxl_comm_result, dxl_error = self.packetHandlerP1.read1ByteTxRx(self.portHandler, motorID,
                                                                                ADDR_AXMX_MOVING)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % self.packetHandlerP1.getRxPacketError(dxl_error))
                dxl_moving_status.append(moving_status)
            #    # Check if groupbulkread data of Dynamixel is available
            #    dxl_getdata_result = self.groupBulkReadP1_moving.isAvailable(motorID, ADDR_AXMX_MOVING, LEN_AXMX_MOVING)
            #    if dxl_getdata_result != True:
            #        print("[ID:%03d] groupSyncRead getdata failed - Ln375" % motorID)
            #        quit()
                # Get Dynamixel present position value

            #    dxl_moving_status.append(self.groupBulkReadP1_pos.getData(motorID, ADDR_AXMX_MOVING, LEN_AXMX_MOVING))

        return dxl_moving_status

    def close(self):
        # Clear syncread parameter storage
        #if self.type_AXMX_P1_used:
        #    self.groupBulkReadP1_pos.clearParam()
        #    self.groupBulkReadP1_moving.clearParam()
        if self.type_PRO_P2_used:
            self.groupBulkReadP2_pos.clearParam()
            self.groupBulkReadP2_moving.clearParam()

        # Disable Dynamixel#1 Torque
        for ii in range(0, self.motorNo):
            motorID = self.IDs[ii]
            if self.motorType[ii] == TYPE_PRO_P2:
                dxl_comm_result, dxl_error = self.packetHandlerP2.write1ByteTxRx(self.portHandler, motorID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % self.packetHandlerP2.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % self.packetHandlerP2.getRxPacketError(dxl_error))
            else:  #if self.motorType[ii] == TYPE_AXMX_P1:
                dxl_comm_result, dxl_error = self.packetHandlerP1.write1ByteTxRx(self.portHandler, motorID, ADDR_AXMX_TORQUE_ENABLE, TORQUE_DISABLE)
                if dxl_comm_result != COMM_SUCCESS:
                    print("%s" % self.packetHandlerP1.getTxRxResult(dxl_comm_result))
                elif dxl_error != 0:
                    print("%s" % self.packetHandlerP1.getRxPacketError(dxl_error))

        # Close port
        self.portHandler.closePort()


from itertools import permutations
from math import atan2
from copy import deepcopy

def angle(p1, p2):
    return abs(atan2(p1[1],p1[0]) - atan2(p2[1],p2[0])) * 57.2958

def dist(p1, p2):
    return (((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) ** 0.5)/vel + angle(p1,p2) * 0.2

def tot_dist(points):
    return sum([dist(point, points[i + 1]) for i, point in enumerate(points[:-1])])

def tsp(points, start=None):
    if start is None:
        start = points[0]
        pointused=deepcopy(points)
        pointused.append(points[0])
        path=pointused
        distused=tot_dist(pointused)
    for pm in permutations(points):
        pm = list(pm)
        if pm[0]==start:
            pm.append(start)
            if tot_dist(pm) < distused:
                path=pm
                distused=tot_dist(pm)
            print(pm)
            print(tot_dist(pm))
    return path

num_times=[]
points=[]
num_points=int(input("Enter the number of points"))
for x in range(num_points):
    pnt=[]
    pnt.append(float(input("Enter the x co-ordinate")))
    pnt.append(float(input("Enter the y co-ordinate")))
    points.append(pnt)
vel=float(input("Enter the velocity "))
order=tsp(points)
print("""The order is {} \nThe time taken  is {}.""".format(order, tot_dist(order),))
input()


# Task Force mission file reader
# A quick Python script I wrote to extract maps from Task Force

import struct, random
import numpy as np
from PIL import Image, ImageDraw, ImageColor, ImageFont, ImageOps

colcodes = [0,8,15,8,15,11,11,8,15,0,17,18,18,17,17,1,1,1,1,1,1,1,17,17,17,17,6,6,6,6,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,19,19,9,9,9,9,6,2,2,2,2,2,6]
palette = "#000","#ABB","#F22","#812","#F81","#951","#EE0","#880","#0E2","#081","#17F","#149","#B4E","#739","#041","#641","#455","#899","#CDD","#FFF","#F77","#7BF","#677","#CA8","#526","#511","#136","#A86","#ECA","#567","#9AB","#DEF"
palette_list = [ ImageColor.getcolor(x, "RGB") for x in palette ]
sprite_file = Image.open("taskforce_sprites.png")
tiles = [ sprite_file.crop((0,n,16,n+16)) for n in range(0,73*16,16) ]

for n in range(1,9):
#for n in range(1,2):
  print(f"\n### Mission {n}")
  filename = f"TFSource/Mission{n}"
  with open (filename, "rb") as f:
    coords = f.read(40)
    text = f.read(360).decode("ascii").replace("\0","\n")
    maps = f.read(3600)
    grid = struct.unpack("3600b",maps)

  coords = struct.unpack('>20h', coords)
  coord_list = [(coords[n], coords[n+1]) for n in range(0,20,2)]

  print(f"```\n{text}\n```")
  print ("Target coordinates:")
  for c in coord_list:
    if not (c[0]==0 and c[1]==0):
      print(c)
# -21267 = aced

  print(f"![Mission {n}](../images/Mission{n}_map.png)"+"{:center}"+f"<br>Mission {n}")

  img = Image.new("RGB",(960,960),(0,0,0))
  draw = ImageDraw.Draw(img)
  enemy_no = -1
  blocks = [0]*76
  for y in range(0, 60):
    for x in range(0, 60):
      tile = grid[y*60+x]
      blocks[tile]+= 1
      if tile>66: # enemies
        enemy_no += 1
      img.paste(tiles[tile],(x*16,y*16))

      for goal in coord_list[1:]:
        if x and y and x==goal[0] and y==goal[1] and coord_list[0][0] < 0:
          print(coord_list[0][0])
          draw.rectangle((x*16, y*16, x*16+15, y*16+15), outline=(255,255,0), width=2)
        elif (goal[0] == enemy_no or goal[1] == enemy_no) and tile>66 and enemy_no!=0:
          draw.rectangle((x*16, y*16, x*16+15, y*16+15), outline=(255,255,0), width=2)

      if tile==1 or tile==2: # mines
        img.paste(tiles[tile+2],(x*16,y*16))
        draw.rectangle((x*16, y*16, x*16+15, y*16+15), outline=(255,0,255), width=2)

  print(f"=Mission {n}")
  print("=Enemies:")
  for n in [(67,"Normal"),(68,"Big Gun"),(69,"Elite"),(70,"Android"),(71,"Captain")]:
    print(f"=- {n[1]}: {blocks[n[0]]}")
  print(f"=- Total: {sum(blocks[67:72])}")

#      colcode = colcodes[tile]
#      color = palette[colcode]
#      color = ImageColor.getcolor(color, "RGB")
#
#      for goal in coord_list:
#        if x and y and x==goal[0] and y==goal[1]:
#          color = (255,0,255)
#
#      if not tile in [5,6,7,8,10,16,26,27,28,29,62,63,64,66,65,49]:
#        draw.text((x*10, y*10), f"{tile:02}", align="center")
#  img.save(f"Mission{n}_map.png")


import collections
import heapq

class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]

        Use Counter to extract the top k frequent elements
        most_common(k) return a list of tuples, where the first item of the tuple is the element,
        and the second item of the tuple is the count
        Thus, the built-in zip function could be used to extract the first item from the tuples

        similar: LC 692

        beats 71.68%
        """
        return zip(*collections.Counter(nums).most_common(k))[0]

    def topKFrequent1(self, nums, k):
        """
        :param nums:
        :param k:
        :return:

        dictionary + min heap

        beats 71.68%
        """
        freq = {}
        freq_list = []
        for num in nums:
            if num in freq:
                freq[num] = freq[num] + 1
            else:
                freq[num] = 1

        for key in freq.keys():
            freq_list.append((-freq[key], key))  # -freq[key] is easier for sorting when heapify
        heapq.heapify(freq_list)
        top_k = []
        for i in range(0, k):
            top_k.append(heapq.heappop(freq_list)[1])
        return top_k

    def topKFrequent2(nums, k):
        """
        :param k:
        :return:

        dictionary + quick select

        beats 63.71%
        """
        def quick_select(left, right):
            pivot = left
            l, r = left, right
            while l < r:
                while l < r and counts[r][1] <= counts[pivot][1]:
                    r -= 1
                while l < r and counts[l][1] >= counts[pivot][1]:
                    l += 1
                counts[l], counts[r] = counts[r], counts[l]
            counts[left], counts[l] = counts[l], counts[left]

            if l + 1 == k:
                return counts[:l + 1]
            elif l + 1 < k:  # right half
                return quick_select(l + 1, right)
            else:  # left half
                return quick_select(left, l - 1)

        if not nums:
            return []

        # Get the counts.
        counts = {}
        for x in nums:
            counts[x] = counts.setdefault(x, 0) + 1

        counts = counts.items()
        # Use quick select to get the top k counts.
        return [c[0] for c in quick_select(0, len(counts) - 1)]

    def topKFrequent3(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]

        beats 31.81%
        """
        c = collections.Counter(nums)
        return heapq.nlargest(k, c, c.get)


import urllib.request as requests
import json
import process_html

################################## prerequisites ##################################
#1. replace the headers with your own
headers = {
}
#2. replace here with how many pages of articles of your subscribed project
page_numbers = 39

#3. replace here with how many pages of articles of your subscribed project
project_id = "8DB74C4CEC521004C8BF9783553ADCEB"

################################## programs ##################################
id_list = []
title_list = []

def post_all_id_and_title():
    post_url = "https://og-web.pressplay.cc/member/timelines"
    for x in range(1, page_numbers+1):
        #(optional) change body payload of post request
        body = {"date": {"end": "2022-01-31", "start": "2017-11-01"}, "reward_ids": [], "tags": [], "categories": [], "keyword": "",
        "sort_by": "newest", "page": x, "count": 12, "mode": "", "project_id": project_id}
        data =  str(json.dumps(body)).encode('utf-8')

        request = requests.Request(post_url, headers=headers, data=data)
        with requests.urlopen(request) as response:
            data = response.read().decode('utf-8')
            jdata = json.loads(data)

        for article in jdata['data']['list']:
            id = article['timeline_key']
            title = article['timeline_title']
            id_list.append(id)
            title_list.append(title)

            filename = "id_title.csv"
            with open(filename, mode='a', encoding='utf-8') as file:
                file.write(id + "," + title + '\n')

def get_article_content_by_id(article_id):
    base_url = "https://og-web.pressplay.cc/timeline/"
    get_url = base_url + article_id + "/info"

    request = requests.Request(get_url, headers=headers)
    with requests.urlopen(request) as response:
        data = response.read().decode('utf-8')
        jdata = json.loads(data)
        parse_content = jdata['data']['timeline_info']['timeline_desc']
        # print(parse_content)
        store_article_content(article_id, parse_content)

def store_article_content(article_id, parse_content):
    filename = article_id + ".html"
    with open(filename, mode='w', encoding='utf-8') as file:
        file.write(parse_content)

def get_and_store_all_articles():
    post_all_id_and_title()

    for id in id_list:
        get_article_content_by_id(id)

get_and_store_all_articles()
process_html.process_html()


from systems.commands.processor import Processor

class Calculator(Processor):

    def __init__(self, command, display_only = False, reset = False):
        super().__init__(command, 'calculation',
            display_only = display_only,
        )
        self.reset = reset

    def provider_process(self, name, spec):
        self.command.get_provider(
            self.plugin_key, spec[self.plugin_key], name, spec
        ).process(self.reset)


import os
import urllib

import numpy as np
from neurochat.nc_lfp import NLfp
from neurochat.nc_spatial import NSpatial
from neurochat.nc_spike import NSpike
from simuran.core.param_handler import ParamHandler
from simuran.loaders.neurochat_loader import NeurochatLoader
from simuran.recording import Recording

main_dir = os.path.dirname(__file__)[: -len(f"{os.sep}tests")]

def fetch_axona_data():
    base_url = (
        "https://gin.g-node.org/seankmartin/SIMURAN_Test_Data/raw/master/AxonaData/"
    )
    filenames = [
        "010416b-LS3-50Hz10.V5.ms.2",
        "010416b-LS3-50Hz10.V5.ms.eeg",
        "010416b-LS3-50Hz10.V5.ms_2.cut",
        "010416b-LS3-50Hz10.V5.ms_2.txt",
        "010416b-LS3-50Hz10.V5.ms.set",
    ]
    full_filenames = [
        os.path.join(main_dir, "tests", "resources", "temp", "axona", f)
        for f in filenames
    ]
    full_urls = [base_url + f for f in filenames]

    for i in range(len(filenames)):
        if not os.path.isfile(full_filenames[i]):
            urllib.request.urlretrieve(full_urls[i], full_filenames[i])

    return full_filenames

def test_nc_recording_loading(delete=False):
    main_test_dir = os.path.join(main_dir, "tests", "resources", "temp", "axona")
    os.makedirs(main_test_dir, exist_ok=True)

    axona_files = fetch_axona_data()

    # Load using SIMURAN auto detection.
    metadata = ParamHandler(
        source_file=os.path.join(
            main_dir, "tests", "resources", "params", "axona_test.py"
        ),
        name="mapping",
    )
    metadata["source_file"] = axona_files[-1]

    loader = NeurochatLoader(system="Axona", pos_extension=".txt")
    ex = Recording(attrs=metadata, loader=loader)
    ex.parse_metadata()

    ex.load()

    ex.data["units"][0].data.set_unit_no(1)
    # Load using NeuroChaT
    lfp = NLfp()
    lfp.set_filename(os.path.join(main_test_dir, "010416b-LS3-50Hz10.V5.ms.eeg"))
    lfp.load(system="Axona")

    unit = NSpike()
    unit.set_filename(os.path.join(main_test_dir, "010416b-LS3-50Hz10.V5.ms.2"))
    unit.load(system="Axona")
    unit.set_unit_no(1)

    spatial = NSpatial()
    spatial.set_filename(os.path.join(main_test_dir, "010416b-LS3-50Hz10.V5.ms_2.txt"))
    spatial.load(system="Axona")

    assert np.all(ex.data["signals"][0].data.get_samples() == lfp.get_samples())
    assert np.all(ex.data["units"][0].data.get_unit_stamp() == unit.get_unit_stamp())
    assert np.all(ex.data["units"][0].data.get_unit_tags() == unit.get_unit_tags())
    assert np.all(ex.data["spatial"].data.get_pos_x() == spatial.get_pos_x())

    ncl = NeurochatLoader()
    ncl.system = "Axona"
    loc = os.path.join(main_dir, "tests", "resources", "temp", "axona")
    file_locs, _ = ncl.auto_fname_extraction(
        loc,
        verbose=False,
        unit_groups=[
            2,
        ],
        sig_channels=[
            1,
        ],
    )
    clust_locs = [os.path.basename(f) for f in file_locs["Cluster"] if f is not None]
    assert "010416b-LS3-50Hz10.V5.ms_2.cut" in clust_locs

    if delete:
        for f in axona_files:
            os.remove(f)

if __name__ == "__main__":
    test_nc_recording_loading(delete=False)


from PyQt5 import QtCore, QtGui, QtWidgets
import ParseWindowImage

class Ui_ParseWindow(object):
    def setupUi(self, ParseWindow):
        ParseWindow.setObjectName("ParseWindow")
        ParseWindow.setFixedSize(600, 800)
        ParseWindow.setStyleSheet("QMainWindow{\n"
                                  "    background-image: url(:/ParseWindowImage/images/Black.jpg);\n"
                                  "}")
        ParseWindow.setWindowIcon(QtGui.QIcon(':/ParseWindowImage/images/WindowIcon.ico'))
        self.centralwidget = QtWidgets.QWidget(ParseWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.InfoButton = QtWidgets.QPushButton(self.centralwidget)
        self.InfoButton.setGeometry(QtCore.QRect(540, 20, 32, 32))
        self.InfoButton.setStyleSheet("QPushButton{\n"
                                      "    background-color: rgb(255, 0, 0, 0);    \n"
                                      "    max-width:51px;\n"
                                      "    max-height:32px;\n"
                                      "    min-width:16px;\n"
                                      "    min-height:16px;\n"
                                      "}\n"
                                      "\n"
                                      "QPushButton:pressed{\n"
                                      "    border-style: solid;\n"
                                      "    border-width:1px;\n"
                                      "    border-radius: 4.2px;\n"
                                      "    border-color: rgb(255, 0, 0)\n"
                                      "}")
        self.InfoButton.setText("")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/ParseWindowImage/images/AboutUs.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.InfoButton.setIcon(icon)
        self.InfoButton.setIconSize(QtCore.QSize(32, 32))
        self.InfoButton.setObjectName("InfoButton")
        self.CentralLine = QtWidgets.QLineEdit(self.centralwidget)
        self.CentralLine.setGeometry(QtCore.QRect(100, 140, 400, 20))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.CentralLine.setFont(font)
        self.CentralLine.setStyleSheet("background-color: rgb(255, 255, 255);\n"
                                       "color: rgb(255, 0, 0);\n"
                                       "border-style: solid;\n"
                                       "border-width:1px;\n"
                                       "border-radius: 5px;\n"
                                       "border-color: rgb(255, 255, 255);")
        self.CentralLine.setAlignment(QtCore.Qt.AlignCenter)
        self.CentralLine.setObjectName("CentralLine")
        self.AddButton = QtWidgets.QPushButton(self.centralwidget)
        self.AddButton.setGeometry(QtCore.QRect(100, 180, 120, 25))
        font = QtGui.QFont()
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.AddButton.setFont(font)
        self.AddButton.setStyleSheet("QPushButton{\n"
                                     "    color: rgb(255, 255, 255);    \n"
                                     "    border-style: solid;\n"
                                     "    border-width:1px;\n"
                                     "    border-radius: 4.2px;\n"
                                     "    border-color: rgb(255, 255, 255);\n"
                                     "    min-width:51px;\n"
                                     "    min-height:21px;\n"
                                     "}\n"
                                     "\n"
                                     "QPushButton:pressed{\n"
                                     "    border-color: rgb(255,0,0)\n"
                                     "}\n"
                                     "    ")
        self.AddButton.setObjectName("AddButton")
        self.DeleteButton = QtWidgets.QPushButton(self.centralwidget)
        self.DeleteButton.setGeometry(QtCore.QRect(240, 180, 120, 25))
        font = QtGui.QFont()
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.DeleteButton.setFont(font)
        self.DeleteButton.setStyleSheet("QPushButton{\n"
                                        "    color: rgb(255, 255, 255);    \n"
                                        "    border-style: solid;\n"
                                        "    border-width:1px;\n"
                                        "    border-radius: 4.2px;\n"
                                        "    border-color: rgb(255, 255, 255);\n"
                                        "    min-width:51px;\n"
                                        "    min-height:21px;\n"
                                        "}\n"
                                        "\n"
                                        "QPushButton:pressed{\n"
                                        "    border-color: rgb(255,0,0)\n"
                                        "}\n"
                                        "    ")
        self.DeleteButton.setObjectName("DeleteButton")
        self.ClearButton = QtWidgets.QPushButton(self.centralwidget)
        self.ClearButton.setGeometry(QtCore.QRect(380, 180, 120, 25))
        font = QtGui.QFont()
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.ClearButton.setFont(font)
        self.ClearButton.setStyleSheet("QPushButton{\n"
                                       "    color: rgb(255, 255, 255);    \n"
                                       "    border-style: solid;\n"
                                       "    border-width:1px;\n"
                                       "    border-radius: 4.2px;\n"
                                       "    border-color: rgb(255, 255, 255);\n"
                                       "    min-width:51px;\n"
                                       "    min-height:21px;\n"
                                       "}\n"
                                       "\n"
                                       "QPushButton:pressed{\n"
                                       "    border-color: rgb(255,0,0)\n"
                                       "}\n"
                                       "    ")
        self.ClearButton.setObjectName("ClearButton")
        self.CentralList = QtWidgets.QListWidget(self.centralwidget)
        self.CentralList.setGeometry(QtCore.QRect(100, 230, 400, 400))
        self.CentralList.setStyleSheet("background-color: rgb(255, 255, 255);\n"
                                       "color: rgb(255,0,0);\n"
                                       "border-style: solid;\n"
                                       "border-width:1px;\n"
                                       "border-radius: 5px;\n"
                                       "")
        self.CentralList.setObjectName("CentralList")
        item = QtWidgets.QListWidgetItem()
        self.CentralList.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.CentralList.addItem(item)
        self.SelectFolderButton = QtWidgets.QPushButton(self.centralwidget)
        self.SelectFolderButton.setGeometry(QtCore.QRect(100, 700, 400, 20))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.SelectFolderButton.setFont(font)
        self.SelectFolderButton.setStyleSheet("QPushButton{\n"
                                              "    color: rgb(255, 255, 255);    \n"
                                              "    border-style: solid;\n"
                                              "    border-width:1px;\n"
                                              "    border-radius: 4.2px;\n"
                                              "    border-color: rgb(255, 255, 255);\n"
                                              "    min-width:51px;\n"
                                              "    min-height:21px;\n"
                                              "}\n"
                                              "\n"
                                              "QPushButton:pressed{\n"
                                              "    border-color: rgb(255,0,0)\n"
                                              "}")
        self.SelectFolderButton.setObjectName("SelectFolderButton")
        self.XLSLine = QtWidgets.QLineEdit(self.centralwidget)
        self.XLSLine.setGeometry(QtCore.QRect(100, 655, 400, 25))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.XLSLine.setFont(font)
        self.XLSLine.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.XLSLine.setAutoFillBackground(False)
        self.XLSLine.setStyleSheet("background-color: rgb(255, 255, 255);\n"
                                   "color: rgb(255, 0, 0);\n"
                                   "border-style: solid;\n"
                                   "border-width:1px;\n"
                                   "border-radius: 5px;\n"
                                   "border-color: rgb(255, 255, 255);")
        self.XLSLine.setAlignment(QtCore.Qt.AlignCenter)
        self.XLSLine.setObjectName("XLSLine")
        self.TitleParseLabel = QtWidgets.QLabel(self.centralwidget)
        self.TitleParseLabel.setGeometry(QtCore.QRect(0, 5, 381, 131))
        self.TitleParseLabel.setText("")
        self.TitleParseLabel.setPixmap(QtGui.QPixmap(":/ParseWindowImage/images/Parse.png"))
        self.TitleParseLabel.setObjectName("TitleParseLabel")
        ParseWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(ParseWindow)
        self.statusbar.setObjectName("statusbar")
        ParseWindow.setStatusBar(self.statusbar)

        self.retranslateUi(ParseWindow)
        QtCore.QMetaObject.connectSlotsByName(ParseWindow)

    def retranslateUi(self, ParseWindow):
        _translate = QtCore.QCoreApplication.translate
        ParseWindow.setWindowTitle(_translate("ParseWindow", "Parse"))
        self.CentralLine.setPlaceholderText(
            _translate("ParseWindow", "Enter the names of the columns that will be in Excel file"))
        self.AddButton.setText(_translate("ParseWindow", "Add a column"))
        self.DeleteButton.setText(_translate("ParseWindow", "Delete a column"))
        self.ClearButton.setText(_translate("ParseWindow", "Clear all"))
        __sortingEnabled = self.CentralList.isSortingEnabled()
        self.CentralList.setSortingEnabled(False)
        item = self.CentralList.item(0)
        item.setText(_translate("ParseWindow", "sdadsa"))
        item = self.CentralList.item(1)
        item.setText(_translate("ParseWindow", "dsad"))
        self.CentralList.setSortingEnabled(__sortingEnabled)
        self.SelectFolderButton.setText(_translate("ParseWindow", "Select the desired folder"))
        self.XLSLine.setPlaceholderText(
            _translate("ParseWindow", "Enter the name that Excel file will have, example: BAD_GIRLS"))

if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    ParseWindow = QtWidgets.QMainWindow()
    ui = Ui_ParseWindow()
    ui.setupUi(ParseWindow)
    ParseWindow.show()
    sys.exit(app.exec_())


N = int(input())
for i in range(1, N+1):
    line_pattern = " " * (N-i)
    for j in range(1, i+1):
        line_pattern = line_pattern + str(j) + " "
    print(line_pattern)

#     1
#    1 2
#   1 2 3
#  1 2 3 4
# 1 2 3 4 5

n = int(input())
start = 1
for row in range(1, n+1):
    print (" " * (n-row), end="")
    for col in range(1, row+1):
        print (start, end=" ")
        start += 1
    print ()


import time
import copy
import torch
import pickle
import random
import numpy as np
from torch import nn
from typing import Dict, List, Tuple, Union, Optional

from tianshou.policy import PGPolicy
from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch

class PPOPolicy(PGPolicy):
    r"""Implementation of Proximal Policy Optimization. arXiv:1707.06347

    :param torch.nn.Module actor: the actor network following the rules in
        :class:`~tianshou.policy.BasePolicy`. (s -> logits)
    :param torch.nn.Module critic: the critic network. (s -> V(s))
    :param torch.optim.Optimizer optim: the optimizer for actor and critic
        network.
    :param torch.distributions.Distribution dist_fn: for computing the action.
    :param float discount_factor: in [0, 1], defaults to 0.99.
    :param float max_grad_norm: clipping gradients in back propagation,
        defaults to ``None``.
    :param float eps_clip: :math:`\epsilon` in :math:`L_{CLIP}` in the original
        paper, defaults to 0.2.
    :param float vf_coef: weight for value loss, defaults to 0.5.
    :param float ent_coef: weight for entropy loss, defaults to 0.01.
    :param action_range: the action range (minimum, maximum).
    :type action_range: (float, float)
    :param float gae_lambda: in [0, 1], param for Generalized Advantage
        Estimation, defaults to 0.95.
    :param float dual_clip: a parameter c mentioned in arXiv:1912.09729 Equ. 5,
        where c > 1 is a constant indicating the lower bound,
        defaults to 5.0 (set ``None`` if you do not want to use it).
    :param bool value_clip: a parameter mentioned in arXiv:1811.02553 Sec. 4.1,
        defaults to ``True``.
    :param bool reward_normalization: normalize the returns to Normal(0, 1),
        defaults to ``True``.

    .. seealso::

        Please refer to :class:`~tianshou.policy.BasePolicy` for more detailed
        explanation.
    """

    def __init__(self,
                 nets, optims,
                 dist_fn: torch.distributions.Distribution,
                 discount_factor: float = 0.99,
                 max_grad_norm: Optional[float] = None,
                 eps_clip: float = .2,
                 vf_coef: float = .5,
                 ent_coef: float = .01,
                 action_range: Optional[Tuple[float, float]] = None,
                 gae_lambda: float = 0.95,
                 dual_clip: Optional[float] = None,
                 value_clip: bool = True,
                 reward_normalization: bool = True,
                 params = None,
                 batch_file = None,
                 **kwargs) -> None:
        super().__init__(None, None, dist_fn, discount_factor, **kwargs)
        self._max_grad_norm = max_grad_norm
        self._eps_clip = eps_clip
        self._w_vf = vf_coef
        self._w_ent = ent_coef
        self._range = True
        self.driver, self.motive, self.critic, self.discriminator = nets
        self.optim_p, self.optim_d = optims
        assert 0 <= gae_lambda <= 1, 'GAE lambda should be in [0, 1].'
        self._lambda = gae_lambda
        assert dual_clip is None or dual_clip > 1, \
            'Dual-clip PPO parameter should greater than 1.'
        self._dual_clip = dual_clip
        self._value_clip = value_clip
        self._rew_norm = reward_normalization
        self.device = params.device
        self.trj_steps = params.trj_steps
        self.trj_clip_steps = params.trj_clip_steps
        self.d_loss = None

    def get_reward_by_discriminator(self,batch):
        rews = []
        v_ = []
        for b in batch.split(self.step_batch_size, shuffle=False):
            expert_label = torch.full((len(b), 1), 1)
            with torch.no_grad():
                prob_expert = self.discriminator(b.obs.s[:, -1, :].cuda(), b.act.s_next.cuda(), b.act.a.cuda(), b.act.o.cuda())
                rews.append(-torch.log(1-prob_expert))
                v_.append(self.critic(b.obs.p.cuda(),
                                      b.obs.s.cuda(),
                                      b.obs.v.cuda(),
                                      b.obs.v_next.cuda()
                                     ))
        rew = torch.cat(rews, dim=0).contiguous().cpu().view(-1)
        v_ = torch.cat(v_, dim=0).contiguous().cpu().view(-1)
        return rew,v_

    def get_mask_indices(self,):
        #获得不用数据的索引和done
        is_done = True
        not_done = False

        indices=self.indices
        trj_steps=self.trj_steps
        trj_clip_steps=self.trj_clip_steps

        use_steps = trj_steps// trj_clip_steps * trj_clip_steps

        def get_done(index):
            return is_done if (index+1) % 5 ==0 else not_done

        mask_indices = []
        done = np.full_like(indices, is_done).astype(bool)
        copy_done = np.array([get_done(i) for i in range(use_steps) ])

        for ulp_index in range(indices.shape[0] // trj_steps):

            start_index = random.choice(range(trj_clip_steps-1))
            stop_index = use_steps + start_index

            start_index = start_index + (ulp_index * trj_steps)
            stop_index = stop_index + (ulp_index * trj_steps)

            done[start_index:stop_index] = copy_done

            mask_indices += range((ulp_index * trj_steps), start_index)
            mask_indices += range(stop_index, (ulp_index+1) * trj_steps)

        return mask_indices,done

    def process_fn(self, batch: Batch, buffer=None,
                   indice=None) -> Batch:
        v_ = None
        rew,v_ = self.get_reward_by_discriminator(batch)

        batch.rew = rew

        if self._rew_norm:
            mean, std = batch.rew.mean(), batch.rew.std()
            if not np.isclose(std.cpu().numpy(), 0):
                batch.rew = (batch.rew - mean) / std
        if self._lambda in [0, 1]:
            return self.compute_episodic_return(
                batch, None, gamma=self._gamma, gae_lambda=self._lambda)
        batch.to_numpy()
        batch = self.compute_episodic_return(
            batch, v_, gamma=self._gamma, gae_lambda=self._lambda)
        batch.to_torch()
        return batch

    def trj_by_policy(self,batch):
        #return batch
        assert len(batch) % self.trj_clip_steps == 0
        infer_batch = None
        old_step_batch = None
        o_len = batch.act.o.shape[-1]
        policy_batch_list = []
        for step in range(self.trj_clip_steps):
            indices = np.arange(step, len(batch), self.trj_clip_steps,)
            step_batch = batch[indices]
            if infer_batch is not None:
                #修正obs
                #print(step)
                #print(step_batch.obs.s[0])
                s = torch.cat([old_step_batch.obs.s,
                                              infer_batch.act_m[:,o_len:].cpu().reshape(len(old_step_batch),1,-1)],1)
                s = s[:,1:,:]
                step_batch.obs.s = s
                #print(step_batch.obs.s[0])

                del infer_batch

            infer_batch = self(step_batch)

            #修正act
            #print(step_batch.act)
            step_batch.act.a = infer_batch.act_d.cpu()
            step_batch.act.o = infer_batch.act_m[:,:o_len].contiguous().cpu()
            step_batch.act.s_next = infer_batch.act_m[:,o_len:].contiguous().cpu()
            #print(step_batch.act)

            old_step_batch = step_batch
            policy_batch_list.append(step_batch)

        policy_batch = Batch()
        policy_batch.cat_list(policy_batch_list)

        re_indices = []
        for i in range(len(policy_batch_list[0])):
            for j in range(self.trj_clip_steps):
                re_indices.append(i + (j*len(policy_batch_list[0])))
        re_indices = np.array(re_indices).astype(np.int32)
        policy_batch = policy_batch[re_indices]

        return policy_batch

    def forward(self, batch: Batch,
                state: Optional[Union[dict, Batch, np.ndarray]] = None,
                **kwargs) -> Batch:
        """Compute action over the given batch data.

        :return: A :class:`~tianshou.data.Batch` which has 4 keys:

            * ``act`` the action.
            * ``logits`` the network's raw output.
            * ``dist`` the action distribution.
            * ``state`` the hidden state.

        .. seealso::

            Please refer to :meth:`~tianshou.policy.BasePolicy.forward` for
            more detailed explanation.
        """

        logits_d = self.driver(batch.obs.p.cuda(), batch.obs.s.cuda(), batch.obs.v.cuda(), batch.obs.v_next.cuda(),)
        if isinstance(logits_d, tuple):
            dist_d = self.dist_fn(*logits_d)
        else:
            dist_d = self.dist_fn(logits_d)
        act_d = dist_d.sample()

        if self._range:
            act_d = act_d.clamp(-1, 1)

        logits_m = self.motive(batch.obs.p.cuda(), batch.obs.s.cuda(), act_d.detach(),)
        if isinstance(logits_m, tuple):
            dist_m = self.dist_fn(*logits_m)
        else:
            dist_m = self.dist_fn(logits_m)
        act_m = dist_m.sample()

        if self._range:
            act_m = act_m.clamp(-1, 1)

        return Batch(logits_d = logits_d,
                     logits_m = logits_m,
                     act_d = act_d,
                     act_m = act_m,
                     dist_d = dist_d,
                     dist_m = dist_m)

    def learn(self, batch, step_batch_size: int, repeat: int, epoch : int,
              **kwargs) -> Dict[str, List[float]]:
        self.step_batch_size = step_batch_size
        #1.生成轨迹
        batch_expert = batch
        batch_policy = copy.deepcopy(batch)
        batch_policy = self.trj_by_policy(batch_policy)
        #print(batch_policy)
        #2.训练判别器
        loss_d = torch.nn.MSELoss(reduce=True, size_average=True)
        d_loss = None
        if True:
            expert_label = torch.full((step_batch_size, 1), 1)
            policy_label = torch.full((step_batch_size, 1), 0)
            if torch.cuda.is_available():
                expert_label = expert_label.cuda()
                policy_label = policy_label.cuda()
            discriminator_batch =  zip(batch_expert.split(step_batch_size, shuffle=True),
                                             batch_policy.split(step_batch_size, shuffle=True))
            for b_expert,b_policy in discriminator_batch:
                prob_expert = self.discriminator(b_expert.obs.s[:, -1, :].cuda(),
                                                 b_expert.act.s_next.cuda(),
                                                 b_expert.act.a.cuda(),
                                                 b_expert.act.o.cuda())

                prob_policy = self.discriminator(b_policy.obs.s[:, -1, :].cuda(),
                                                 b_policy.act.s_next.cuda(),
                                                 b_policy.act.a.cuda(),
                                                 b_policy.act.o.cuda())

                expert_loss = loss_d(prob_expert, expert_label)
                policy_loss = loss_d(prob_policy, policy_label)
                d_loss  = (expert_loss.mean()+policy_loss.mean()) / 2.0
                self.optim_d.zero_grad()
                d_loss.backward()
                if d_loss.item() >= 0.1:
                    self.optim_d.step()
                else:
                    break

        #3.使用训练后的判别器对生成轨迹计算reward并应用GAE;
        batch_policy = self.process_fn(batch_policy)
        #4.使用PPO训练策略网络
        losses, clip_losses, vf_losses, ent_losses, adv_list = [], [], [], [], []
        v = []
        old_log_prob_d = []
        old_log_prob_m = []
        with torch.no_grad():
            #critic评估当前状态价值
            for b in batch_policy.split(self.step_batch_size, shuffle=False):
                v.append(self.critic(b.obs.p.cuda(),
                                     b.obs.s.cuda(),
                                     b.obs.v.cuda(),
                                     b.obs.v_next.cuda()
                                     )
                                        )
                batch_infer = self(b)
                old_log_prob_d.append(batch_infer.dist_d.log_prob(b.act.a.cuda()).detach())
                old_log_prob_m.append(batch_infer.dist_m.log_prob(torch.cat([b.act.o, b.act.s_next - b.obs.s[:, -1, :]],1).cuda()).detach())

        batch_policy.v = torch.cat(v, dim=0).cpu()
        #batch.act = to_torch(batch.act, v[0])
        batch_policy.old_log_prob_d = torch.cat(old_log_prob_d, dim=0)
        batch_policy.old_log_prob_m = torch.cat(old_log_prob_m, dim=0)
        batch_policy.returns = batch_policy.returns.reshape(batch_policy.v.shape)

        #print(a)

        if self._rew_norm:
            mean, std = batch_policy.returns.mean(), batch_policy.returns.std()
            if not np.isclose(std.item(), 0):
                batch_policy.returns = (batch_policy.returns - mean) / std
        batch_policy.adv = batch_policy.returns - batch_policy.v
        #print(batch_policy.adv)
        if self._rew_norm:
            mean, std = batch_policy.adv.mean(), batch_policy.adv.std()
            if not np.isclose(std.item(), 0):
                batch_policy.adv = (batch_policy.adv - mean) / std
        #print(batch_policy.adv)
        for _ in range(repeat):
            for b in batch_policy.split(self.step_batch_size, shuffle=True):
                batch_dist = self(b)
                dist_d = batch_dist.dist_d
                dist_m = batch_dist.dist_m
                value = self.critic(b.obs.p.cuda(),
                                     b.obs.s.cuda(),
                                     b.obs.v.cuda(),
                                     b.obs.v_next.cuda()
                                     )

                ratio = ((dist_d.log_prob(b.act.a.cuda()) \
                         +dist_m.log_prob(torch.cat([b.act.o, b.act.s_next - b.obs.s[:, -1, :]],1).cuda())) \
                         - (b.old_log_prob_d + b.old_log_prob_m)).exp().float()

                #time.sleep(1)
                b.adv = b.adv.cuda()
                surr1 = ratio * b.adv
                surr2 = ratio.clamp(
                    1. - self._eps_clip, 1. + self._eps_clip) * b.adv
                if self._dual_clip:
                    clip_loss = -torch.max(torch.min(surr1, surr2),
                                           self._dual_clip * b.adv).mean()
                else:
                    clip_loss = -torch.min(surr1, surr2).mean()

                if self._value_clip:
                    b.v = b.v.cuda()
                    b.returns = b.returns.cuda()
                    v_clip = b.v + (value - b.v).clamp(
                        -self._eps_clip, self._eps_clip)
                    vf1 = (b.returns - value).pow(2)
                    vf2 = (b.returns - v_clip).pow(2)
                    vf_loss = .5 * torch.max(vf1, vf2).mean()
                else:
                    b.returns = b.returns.cuda()
                    vf_loss = .5 * (b.returns - value.reshape(-1)).pow(2).mean()

                e_loss = (dist_d.entropy().mean() + dist_m.entropy().mean()) / 2.0

                #loss = vf_loss
                loss = clip_loss + self._w_vf * vf_loss  - self._w_ent * e_loss
                #loss = clip_loss
                losses.append(loss.item())
                clip_losses.append(clip_loss.item())
                vf_losses.append(self._w_vf * vf_loss.item())
                ent_losses.append(-self._w_ent * e_loss.item())
                adv_list.append(b.adv.mean().item())

                self.optim_p.zero_grad()
                loss.backward()
                nn.utils.clip_grad_norm_(list(self.driver.parameters())
                                         + list(self.motive.parameters())
                                         + list(self.critic.parameters()),
                    self._max_grad_norm)
                self.optim_p.step()

                #5.记录训练过程信息
                print("Loss:{},clip_loss:{};vf_loss:{};e_loss:{};adv:{};Dis:{}".format(loss.item(),
                                                                          clip_loss.item(),
                                                                 self._w_vf * vf_loss.item(),
                                                                self._w_ent * e_loss.item(),
                                                                b.adv.mean().item(),
                                                                d_loss.item() ))
        torch.cuda.empty_cache()
        return {
            'loss': losses,
            'loss/clip': clip_losses,
            'loss/vf': vf_losses,
            'loss/ent': ent_losses,
            'loss/discriminator':[d_loss.item(),],
            'adv':adv_list,
        }


from pymodbus.client.sync import ModbusSerialClient
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.constants import Endian
from pymodbus.client.sync import ModbusTcpClient
from pymodbus.compat import iteritems
import struct
import paho.mqtt.client as mqtt
import time
from tkinter import *

def main():
    root=Tk()
    topFrame = Frame(root)
    topFrame.pack()

    button1 = Button(topFrame, text="Send",command=mqttClient)
    button1.pack(side=LEFT)
    #button2 = Button(topFrame, text="Stop",command=Stop_)
    #button2.pack(side=LEFT)
    button3 = Button(topFrame, text="Exit",command=Exit_)
    button3.pack(side=LEFT)

    root.mainloop()

def Exit_():
    exit()

def mqttClient():
    host ="siamgreenergy.com"
    port = 8000
    client = mqtt.Client()
    print("Connecting to broker")
    client.connect(host)

    #n = int(input(("Refresh time(s): "))) # input time to refresh
    #print("Refresh every ", n," second.")

    funcC = connect()
    client.publish("wlegat/wl002",funcC)
    time.sleep(1)       # time to refresh
    client.connect(host)
    #while True: # loop for sending infomation.
     #   funcC = connect()
      #  client.publish("wlegat/wl002",funcC)
       # time.sleep(n)       # time to refresh
        #client.connect(host)

def connect():
    client = ModbusSerialClient(
        method='rtu',
        port='COM3',
        baudrate=9600,
        timeout=3,
        parity='N',
        stopbits=1,
        bytesize=8
    )
    if client.connect():
        #ad1=int(input("address1: ")) # Address input normal
        x = 0
        list_A = []
        while(x<8):
            if(x == 0): #1 Voltage
                try:
                    ad1 = 1
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans

                list_A.append(ans)

            if(x == 1): #7 Current
                try:
                    ad1 = 7
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans
                list_A.append(ans)
            if(x == 2): #13 Active power
                try:
                    ad1 = 13
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans
                list_A.append(ans)
            if(x == 3): #31 Power factor
                try:
                    ad1 = 31
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans
                list_A.append(ans)
            if(x == 4): #71 Frequency
                try:
                    ad1 = 71
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans
                list_A.append(ans)
            if(x == 5): #73
                ad1 = 73
                result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)
                result2 = client.read_input_registers(address=ad1,count=1,unit=1)

                r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans
                list_A.append(ans)
            if(x == 6): #75 Import active energy
                try:
                    ad1 = 75
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans

                if(ans == '0.00'):
                    ans = 'nan'
                list_A.append(ans)

            if(x == 7): #343 Total active energy
                try:
                    ad1 = 343
                    result1 = client.read_input_registers(address=ad1-1,count=1,unit=1)  #Uint32/1
                    result2 = client.read_input_registers(address=ad1,count=1,unit=1)   #Uint32/2

                    r = result2.registers + result1.registers #[Uint32/2, Uint32/1]
                except AttributeError:
                    connect()
                print(r)
                b=struct.pack('HH',r[0],r[1])
                ans=struct.unpack('f',b)[0]
                ans = '%.2f'%ans
                list_A.append(ans)

            print('x = ',x)
            x+=1

        print(list_A)

        allans = 'V = '+str(list_A[0])+', '+'I = '+str(list_A[1])+', '+'W = '+str(list_A[2])+', '+'PF = '+str(list_A[3])+', '+'Hz = '+str(list_A[4])+', '+'IAE kWh = '+str(list_A[5])+', '+'EAE kWh = '+str(list_A[6])+', '+'TAE kWh = '+str(list_A[7])
        print('allans: ',allans)
        client.close()
        return allans

    else:
        print('Cannot connect to the Modbus Server/Slave')

main()


# Gustave Michel III
# 05/03/2017
# Encrypt and Decrypt file using AES with 16, 24, or 32 Byte Keys.
# Also checks Key Hashes to ensure right Key is being supplied to Decrypt

import sys
import os
import argparse
import re

import hashlib
from Crypto.Cipher import AES

def input_file(x):
    """'Type' for argparse - checks that file exists and opens read-only."""
    if not os.path.exists(x):
        raise argparse.ArgumentTypeError("{0} does not exist".format(x))
    return open(x,'r')

parser = argparse.ArgumentParser(description='')
parser.add_argument('action', choices=['enc','dec'], help='Encrypt or Decrypt')
parser.add_argument('key', help='Encryption/Decryption Key')
parser.add_argument('filename', type=input_file, help='File to Encrypt/Decrypt')
args = parser.parse_args()

# The block size for cipher object; must be 16 bytes (128 bit) for AES.
BLOCK_SIZE = 16

# Pad at the end, so all blocks, including the last one, are 128 bit long.
PAD_WITH = '#'

# Valid Key Lengths (Bytes)
KEY_LENGTHS = [16,24,32]

# Appends 'PAD_WITH' to end of plaintext to make it fully fill all blocks.
def pad(plaintext):
    return plaintext + (BLOCK_SIZE - len(plaintext) % BLOCK_SIZE) * PAD_WITH

# Encrypts 'plaintext' using 'cipher' object.
def encrypt(cipher, plaintext):
    return cipher.encrypt(pad(plaintext))

# Decrypts 'ciphertext' using 'cipher' object.
def decrypt(cipher, ciphertext):
    return  cipher.decrypt(ciphertext).rstrip(PAD_WITH)

# Create a 'cipher' object and generate the 'key hash' using 'key'
cipher = AES.new(args.key)
key_hash = hashlib.sha256(args.key).digest()

# Filename Regex Groups
filename = re.search('(^.+?)(_enc|_dec)?(\..+$)',args.filename.name)
input_text = args.filename.read()

# Encryption
if args.action == 'enc': # Encryption
    output_text = key_hash+encrypt(cipher, input_text)
# Key Hash Validation and Decryption
elif args.action == 'dec': # Decryption
    ciphertext, ciphertext_hash = [input_text[32:],input_text[:32]]
    if key_hash != ciphertext_hash:
        raise ValueError('File\'s Key Hash does not match provided Key\'s Hash')
    output_text = decrypt(cipher, ciphertext)

out_file = open(filename.group(1)+"_"+args.action+filename.group(3),'w')
out_file.write(output_text)
out_file.close()
args.filename.close()


#!/usr/bin/env python
import getpass
import sys
import time
import telnetlib

rc = 0

tn = telnetlib.Telnet("localhost",2004)

tn.read_until("key:")
tn.write("123\n")
tn.read_until(">>")

# Test case #1
tn.write("inter 0.0.0.0 TH_Temp_Inside:=24.0;\n")
tn.read_until(">>")

time.sleep(1)

tn.write("ls\n")
resp = tn.read_until(">>")
lines = resp.splitlines()
for line in lines:
  if line.find("TH_Output") >= 0 :
    #print line
    if line.find("FALSE") >= 0 :
      rc = 1

# Test case #2
tn.write("inter 0.0.0.0 TH_Temp_Inside:=26.0;\n")
tn.read_until(">>")

time.sleep(1)

tn.write("ls\n")
resp = tn.read_until(">>")
lines = resp.splitlines()
for line in lines:
  if line.find("TH_Output") >= 0 :
    #print line
    if line.find("TRUE") >= 0 :
      rc = 1

tn.write("quit\n")
tn.read_all()

#print rc

sys.exit(rc)