#!/usr/bin/env python
from metareasoning_agent import agent
from metareasoning_agent import knowledge_base as kb

import rospy
from geometry_msgs.msg import Point, Pose2D

import networkx.algorithms.isomorphism as iso
import networkx as nx

import math

def generate_pick_and_place(block, location, pick_orientation, place_orientation):
    resting_position = Point(x=0.75, y=-.65, z=0.0)

    return [
        {'action': kb.PrimitiveActions.detect,
            'constraints': agent.Constraints(),
            'desc': "Detecting block locations with top camera"
         },

        {'action': kb.PrimitiveActions.transport,
            'constraints': agent.Constraints(block=block,
                                             position=None,
                                             orientation=pick_orientation),
            'desc': "Moving towards " + str(block),
         },

        {'action': kb.PrimitiveActions.align,
            'constraints': agent.Constraints(block=block,
                                             position=None,
                                             orientation=pick_orientation),
            'desc': "Aligning with " + str(block) + " with orientation " + str(pick_orientation)
         },

        {'action': kb.PrimitiveActions.pick,
            'constraints': agent.Constraints(),
            'desc': "Picking " + str(block),
         },

        {'action': kb.PrimitiveActions.retract,
            'constraints': agent.Constraints(),
            'desc': "Retracting..."
         },

        {'action': kb.PrimitiveActions.transport,
            'constraints': agent.Constraints(block=None,
                                             position=location,
                                             orientation=place_orientation),
            'desc': "Moving " + str(block) + " to " + str(location)
         },

        {'action': kb.PrimitiveActions.align,
            'constraints': agent.Constraints(block=None,
                                             position=None,
                                             orientation=place_orientation),
            'desc': "Aligning " + str(block) + "with orientation " + str(place_orientation),
         },

        {'action': kb.PrimitiveActions.place,
            'constraints': agent.Constraints(),
            'desc': "Placing " + str(block)
         },

        {'action': kb.PrimitiveActions.retract,
            'constraints': agent.Constraints(),
            'desc': "Retracting...",
         },

        {'action': kb.PrimitiveActions.transport,
            'constraints': agent.Constraints(block=None,
                                             position=resting_position,
                                             orientation=0),
            'desc': "Moving back to starting pose",
         },
    ]

def main():
    # create a rosnode
    rospy.init_node("agent_test", log_level=rospy.DEBUG)

    # create an agent with the intent to control right arm
    test_agent = agent.Agent('right')  # pylint: disable=C0103
    test_agent.subscribe()

    #    B
    # _ BB
    #   BB
    #    B Actual Pyramid
    """
    green_1x4 = kb.Block(length=4, width=1, color="green")
    green_1x4_final_position = Point(x=0.735, y=-0.287, z=0.0)
    blue_1x2 = kb.Block(length=2, width=1, color="blue")
    blue_1x2_final_position = Point(x=0.738, y=-0.240, z=0.0)

    green_1x4_pnp = generate_pick_and_place(
        green_1x4, green_1x4_final_position, 0, 0)

    blue_1x2_pnp = generate_pick_and_place(
        blue_1x2, blue_1x2_final_position, 0, 1)

    fake_action_list = green_1x4_pnp + blue_1x2_pnp + [None]

    green_1x4_desired = Pose2D(x=0.729, y=-0.273, theta=0.0)
    blue_1x2_desired = Pose2D(x=0.723, y=-0.321, theta=math.pi/2)

    green_1x4_block = kb.Block(length=4, width=1, color="green",
                               pose=green_1x4_desired)
    blue_1x2_block = kb.Block(
        length=2, width=1, color="blue", pose=blue_1x2_desired)
    """

    # BBB
    #  B
    #  B
    #  B
    #  B
    # BBB  Barbell
    green_1x2 = kb.Block(length=2, width=1, color="green")
    green_1x2_final_position = Point(x=0.554, y=-0.239, z=0.0)

    blue_1x4 = kb.Block(length=4, width=1, color="blue")
    blue_1x4_final_position = Point(x=.637, y=-0.242, z=0.0)

    red_1x2 = kb.Block(length=2, width=1, color="red")
    red_1x2_final_position = Point(x=0.728, y=-0.247, z=0.0)

    green_1x2_pnp = generate_pick_and_place(
        green_1x2, green_1x2_final_position, 0, 1)

    blue_1x4_pnp = generate_pick_and_place(
        blue_1x4, blue_1x4_final_position, 0, 0)

    red_1x2_pnp = generate_pick_and_place(
        red_1x2, red_1x2_final_position, 0, 1)

    fake_action_list = green_1x2_pnp + red_1x2_pnp + blue_1x4_pnp

    green_1x2_desired = Pose2D(x=0.807, y=-0.245, theta=math.pi/2)
    blue_1x4_desired = Pose2D(x=0.729, y=-0.241, theta=0)
    red_1x2_desired = Pose2D(x=0.653, y=-0.232, theta=math.pi/2)

    green_1x2_block = kb.Block(length=4, width=1, color="green",
                               pose=green_1x2_desired)
    blue_1x4_block = kb.Block(
        length=4, width=1, color="blue", pose=blue_1x4_desired)
    red_1x2_block = kb.Block(
        length=2, width=1, color="red", pose=red_1x2_desired)

    expectation = kb.EnvState()
    expectation.add_block(green_1x2_block)
    expectation.add_block(blue_1x4_block)
    expectation.add_block(red_1x2_block)

    errortolerancexy = 0.010
    errortolerancetheta = 0.087

    node_condition1 = iso.categorical_node_match(['length', 'width'],
                                                 [1, 1])
    node_condition2 = iso.numerical_edge_match(
        ['pose_x', 'pose_y'], [0, 0], rtol=errortolerancexy)
    node_condition3 = iso.numerical_edge_match(
        ['pose_theta'], [0], rtol=errortolerancetheta)

    i = 0
    none_count = 0
    while(True):
        action_dict = fake_action_list[i]

        if(action_dict is None):
            none_count += 1
        else:
            rospy.loginfo("Executing action: %s", action_dict['desc'])
            action = action_dict['action']
            constraints = action_dict['constraints']

            test_agent.executor(action, constraints)
            rospy.sleep(0.1)

        i += 1

        if(none_count == 1):
            rospy.loginfo("Finished block PNP!")
            rospy.loginfo("Adding new block to WS EnvState")

        if(none_count == 2):
            rospy.loginfo("Task complete")
            break

    expectation.print_graph()
    test_agent.get_ws().print_graph()
    result1 = nx.is_isomorphic(
        expectation.ws_state,
        test_agent.get_ws().ws_state,
        node_match=node_condition1)
    result2 = nx.is_isomorphic(
        expectation.ws_state,
        test_agent.get_ws().ws_state,
        node_match=node_condition2)
    result3 = nx.is_isomorphic(
        expectation.ws_state,
        test_agent.get_ws().ws_state,
        node_match=node_condition3)
    result = result1 and result2 and result3

    print("Result 1: ", result1, " and Result 2: ", result2,
          " Result 3: ", result3, " and sum ", result)

if __name__ == "__main__":
    main()


"""
This is test code written outside of the schema files as a means to test
the logic and syntax for creating the lists without worrying about it
affecting anything or being lost.
"""

# code to open and sort movie ratings list
with open("u.data", encoding="latin1") as movieratings:
    ratings_table = movieratings.read()
# user id | item id | rating | timestamp
ratings_list = ratings_table.split('\n')
ratingsrow_list = []
for row in ratings_list:
    row_list = row.split('\t')
    if row_list[0] != '':
        ratingsrow_list.append(row_list)

# code to open and sort movie information
with open("u.item", encoding="latin1") as movieinformation:
    information_table = movieinformation.read()
# movie id|title|releasedate|videodate|imdb|un|act|adv|ani|child|com|crim|doc|drama|fant|
# |f-noir|horror|mus|mys|rom|syfy|thril|war|west
information_list = information_table.split('\n')
inforow_list = []
for row in information_list:
    row_list = row.split('|')
    if row_list[0] != '':
        inforow_list.append(row_list)

# code to open and sort user information
with open("u.user", encoding="latin1") as userinformation:
    user_table = userinformation.read()
# userid | age | gender | occupation | zip code
user_list = user_table.split('\n')
finaluser_list = []
for row in user_list:
    row_list = row.split('|')
    if row_list[0] != '':
        finaluser_list.append(row_list)
for row in finaluser_list:
    print(row[4])


"""Autor: Orlando Urbano Trejo (Lando)
   Fecha: 13-07-2023
   Correo: urbanoorlando79@gmail.com

 Ejercicio: Se requiere determinar el tiempo en que tarda una persona en llegar de una ciudad a otra en bicicleta. Considerando que lleva una velocidad constante
"""

Distancia = float(input("Distancia (en kilómetros): "))
Velocidad = float(input("Velocidad (en kilómetros por hora): "))

tiempo_total = (Distancia * Velocidad) / 60

print(f"El tiempo total de viaje es de {tiempo_total} horas.")


# Weather Alerts Detail
#
# - https://weather.com/swagger-docs/ui/sun/v3/sunV3AlertsWeatherAlertDetail.json
#
# The Weather Alert Details API provides weather watches, warnings, statements and
# advisories issued by the NWS (National Weather Service), Environment Canada and
# MeteoAlarm. These weather alerts can provide crucial life-saving information.
# Weather alerts can be complicated and do not always follow consistent standards,
# format and rules. The Weather Channel (TWC) strives to ensure that the information
# is consistent from all of the different sources but the content is subject to
# change whenever there is an update from the authoritative source. The Weather Alert
# Headlines API returns active weather alert headlines related to Severe
# Thunderstorms, Tornadoes, Earthquakes, Floods, etc . This API also returns
# non-weather alerts such as Child Abduction Emergency and Law Enforcement Warnings.
# The Alert Headlines API also provides a key value found in the attribute to access
# the alert details in the Alert Details API. Your application should first call the
# Weather Alert Headlines API and use the value found in the attribute to request the
# detailed information found in the Weather Alert Details API.
#
# Base URL: api.weather.com/v3
# Endpoint: /alerts/detail

__name__ = 'weatheralertdetails'

from lib.apiutil import host, default_params

def request_options (detail_key):
  url = host + '/v3/alerts/detail'

  params = default_params()
  params['alertId'] = detail_key
  params['format'] = 'json'

  return url, params

def handle_response (res):
  if res and res['alertDetail']:
    alert = res['alertDetail']
    # Main thing here that is not in the alert headline is the alert['texts'] array
    print('weather-alerts-detail: {}'.format(alert['headlineText']))

    if alert['texts']:
      for text in alert['texts']:
        print(text['languageCode'])
        print(text['instruction'])
        print(text['overview'])
        print(text['description'])
    else:
      print('weather-alerts-detail: No alert text available')
  else:
    print('weather-alerts-detail: No alert detail available')


import subprocess
import re
import struct
from cell import Cell

class IWScanner(object):

    def __init__(self, interface="wlan0"):
        self.interface = interface

    def do_scan(self):
        proc = subprocess.Popen("iwlist {} scan".format(self.interface), shell=True, stdout=subprocess.PIPE)
        output = proc.stdout.readlines()
        if "wlan0     Scan completed :" not in output[0]:
            raise "scan failed"

        output = map(lambda x: x.lstrip(" ").rstrip("\n").rstrip(" "), output)[1:-1]
        return self._do_parse('\n'.join(output))

    def _do_parse(self, raw_text):
        top_stack = -1
        cells = []
        lines = raw_text.split('\n')
        for line in lines:
            m = re.match("Cell [0-9]+ - Address: (.*)", line)
            if m:
                cells.append(Cell(m.group(1)))
                top_stack += 1
            m = re.match("Channel:(.*)", line)
            if m: cells[top_stack].channel = int(m.group(1))
            m = re.match("ESSID:\"(.*)\"", line)
            if m: cells[top_stack].essid = m.group(1)
            m = re.match("Quality=([0-9]+)/([0-9]+)  Signal level=(.*) dBm", line)
            if m:
                cells[top_stack].quality = m.group(1), m.group(2)
                cells[top_stack].rssi = int(m.group(3))

        return cells


import pandas as pd
import tensorflow as tf
import numpy as np
import opencl
# Загрузка данных для обучения
data = pd.read_csv('bnb.csv')
# Преобразование данных в массивы NumPy
X_train = data.iloc[:, 1:5].values
y_train = data.iloc[:, 5].values
# Определение структуры модели
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(4, activation='relu'))
model.add(tf.keras.layers.Dense(1))
# Компиляция модели
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
# Обучение модели
with opencl.OpenCLContext() as cl_context:
    model.fit(X_train, y_train, epochs=10, batch_size=32, use_opencl=True, opencl_context=cl_context)
# Сохранение модели
model.save('crypto_model.h5')


import random
import time
import re
from locators.marks_page_locators import MarksLocators
from selenium.webdriver.common.by import By
from regex_patterns.marks_patterns import MarksPatterns
import logging

# logging.basicConfig(format='%(asctime)s %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
#                     datefmt='%d-%m-%Y %H:%M:%S',
#                     level=logging.INFO,
#                     filename='logs.txt')

logger = logging.getLogger('libscrap.marks_parser')

class MarksPage:
    def __init__(self, marks_page):
        self.page = marks_page
        logger.info('Initializing marks page')

    @property
    def all_marks(self):
        logger.debug('Starting all marks function')
        subjects = self.subjects_names
        #subjects = ["Matematyka", "Plastyka"]
        subjects.remove('Zachowanie')
        marks = {}
        for subject in subjects:
            logger.debug(f'Getting marks for {subject} and adding to dictionary')
            marks[subject] = self.get_marks_for_subject(subject)
        return (marks)

    @property
    def subjects_ids(self):
        ids = self.page.find_elements(*MarksLocators.SUBJECTS_ID_LOCATOR)

        id_list = [id.get_attribute('id') for id in ids if id.get_attribute('id') != '']
        return list(id_list)

    @property
    def subjects_names(self):
        logger.debug('generating list of subject names webelements [subject_names func]')
        names = self.page.find_elements(*MarksLocators.SUBJECTS_NAME_LOCATOR)
        #print(len(names))
        logger.debug('extracting text from subject names webelements [subject_names func]')
        names_list = [name.text for name in names if name.text != ' ']
        return names_list

    def get_marks_for_subject(self, subject_name):
        logger.debug('[get_marks_for_subject] getting marks for subject')
        marks_subject = self.page.find_elements(By.XPATH, f'//td[text()="{subject_name}"]//following-sibling::td')
        marks_list = []
        for mark_subject_element in marks_subject:
            marks_list.append(self.extract_marks(mark_subject_element))
        # following columns contain marks: 0,2, 3, 5, 7 approprietly for 1sem, 1sem_final, 2sem, 2sem_final, year_final
        marks_list_temp = [marks_list[0], marks_list[2], marks_list[3], marks_list[5], marks_list[7]]
        semesters = ['1', '1', '2', '2', '2']
        for marks, semester in zip(marks_list_temp, semesters):
            if marks:
                for mark in marks:
                    mark['semester'] = semester
        marks_list = []
        for list in marks_list_temp:
            marks_list.extend(list)

        return marks_list

    def extract_marks(self, many_marks):
        logger.debug('[extract_marks] start')
        marks_list = many_marks.find_elements(*MarksLocators.EXTRACT_MARKS_LOCATOR)
        marks = []
        for mark in marks_list:
            logger.debug('[extract_marks] extracting mark...')
            marks.append(self.mark_details(mark))
        return marks

    def mark_details(self,mark):
        logger.debug('[mark_details] start')
        logger.debug(f'[mark_details] extracting summary from mark: {mark.get_attribute("outerHTML")}')
        summary = mark.find_element(*MarksLocators.SUMMARY_LOCATOR)
        logger.debug('[mark_details] getting text with mark attributes')
        summary_text = summary.get_attribute('title')
        logger.debug(f'[mark_details] starting regex extract from {summary_text}')

        # pattern_category = 'Kategoria: (.*)<br>Data'
        # pattern_date = 'Data: (\d{4}-\d{2}-\d{2})'
        # pattern_average = 'Licz do .redniej: (\w+)'
        # pattern_factor = 'Waga: (\d+)'
        #comment = re.search(pattern_comment, summary_text)
        logger.debug('[mark_details] extracting comment')
        comment = re.search(MarksPatterns.MARK_COMMENT, summary_text)
        logger.debug('[mark_details] extracting category')
        category_extract = re.search(MarksPatterns.MARK_CATEGORY, summary_text)
        category = category_extract.group(1) if category_extract != None else '0'
        logger.debug('[mark_details] extracting date')
        mark_date_extract = re.search(MarksPatterns.MARK_DATE, summary_text)
        mark_date = mark_date_extract.group(1) if mark_date_extract != None else '0'
        logger.debug('[mark_details] extracting average')
        average_extract = re.search(MarksPatterns.MARK_AVERAGE, summary_text)
        average = average_extract.group(1) if average_extract != None else '0'
        logger.debug('[mark_details] extracting factor')
        factor_extract = re.search(MarksPatterns.MARK_FACTOR, summary_text)
        factor = factor_extract.group(1) if factor_extract != None else '0'
        logger.debug('[mark_details] extracting correction')
        correction_extract = re.search(MarksPatterns.MARK_CORRECTION, summary_text)
        correction = correction_extract.group(1) if correction_extract != None else '0'
        logger.debug('[mark_details] extracting comment')
        comment = comment.group(1) if comment != None else '0'
        mark_value = summary.text
        logger.debug('[mark_details] building mark dict')
        mark_dict = {
            'mark_value': mark_value,
            'factor': factor,
            'average': average,
            'category': category,
            'mark_date': mark_date,
            'comment': comment,
            'correction': correction
        }
        logger.debug('[mark_details] returning mark dict')
        return mark_dict

    '''
    marks = [(mark, wage, date, notes),]

    '''


#Double Alphabet function

def getDoubleAlphabet(alphabet):
   doubleAlphabet = alphabet + alphabet
   return doubleAlphabet

alphabet = "ABC"

a = getDoubleAlphabet(alphabet)
print(a)

# get message to encrypt
def getMessage():
   stringToEncrypt = input("Please enter a message to encrypt: ")
   return stringToEncrypt

# Cipher Key
def getCipherKey():
   shiftAmount = input( "Please enter a key (whole number from 1-25): ")
   return shiftAmount

# encrypt message
def encryptMessage(message, cipherKey, alphabet):
    encryptedMessage = ""
    uppercaseMessage = ""
    uppercaseMessage = message.upper()
    for currentCharacter in uppercaseMessage:
        position = alphabet.find(currentCharacter)
        newPosition = position + int(cipherKey)
        if currentCharacter in alphabet:
            encryptedMessage = encryptedMessage + alphabet[newPosition]
        else:
            encryptedMessage = encryptedMessage + currentCharacter
    return encryptedMessage

#decrypt message
def decryptMessage(message, cipherKey, alphabet):
    decryptKey = -1 * int(cipherKey)
    return encryptMessage(message, decryptKey, alphabet)

# main function
def runCaesarCipherProgram():
    myAlphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"  #contains alphabet
    print(f'Alphabet: {myAlphabet}')
    myAlphabet2 = getDoubleAlphabet(myAlphabet) #double the alphabet to be able to shift the letters
    print(f'Alphabet2: {myAlphabet2}')
    myMessage = getMessage()
    print(myMessage)
    myCipherKey = getCipherKey() #get cipher key from user
    print(myCipherKey)
    myEncryptedMessage = encryptMessage(myMessage, myCipherKey, myAlphabet2) #encrypt message
    print(f'Encrypted Message: {myEncryptedMessage}')
    myDecryptedMessage = decryptMessage(myEncryptedMessage, myCipherKey, myAlphabet2)  #decrypt message
    print(f'Decypted Message: {myDecryptedMessage}')

#call the function
runCaesarCipherProgram()


import dash
import re

from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import pandas as pd
import plotly

def __get_cv_columns(df):
    cols = list(df.columns)

    mean_fit_time = ['mean_fit_time']
    mean_score_time = ['mean_score_time']
    std_fit_time = ['std_fit_time']
    std_score_time = ['std_score_time']

    rs = [('mean_train_scores', 'mean_train_([a-zA-Z0-9]*)'),
          ('mean_test_scores', 'mean_test_([a-zA-Z0-9]*)'),
          ('rank_test_scores', 'rank_test_([a-zA-Z0-9]*)'),
          ('splits', 'split([0-9]*)_(test|train)_([_a-zA-Z0-]*)'),
          ('std_scores', 'std_(test|train)_([_a-zA-Z0-9]*)'),
          ('params', 'param_([a-zA-Z0-9]*)'), ]

    b = {}
    for k, r in rs:
        b[k] = [y.string for y in list(filter(None, (re.search(r, x) for x in cols)))]

    metrics = mean_fit_time + mean_score_time + std_fit_time + std_score_time + b['mean_train_scores'] + b['mean_test_scores'] + b['rank_test_scores'] + b['std_scores']

    params = b['params']

    return metrics, params

def __is_cv_results_df(df):
    if 'mean_fit_time' in list(df.columns) and 'mean_score_time' in list(df.columns) and 'std_fit_time' in list(df.columns) and 'std_score_time' in list(df.columns):
        return True

    return False

def __view_results_df(df: pd.DataFrame):
    app = dash.Dash()

    df.fillna('None', inplace=True)

    metrics, params = __get_cv_columns(df)

    df.rename(lambda x: x[6:] if x.startswith('param_') else x, axis='columns', inplace=True)
    params = [p[6:] for p in params]

    c_x = dcc.Checklist(
        options=[{'label': c, 'value': c} for c in params],
        values=params[:2],
        id='radio_x'
    )

    tb = dt.DataTable(
        rows=df.to_dict('records'),
        row_selectable=True,
        filterable=True,
        sortable=True,
        selected_row_indices=[],
        id='datatable'
    )

    t = dcc.Textarea(
        placeholder='',
        value='',
        style={'width': '100%'},
        id='query'
    )

    b = html.Button('Submit',
                    id='submit-query'
                    )

    app.layout = html.Div([
        html.Div([
            html.Div([
                html.H4('LitKit'),
            ], className="col-md-12"),
        ], className="row"),
        html.Div([
            html.Div([
                html.Label('X'),
                c_x,
            ], className="col-md-2"),
            html.Div([
                html.Div([
                    html.Div([
                        html.H5('Time'),
                    ], className="col-md-12"),
                ], className="row"),
                html.Div([
                    html.Div([html.Div([dcc.Graph(id=x)], className="col-md-3") for x in ['mean_fit_time', 'std_fit_time', 'mean_score_time', 'std_score_time']], className='row')
                ], className="row"),
                html.Div([
                    html.Div([
                        html.H5('Scores'),
                    ], className="col-md-12"),
                ], className="row"),
                html.Div([
                    html.Div([html.Div([dcc.Graph(id=x)], className="col-md-3") for x in ['mean_test_score', 'std_test_score', 'mean_train_score', 'std_train_score']], className='row')
                ], className="row"),
                html.Div([
                    html.Div([
                        html.H5('Rank'),
                    ], className="col-md-12"),
                ], className="row"),
                html.Div([
                    html.Div([html.Div([dcc.Graph(id=x)], className="col-md-3") for x in ['rank_test_score', ]], className='row')
                ], className="row"),
                html.Div([
                    html.Div([
                        html.H5('Query'),
                        t,
                        b,
                    ], className="col-md-12"),
                ], className="row"),
                html.Div([
                    html.Div([
                        html.Div([
                        ], id="editor"),
                    ], className="col-md-12", id="editor-p"),
                ], className="row"),
            ], className="col-md-10"),
        ], className="row"),
        html.Div([
            html.Div([
                tb,
            ], className="col-md-12"),
        ], className="row")
    ], className="container-fluid")

    @app.callback(
        Output('datatable', 'rows'),
        [
            Input('submit-query', 'n_clicks'),
        ],
        [
            State('query', 'value'),
        ]
    )
    def update_rows(_, query):
        try:
            rows = df.query(query).to_dict('records')
        except Exception as e:
            rows = df.to_dict('records')

        return rows

    for id in ['mean_fit_time', 'std_fit_time', 'mean_score_time', 'std_score_time', 'mean_test_score', 'std_test_score', 'mean_train_score', 'std_train_score', 'rank_test_score']:
        @app.callback(
            Output(id, 'figure'),
            [
                Input(id, 'id'),
                Input('datatable', 'rows'),
                Input('radio_x', 'values'),
            ])
        def update_figure(id, rows, x_cols):
            for i in range(len(rows)):
                for k in rows[i].keys():
                    if isinstance(rows[i][k], int):
                        rows[i][k] = float(rows[i][k])

            dff = pd.DataFrame(rows)

            fig = plotly.tools.make_subplots(rows=1, cols=1, )

            x_cols = sorted(x_cols)

            if len(x_cols) == 1:
                fig.append_trace({
                    'x': dff[x_cols[0]],
                    'y': dff[id],
                    'type': 'box',
                }, 1, 1)

                fig['layout']['xaxis'] = {'title': x_cols[0], }
                fig['layout']['yaxis'] = {'title': id, }

            if len(x_cols) == 2:
                fig.append_trace({
                    'z': dff[id],
                    'x': dff[x_cols[0]],
                    'y': dff[x_cols[1]],
                    'type': 'heatmap',
                }, 1, 1)

                fig['layout']['xaxis'] = {'title': x_cols[0], }
                fig['layout']['yaxis'] = {'title': x_cols[1], }
                fig['layout']['scene']['zaxis'] = {'title': id, }
                fig['layout']['scene']['xaxis'] = {'title': x_cols[0], }
                fig['layout']['scene']['yaxis'] = {'title': x_cols[1], }

            fig['layout']['showlegend'] = False

            fig['layout']['margin'] = {
                'l': 60,
                'r': 30,
                't': 30,
                'b': 100
            }

            return fig

    app.css.append_css({
        'external_url': 'https://codepen.io/21stio/pen/RQxLLg.css'
    })

    app.css.append_css({
        'external_url': 'https://unpkg.com/bootstrap@4.0.0-alpha.2/dist/css/bootstrap.min.css'
    })

    app.run_server(debug=True)

def __view_df(df):
    raise NotImplemented()

def view(df):
    if __is_cv_results_df(df):
        __view_results_df(df)
    else:
        __view_df(df)


# -*- coding: utf-8 -*-
"""
Log management:
Adds logging to file everytime a task is realised
Logs can be of three levels: INFO, WARNING, ERROR
Adds information to the content fro email and notification if needed
Sends email and/or notification

@author: Kim-Céline FRANOT
"""

import logging
import os
from source.mattermost import Mattermost
from source.e_mail import Email

class Log:
    """
    Class to manage logging

    Attributes:
        nb_error: int
        nb_warning: int
        mattermost: Mattermost
        send_notification: string
        email: Email
        send_emails: string

    Methods:
        info(string, string): None
        error(string, string): None
        warning(string, string): None
        get_file(): string
        send_notification_email(): None
    """

    def __init__(self, notification_=None, emails_=None, webhook_=None):
        self.nb_error = 0
        self.nb_warning = 0
        logging.basicConfig(
            filename="./logfile.log",
            level=logging.INFO,
            format="%(asctime)s - %(levelname)s - %(message)s",
            datefmt="%d/%m/%Y %I:%M:%S %p",
        )
        self.mattermost = None
        self.email = None

        # delete initial content of file
        with open('logfile.log', 'w'):
            pass

        # instantiate Mattermost object
        if notification_ is not None:
            self.send_notification = notification_
            self.mattermost = Mattermost(self, webhook_)
            if notification_ not in ("always", "error", "never"):
                self.send_notification = "always"
                self.warning("Config File", "Notification value not supported. Default value 'always' applied")

        # instantiate Email Object
        if emails_ is not None:
            self.send_emails = emails_["send-mail"].lower()
            self.email = Email(emails_, self)

            if self.send_emails not in ("yes", "y", "no", "n"):
                self.send_emails = "yes"
                self.warning("Config File", "Email value not supported. Default value 'yes' applied")

    def info(self, action_name, message=None):
        """
        Add info message to log file, notification and email body
        :param action_name: string
        :param message: string
        :return: None
        """
        if message is not None:
            logging.info("%s: %s", action_name, message)
        else:
            logging.info('Task: "%s" went smoothly.', action_name)

        # add content to mattermost notification is needed
        if self.mattermost is not None:
            self.mattermost.set_info(action_name)

        # add content to email body is needed
        if self.email is not None:
            if message is not None:
                self.email.add_content("INFO", action_name + ": " + message)
            else:
                self.email.add_content("INFO", action_name + ": task successful")

    def error(self, action_name, message=None):
        """
        Add error message to log file, notification and email body
        :param action_name: string
        :param message: string
        :return: None
        """
        self.nb_error += 1
        if message is not None:
            logging.error("%s: %s", action_name, message)
        else:
            logging.error('Task: "%s" failed.', action_name)

        # add content to mattermost notification is needed
        if self.mattermost is not None:
            self.mattermost.set_error(action_name)

        # add content to email body is needed
        if self.email is not None:
            if message is not None:
                self.email.add_content("ERROR", action_name + ": " + message)
            else:
                self.email.add_content("ERROR", action_name + ": task failed")

    def warning(self, action_name, message=None):
        """
        Add warning message to log file, notification and email body
        :param action_name: string
        :param message: string
        :return: None
        """
        self.nb_warning += 1
        if message is not None:
            logging.warning("%s: %s", action_name, message)
        else:
            logging.warning('Task: "%s" raised a warning.', action_name)

        # add content to mattermost notification is needed
        if self.mattermost is not None:
            self.mattermost.set_warning(action_name)

        # add content to email body is needed
        if self.email is not None:
            if message is not None:
                self.email.add_content("WARNING", action_name + ": " + message)
            else:
                self.email.add_content("WARNING", action_name + ": task raised a warning")

    def get_file(self):
        """
        method that returns the path to the log file
        :return: string
        """
        return str(os.path.abspath("logfile.log"))

    def send_notification_email(self):
        """
        method to send email and/or notification
        :return: None
        """
        # notification to be sent if not None
        if self.mattermost is not None and self.send_notification is not None:
            # send notification if value is always or if value is error and errors have been encountered
            if self.send_notification == "always" or (self.send_notification == "error" and self.nb_error > 0):
                self.mattermost.send_notification()

        # email to be sent if not None
        if self.email is not None and self.send_emails in ("yes", "y"):
            # add a title according to number of errors or warnings found
            if self.nb_error > 0:
                self.email.err_warning = "Service disrupted due to " + str(self.nb_error) + " error(s)"
            else:
                self.email.err_warning = "Service completed with " + str(self.nb_warning) + " warning(s)"
            # send email
            self.email.send_email()


#!/usr/local/bin/python3.5

from sys import argv
from bs4 import BeautifulSoup #HTML Parser
import pdb
import shutil
import urllib.request
import requests
import os

TOPIC = "Äquivalenzrelationen"

#Functions-------------------------
def replaceTag(tag, newTag):
    tag.insert_after(newTag)
    tag.unwrap() #Delete old tag

def replaceMathTag(mathTag):
    content = mathTag.get("tex")
    newTag = '$' + content + '$'

    replaceTag(mathTag, newTag)

#example fileUrl:
#https://de.wikibooks.org/wiki/Datei:Drehung_um_90_Grad_und_um_450_Grad.svg
def downloadPictureFromWikifile(fileUrl, fileName):
    picRequest = requests.get(fileUrl)

    soup = BeautifulSoup(picRequest.text , 'html.parser')
    linkTagToOriginal = soup.find_all("a", string="Originaldatei")[0]
    picUrl = linkTagToOriginal.get("href")
    picUrl = "https:" + picUrl

    urllib.request.urlretrieve(picUrl, fileName)

#Need inkscape installed!
def convertImgSvgToPdf(imgPath, outName):
    os.system("inkscape -f " + imgPath + "-A" + outName)

def replaceFigure(figureTag):
    #exchange svgs to pdfs!
    figureHref = figureTag.get("href")
    figureHeightFile = figureTag.get("data-file-height")
    figureHeightFile = figureTag.get("data-file-width")
    figureHeight = figureTag.get("height")
    figureHeight = figureTag.get("width")

    fileName =  figureHref[8:]
    filePage = "https://de.wikibooks.org/wiki/Datei:" + fileName
    downloadPictureFromWikifile(filePage, fileName)
    convertImgSvgToPdf(fileName, "test1")

    #replaceTag(mathTag, newTag)

#Main------------------------------
if __name__ == "__main__":

     pdb.set_trace()
#
    #inputHtmlFileName = argv[1]
    #inputHtmlFile = open(inputHtmlFileName)
    #inputHtml = inputHtmlFile.read()
#
    #soup = BeautifulSoup(inputHtml , 'html.parser')
    #mathTags = soup.find_all('math')
    #
    #for tag in mathTags:
        #replaceMathTag(tag)
#
    #
    #open(TOPIC + '.tex', 'w').close() #clean file: empty
    #testFile = open(TOPIC + '.tex', 'a')
    #testFile.write(soup.prettify())
#


def checkio(words: str) -> bool:
    count = 0
    li = words.split()
    for i in li:
        if i.isnumeric():
            count = 0
        else:
            count += 1
        if count == 3:
            return True
    return False

#These "asserts" using only for self-checking and not necessary for auto-testing
if __name__ == '__main__':
    print('Example:')
    print(checkio("Hello World hello"))

    assert checkio("Hello World hello") == True, "Hello"
    assert checkio("He is 123 man") == False, "123 man"
    assert checkio("1 2 3 4") == False, "Digits"
    assert checkio("bla bla bla bla") == True, "Bla Bla"
    assert checkio("Hi") == False, "Hi"


import argparse
import pickle
import gym
import time
import numpy as np
import random
import torch
import torch.nn as nn
import torch.nn.functional as F
import d4rl # Import required to register environments
import deepdish as dd
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

def parallel_predict_reward_sequence(net, traj):
    rewards_from_obs = []
    steps = 0
    batch_size = 10
    with torch.no_grad():
        for s in traj:
            steps += 1
            if steps % 100000 == 0:
                print(f'steps: {steps}')
            r = net.parallel_cum_return(torch.from_numpy(np.array([s])).float().to(device))[0].tolist()
            if isinstance(r,float):
                rewards_from_obs.append(r)
            else:
                rewards_from_obs.extend(r)
    return rewards_from_obs

def generate_novice_demos(dataset, num_trajs, traj_length, steps=0):
    demonstrations = []
    learning_returns = []
    learning_rewards = []

    for i in range(num_trajs):
        done = False
        traj = []
        gt_rewards = []
        r = 0

        acc_reward = 0

        while True:
            ob, r, done = dataset['observations'][steps], dataset['rewards'][steps], dataset['terminals'][steps]
            traj.append(ob)
            gt_rewards.append(r)
            steps += 1
            acc_reward += r
            # no terminal states for maze
            # if done:
            if steps % traj_length == 0:
                # print("checkpoint: {}, steps: {}, return: {}".format(checkpoint, steps,acc_reward))
                # print("steps: {}, return: {}".format(steps,acc_reward))
                break
        demonstrations.append(traj)
        learning_returns.append(acc_reward)
        learning_rewards.append(gt_rewards)

    return demonstrations, learning_returns, learning_rewards

def create_training_data(demonstrations, num_trajs, num_snippets, min_snippet_length, max_snippet_length):
    #collect training data
    max_traj_length = 0
    training_obs = []
    training_labels = []
    num_demos = len(demonstrations)

    #add full trajs (for use on Enduro)
    for n in range(num_trajs):
        ti = 0
        tj = 0
        #only add trajectories that are different returns
        while(ti == tj):
            #pick two random demonstrations
            ti = np.random.randint(num_demos)
            tj = np.random.randint(num_demos)
        #create random partial trajs by finding random start frame and random skip frame
        # si = np.random.randint(6)
        # sj = np.random.randint(6)
        # step = np.random.randint(3,7)

        traj_i = demonstrations[ti]  #slice(start,stop,step)
        traj_j = demonstrations[tj]

        if ti > tj:
            label = 0
        else:
            label = 1

        training_obs.append((traj_i, traj_j))
        training_labels.append(label)
        max_traj_length = max(max_traj_length, len(traj_i), len(traj_j))

    #fixed size snippets with progress prior
    for n in range(num_snippets):
        ti = 0
        tj = 0
        #only add trajectories that are different returns
        while(ti == tj):
            #pick two random demonstrations
            ti = np.random.randint(num_demos)
            tj = np.random.randint(num_demos)
        #create random snippets
        #find min length of both demos to ensure we can pick a demo no earlier than that chosen in worse preferred demo
        min_length = min(len(demonstrations[ti]), len(demonstrations[tj]))
        rand_length = np.random.randint(min_snippet_length, max_snippet_length)
        if ti < tj: #pick tj snippet to be later than ti
            ti_start = np.random.randint(min_length - rand_length + 1)
            #print(ti_start, len(demonstrations[tj]))
            tj_start = np.random.randint(ti_start, len(demonstrations[tj]) - rand_length + 1)
        else: #ti is better so pick later snippet in ti
            tj_start = np.random.randint(min_length - rand_length + 1)
            #print(tj_start, len(demonstrations[ti]))
            ti_start = np.random.randint(tj_start, len(demonstrations[ti]) - rand_length + 1)
        traj_i = demonstrations[ti][ti_start:ti_start+rand_length:2] #skip everyother framestack to reduce size
        traj_j = demonstrations[tj][tj_start:tj_start+rand_length:2]

        max_traj_length = max(max_traj_length, len(traj_i), len(traj_j))
        if ti > tj:
            label = 0
        else:
            label = 1
        training_obs.append((traj_i, traj_j))
        training_labels.append(label)

    return training_obs, training_labels

# Train the network
def learn_reward(reward_network, optimizer, training_inputs, training_outputs, num_iter, l1_reg, checkpoint_dir):
    #check if gpu available
    # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    # Assume that we are on a CUDA machine, then this should print a CUDA device:
    # print(device)
    loss_criterion = nn.CrossEntropyLoss()

    cum_loss = 0.0
    training_data = list(zip(training_inputs, training_outputs))
    for epoch in range(num_iter):
        np.random.shuffle(training_data)
        training_obs, training_labels = zip(*training_data)
        for i in range(len(training_labels)):
            traj_i, traj_j = training_obs[i]
            labels = np.array([training_labels[i]])
            traj_i = np.array(traj_i)
            traj_j = np.array(traj_j)
            traj_i = torch.from_numpy(traj_i).float().to(device)
            traj_j = torch.from_numpy(traj_j).float().to(device)
            labels = torch.from_numpy(labels).to(device)

            #zero out gradient
            optimizer.zero_grad()

            #forward + backward + optimize
            outputs, abs_rewards = reward_network.forward(traj_i, traj_j)
            outputs = outputs.unsqueeze(0)
            loss = loss_criterion(outputs, labels) + l1_reg * abs_rewards
            loss.backward()
            optimizer.step()

            #print stats to see if learning
            item_loss = loss.item()
            cum_loss += item_loss
            if i % 100 == 99:
                #print(i)
                # print("epoch {}:{} loss {}".format(epoch,i, cum_loss))
                # print(abs_rewards)
                cum_loss = 0.0
                # print("check pointing")
                # torch.save(reward_net.state_dict(), checkpoint_dir)
    # print("finished training")

def calc_accuracy(reward_network, training_inputs, training_outputs):
    # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    loss_criterion = nn.CrossEntropyLoss()
    num_correct = 0.
    with torch.no_grad():
        for i in range(len(training_inputs)):
            label = training_outputs[i]
            traj_i, traj_j = training_inputs[i]
            traj_i = np.array(traj_i)
            traj_j = np.array(traj_j)
            traj_i = torch.from_numpy(traj_i).float().to(device)
            traj_j = torch.from_numpy(traj_j).float().to(device)

            #forward to get logits
            outputs, abs_return = reward_network.forward(traj_i, traj_j)
            _, pred_label = torch.max(outputs,0)
            if pred_label.item() == label:
                num_correct += 1.
    return num_correct / len(training_inputs)

def test_calc_accuracy(reward_network, training_inputs, training_outputs):
    # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    loss_criterion = nn.CrossEntropyLoss()
    num_correct = 0.
    with torch.no_grad():
        for i in range(len(training_inputs)):
            label = training_outputs[i]
            traj_i, traj_j = training_inputs[i]
            traj_i = np.array(traj_i)
            traj_j = np.array(traj_j)
            traj_i = torch.from_numpy(traj_i).float().to(device)
            traj_j = torch.from_numpy(traj_j).float().to(device)

            #forward to get logits
            outputs, abs_return = reward_network.test_forward(traj_i, traj_j)
            _, pred_label = torch.max(outputs,0)
            if pred_label.item() == label:
                num_correct += 1.
    return num_correct / len(training_inputs)

def predict_reward_sequence(net, traj):
    # device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    rewards_from_obs = []
    steps = 0
    with torch.no_grad():
        for s in traj:
            steps += 1
            if steps % 100000 == 0:
                print(f'steps: {steps}')
            r = net.cum_return(torch.from_numpy(np.array([s])).float().to(device))[0].item()
            rewards_from_obs.append(r)
    return rewards_from_obs

def predict_traj_return(net, traj):
    return sum(predict_reward_sequence(net, traj))

def stable_softmax(x, beta):
    #Bradley-Terry Luce-Shepherd function for prefs (essentially cross entropy loss)
    x = beta * np.array(x)
    z = x - np.max(x, axis=-1, keepdims=True)
    numerator = np.exp(z)
    denominator = np.sum(numerator, axis=-1, keepdims=True)
    softmax = numerator / denominator
    return softmax

def gen_dropout_distribution_pair(traj_a, traj_b, dropout_net, num_dropout_samples, device):
    '''
        input: two trajs, a trained dropout network, the number of dropout samples, and the device (cpu or cuda)
        output: the posterior over the rewards for the two trajs
    '''
    # dropout_returns_a = np.zeros(num_dropout_samples)
    # dropout_returns_b = np.zeros(num_dropout_samples)
    dropout_returns_a = []
    dropout_returns_b = []
    dropout_masks = []
    #run the traj through the network
    #convert to pytorch tensor
    traj_a = np.array(traj_a)
    traj_a = torch.from_numpy(traj_a).float().to(device)
    traj_b = np.array(traj_b)
    traj_b = torch.from_numpy(traj_b).float().to(device)

    #first run traj_a through dropout net and save the masks for traj_b
    for _ in range(num_dropout_samples):
        cum_ret, _, dmask = dropout_net.cum_return(traj_a)
        dropout_masks.append(dmask)
        dropout_returns_a.append(cum_ret.item())

    for i in range(num_dropout_samples):
        cum_ret, _, _ = dropout_net.cum_return(traj_b, dropout_masks[i])
        # dropout_masks.append(dmask) #where is this dmask coming from
        dropout_returns_b.append(cum_ret.item())

    return dropout_returns_a, dropout_returns_b

def pref_info_gain(rewards_x, rewards_y, beta=1):
    '''
        input: rewards_x and rewards_y are lists of the different possible outcomes of two experiments involving x and y (x and y will typically be trajectories)
                These scores come from generating n samples of the posterior distribution
        output: the empirical estiamte of the expected information gain of running a preference query experiment between x and y on the parameters of the reward (score) model posterior
        I(theta; Pref | Data) = H(Pref | Data) - Expectation over thetas [H(Pref | theta, Data)]
        where theta is the random variable representing the true reward function params, Data is the set of prefs so far,
        and Pref is a possible pair of trejctories we ask the user for a preference over

        Note that beta is set to 1 by default. If you know the person provides noisy labels it could be set lower
        if you know the labels are always correct you could set them higher, but I think beta = 1 is a decent value
    '''

    assert(len(rewards_x) == len(rewards_y))

    #calculate the probability of a user preference given each pair of samples rewards
    rewards_xy = np.stack((rewards_x, rewards_y), axis=1)
    probs = stable_softmax(rewards_xy, beta)

    #compute the entropy
    hs = -np.sum(probs * np.log2(probs), axis=1)

    #compute average probs for each option
    ave_ps = np.mean(probs, axis=0)

    #compute the entropy of preference given the current data: H(Pref | Data)
    H1 = -np.sum(ave_ps * np.log2(ave_ps))

    #compute the expected conditional entropy given the outcome of the preference query: Expectation over thetas [H(Pref | theta, Data)]
    H2 = np.mean(hs)

    return H1 - H2
    #this term will be large if H1 is high, i.e. if the model is quite uncertain (i.e. ave probs are close to 0.5)
    #and H2 is low, i.e., the individual samples from the posterior are quite certain

#pseudo-code for active query selection using info-gain
def select_active_query(pref_pair_pool, dropout_net, num_dropout_samples, device, beta):
    '''
        input: pref_pair_pool is a list of unlabelled 2-tuples of possible trajectories to ask for a preference over
                dropout_net is a T-REX net with dropout that has been trained on the prefs collected so far
                num_dropout_samples is the number of times to run through the dropout_net to approximate the posterior
                device is either cpu or cuda to make sure data is loaded correctly for running through the nnet

        output: the pair from the pref_pair_pool with highest info gain and the corresponding info_gain
    '''
    # best_pair = None
    max_info_gain = -np.inf
    best_idx = None
    # for traj_a, traj_b in pref_pair_pool:
    info_gain_list = []
    for i in range(len(pref_pair_pool)):
        traj_a, traj_b = pref_pair_pool[i]
        rewards_a, rewards_b = gen_dropout_distribution_pair(traj_a, traj_b, dropout_net, num_dropout_samples, device)
        # print('rewards_a', rewards_a)
        # print('rewards_b', rewards_b)
        info_gain = pref_info_gain(rewards_a, rewards_b, beta)
        # print('info_gain', info_gain)
        info_gain_list.append(info_gain)

        # #check if best found so far
        # if info_gain > max_info_gain:
        #     max_info_gain = info_gain
        #     # best_pair = (traj_a, traj_b)
        #     best_idx = i

    return info_gain_list

def gen_dropout_distribution_pair(traj_a, traj_b, dropout_net, num_dropout_samples, device):
    '''
        input: two trajs, a trained dropout network, the number of dropout samples, and the device (cpu or cuda)
        output: the posterior over the rewards for the two trajs
    '''
    # dropout_returns_a = np.zeros(num_dropout_samples)
    # dropout_returns_b = np.zeros(num_dropout_samples)
    dropout_returns_a = []
    dropout_returns_b = []
    dropout_masks = []
    #run the traj through the network
    #convert to pytorch tensor
    traj_a = np.array(traj_a)
    traj_a = torch.from_numpy(traj_a).float().to(device)
    traj_b = np.array(traj_b)
    traj_b = torch.from_numpy(traj_b).float().to(device)

    #first run traj_a through dropout net and save the masks for traj_b
    for _ in range(num_dropout_samples):
        cum_ret, _, dmask = dropout_net.cum_return(traj_a)
        dropout_masks.append(dmask)
        dropout_returns_a.append(cum_ret.item())

    for i in range(num_dropout_samples):
        cum_ret, _, _ = dropout_net.cum_return(traj_b, dropout_masks[i])
        # dropout_masks.append(dmask) #where is this dmask coming from
        dropout_returns_b.append(cum_ret.item())

    return dropout_returns_a, dropout_returns_b

class Net(nn.Module):
    def __init__(self, input_dim):
        super().__init__()
        self.input_dim = input_dim

        # define a simple MLP neural net
        self.net = []
        nin, nout = self.input_dim, 1
        hidden_sizes = [512, 256, 128, 64, 32]
        hs = [nin] + hidden_sizes + [nout]
        for h0,h1 in zip(hs, hs[1:]):
            self.net.extend([
                    nn.Linear(h0, h1),
                    nn.ReLU(),
                ])
        self.net.pop() # pop the last ReLU for the output layer
        self.net = nn.Sequential(*self.net)

    def cum_return(self, traj):
        '''calculate cumulative return of trajectory'''
        sum_rewards = 0
        sum_abs_rewards = 0

        #compute forward pass of reward network (we parallelize across frames so batch size is length of partial trajectory)
        x = traj
        x = x.view(-1,self.input_dim)
        r = self.net(x)

        sum_rewards += torch.sum(r)
        sum_abs_rewards += torch.sum(torch.abs(r))
        return sum_rewards, sum_abs_rewards

    def parallel_cum_return(self, traj):
        '''calculate cumulative return of trajectory'''
        sum_rewards = 0
        sum_abs_rewards = 0

        #compute forward pass of reward network (we parallelize across frames so batch size is length of partial trajectory)
        x = traj
        x = x.view(-1,self.input_dim)
        r = self.net(x)

        sum_rewards = r.squeeze()
        sum_abs_rewards = torch.abs(r).squeeze()
        return sum_rewards, sum_abs_rewards

    def forward(self, traj_i, traj_j):
        '''compute cumulative return for each trajectory and return logits'''
        cum_r_i, abs_r_i = self.cum_return(traj_i)
        cum_r_j, abs_r_j = self.cum_return(traj_j)
        return torch.cat((cum_r_i.unsqueeze(0), cum_r_j.unsqueeze(0)),0), abs_r_i + abs_r_j

    def get_returns(self, traj_i, traj_j):
        '''compute cumulative return for each trajectory and return logits'''
        cum_r_i, abs_r_i = self.cum_return(traj_i)
        cum_r_j, abs_r_j = self.cum_return(traj_j)

        return cum_r_i, cum_r_j

class DropoutNet(nn.Module):
    def __init__(self, input_dim):
        super().__init__()
        self.input_dim = input_dim
        # self.input_dim = 17
        # self.input_dim = 2

        # number of hidden nodes in each layer (512)
        self.hidden_sizes = [512, 256, 128, 64, 32]

        # hidden_sizes = [256, 256, 256, 256, 256, 128, 64, 32] # for walker2d

        # linear layer (784 -> hidden_1)
        self.fc1 = nn.Linear(self.input_dim, self.hidden_sizes[0])
        # linear layer (n_hidden -> hidden_2)
        self.fc2 = nn.Linear(self.hidden_sizes[0],self.hidden_sizes[1])
        self.fc3 = nn.Linear(self.hidden_sizes[1],self.hidden_sizes[2])
        self.fc4 = nn.Linear(self.hidden_sizes[2],self.hidden_sizes[3])
        # linear layer (n_hidden -> 10)
        self.fc5 = nn.Linear(self.hidden_sizes[3],self.hidden_sizes[4])
        self.fc6 = nn.Linear(self.hidden_sizes[4],1)

    def cum_return(self, traj, mask=None):
        '''calculate cumulative return of trajectory'''
        sum_rewards = 0
        sum_abs_rewards = 0
        #compute forward pass of reward network (we parallelize across frames so batch size is length of partial trajectory)

        #if mask is given then use it, otherwise generate one new mask to use for all states in the trajectory
        if mask is None:
            my_mask = (torch.rand(self.hidden_sizes[4]) < 0.5).float().to(device) / 0.5
            # my_mask = [(torch.rand(hs) < 0.5).float().to(device) / 0.5 for hs in self.hidden_sizes] #is 0.5 too much?
        else:
            my_mask = mask

        x = traj
        x = x.view(-1,self.input_dim)

        # x = F.relu(self.fc1(x)) * my_mask[0] #mask after this, hidden_1
        # x = F.relu(self.fc2(x)) * my_mask[1] #mask after this, Hidden_2
        # x = F.relu(self.fc3(x)) * my_mask[2] #mask after this, hidden_3
        # x = F.relu(self.fc4(x)) * my_mask[3] #mask after this, hidden_4
        # x = F.relu(self.fc5(x)) * my_mask[4] #mask after this, hidden_5
        # r = self.fc6(x) #don't mask after this for now. Check with Daniel Brown

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = F.relu(self.fc4(x))
        x = F.relu(self.fc5(x)) * my_mask
        # r = self.fc6(x) #don't mask after this for now. Check with Daniel Brown
        r = F.relu(self.fc6(x))

        sum_rewards += torch.sum(r)
        sum_abs_rewards += torch.sum(torch.abs(r))
        return sum_rewards, sum_abs_rewards, my_mask

    def parallel_cum_return(self, traj, mask=None):
        '''calculate cumulative return of trajectory'''
        sum_rewards = 0
        sum_abs_rewards = 0
        #compute forward pass of reward network (we parallelize across frames so batch size is length of partial trajectory)
        #if mask is given then use it, otherwise generate one new mask to use for all states in the trajectory
        if mask is None:
            my_mask = (torch.rand(self.hidden_sizes[4]) < 0.5).float().to(device) / 0.5
            # my_mask = [(torch.rand(hs) < 0.5).float().to(device) / 0.5 for hs in self.hidden_sizes]
        else:
            my_mask = mask

        x = traj
        x = x.view(-1,self.input_dim)

        # x = F.relu(self.fc1(x)) * my_mask[0] #mask after this, hidden_1
        # x = F.relu(self.fc2(x)) * my_mask[1] #mask after this, Hidden_2
        # x = F.relu(self.fc3(x)) * my_mask[2] #mask after this, hidden_3
        # x = F.relu(self.fc4(x)) * my_mask[3] #mask after this, hidden_4
        # x = F.relu(self.fc5(x)) * my_mask[4] #mask after this, hidden_5
        # r = self.fc6(x) #don't mask after this for now. Check with Daniel Brown

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = F.relu(self.fc4(x))
        x = F.relu(self.fc5(x)) * my_mask
        # r = self.fc6(x) #don't mask after this for now. Check with Daniel Brown
        r = F.relu(self.fc6(x))

        sum_rewards = r.squeeze()
        sum_abs_rewards = torch.abs(r).squeeze()
        # print('sum_rewards.size()', sum_rewards.size())
        # print('sum_rewards', sum_rewards)
        return sum_rewards, sum_abs_rewards, my_mask

    def test_cum_return(self, traj):
        '''calculate cumulative return of trajectory'''
        sum_rewards = 0
        sum_abs_rewards = 0
        #compute forward pass of reward network (we parallelize across frames so batch size is length of partial trajectory)

        x = traj
        x = x.view(-1,self.input_dim)

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = F.relu(self.fc4(x))
        x = F.relu(self.fc5(x))
        # r = self.fc6(x) #don't mask after this for now. Check with Daniel Brown
        r = F.relu(self.fc6(x))

        sum_rewards += torch.sum(r)
        sum_abs_rewards += torch.sum(torch.abs(r))
        return sum_rewards, sum_abs_rewards

    def test_parallel_cum_return(self, traj, mask=None):
        '''calculate cumulative return of trajectory'''
        sum_rewards = 0
        sum_abs_rewards = 0
        #compute forward pass of reward network (we parallelize across frames so batch size is length of partial trajectory)
        #if mask is given then use it, otherwise generate one new mask to use for all states in the trajectory

        x = traj
        x = x.view(-1,self.input_dim)

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = F.relu(self.fc4(x))
        x = F.relu(self.fc5(x))
        # r = self.fc6(x) #don't mask after this for now. Check with Daniel Brown
        r = F.relu(self.fc6(x))

        sum_rewards = r.squeeze()
        sum_abs_rewards = torch.abs(r).squeeze()
        # print('sum_rewards.size()', sum_rewards.size())
        # print('sum_rewards', sum_rewards)
        return sum_rewards, sum_abs_rewards

    def forward(self, traj_i, traj_j):
        '''compute cumulative return for each trajectory and return logits'''
        cum_r_i, abs_r_i, mask = self.cum_return(traj_i)
        cum_r_j, abs_r_j, _ = self.cum_return(traj_j, mask)
        return torch.cat((cum_r_i.unsqueeze(0), cum_r_j.unsqueeze(0)),0), abs_r_i + abs_r_j

    def test_forward(self, traj_i, traj_j):
        '''compute cumulative return for each trajectory and return logits'''
        cum_r_i, abs_r_i = self.test_cum_return(traj_i)
        cum_r_j, abs_r_j = self.test_cum_return(traj_j)
        return torch.cat((cum_r_i.unsqueeze(0), cum_r_j.unsqueeze(0)),0), abs_r_i + abs_r_j


from threading import Thread
import datetime, time
import os
from datetime import datetime
import pickle
import logging
import sys

# logger = logging.getLogger('spider')

# 指定logger输出格式
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')

# 控制台日志
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter  # 也可以直接给formatter赋值

def getlog(name):
    logger = logging.getLogger(name)
    # 文件日志
    file_handler = logging.FileHandler("./log/%s.log"%name)
    file_handler.setFormatter(formatter)  # 可以通过setFormatter指定输出格式

    # 为logger添加的日志处理器
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)

    # 指定日志的最低输出级别，默认为WARN级别
    logger.setLevel(logging.INFO)
    return logger

class Result:

    def __init__(self):
        self.data = ''

def exc_cmd(cmd, timeout):
    data = Result()
    t = Thread(target=run_cmd, args=(cmd, data))
    t.start()
    start = datetime.now()
    while not data.data:
        time.sleep(0.2)
        now = datetime.now()
        if (now - start).seconds > timeout:
            t.join(5)
            return None
    return data.data

def run_cmd(cmd, data):
    result = os.popen(cmd).read()
    data.data = result

def parse_cookie(cookie):
    item = cookie.split(';')
    cookies = []
    for it in item:
        cookie_dt = {}
        res = it.split('=')
        cookie_dt['name'] = res[0]
        cookie_dt['value'] = res[1]
        cookies.append(cookie_dt)
    return cookies

start = datetime(1970, 4, 19, 12, 20).strftime('%Y-%m-%d %H:%M:%S')

class History:

    def __init__(self, username):
        self.username = username
        self.yc_endtime = datetime(1970, 4, 19, 12, 20).strftime('%Y-%m-%d %H:%M')
        self.ch_endtime = start
        self.ic_endtime = start
        self.format = '%Y-%m-%d %H:%M:%S'
        self.formats = '%Y%m%d%H%M%S'
        self.yc_endtime_tmp = ''
        self.ch_endtime_tmp = ''
        self.ic_endtime_tmp = ''
        self.index = 0
        try:
            f = open('tp.plk', 'rb')
            dt = pickle.load(f)
            self.yc_endtime = dt.get('yc'+self.username,datetime(1970, 4, 19, 12, 20).strftime('%Y-%m-%d %H:%M'))
            self.ch_endtime = dt.get('ch'+self.username, start)
            self.ic_endtime = dt.get('ic'+self.username, start)
            f.close()
        except:
            pass

    def vild_yiche(self, dt):
        format = '%Y-%m-%d %H:%M'
        end_time = datetime.strptime(self.yc_endtime, format)
        now = datetime.strptime(dt, format)
        return end_time < now

    def vild_carhome(self, dt):
        end_time = datetime.strptime(self.ch_endtime, self.format)
        now = datetime.strptime(dt, self.format)
        # print(end_time, now, end_time < now)
        return end_time < now

    def vild_icar(self, dt):
        end_time = datetime.strptime(self.ic_endtime, self.format)
        now = datetime.strptime(dt, self.format)
        return end_time < now

    def test(self):
        f = open('tp.plk', 'rb')
        dt = pickle.load(f)
        if self.yc_endtime_tmp:
            dt['yc'] = self.yc_endtime_tmp
        if self.ch_endtime_tmp:
            dt['ch'] = self.ch_endtime_tmp
        if self.ic_endtime_tmp:
            dt['ic'] = self.ic_endtime_tmp
        print(dt)
        f.close()

    def save(self):
        try:
            f = open('tp.plk', 'rb')
            dt = pickle.load(f)
            if self.yc_endtime_tmp:
                dt['yc'+self.username] = self.yc_endtime_tmp
            if self.ch_endtime_tmp:
                dt['ch'+self.username] = self.ch_endtime_tmp
            if self.ic_endtime_tmp:
                dt['ic'+self.username] = self.ic_endtime_tmp
            f.close()
            tmp = dt
        except Exception as e:
            tmp = {}
            if self.yc_endtime_tmp:
                tmp['yc'+self.username] = self.yc_endtime_tmp
            if self.ch_endtime_tmp:
                tmp['ch'+self.username] = self.ch_endtime_tmp
            if self.ic_endtime_tmp:
                tmp['ic'+self.username] = self.ic_endtime_tmp
        with open('tp.plk', 'wb') as f:
            pickle.dump(tmp, f)

    def __del__(self):
        # tmp = None
        # self.save()
        pass

if __name__ == '__main__':
    history = History()
    print(history.ch_endtime)
    print(history.yc_endtime)
    print(history.ic_endtime)
    # history.ch_endtime_tmp = '2018-03-23 12:20:00'
    # print(history.vild_carhome('1977-04-19 12:20:00'))
    # print(history.yc_endtime)
    # print(history.vild_yiche('1977-04-19 12:20'))
    # history.save()
    # history.test()


import logging
# import cmapPy.pandasGEXpress.setup_GCToo_logger as setup_logger
from cmappython3 import setup_GCToo_logger as setup_logger
import os
import numpy as np
import pandas as pd
import h5py
# import cmapPy.pandasGEXpress.GCToo as GCToo

__author__ = "Oana Enache"
__email__ = "oana@broadinstitute.org"

# instantiate logger
logger = logging.getLogger(setup_logger.LOGGER_NAME)

version_node = "version"
rid_node = "/0/META/ROW/id"
cid_node = "/0/META/COL/id"
data_node = "/0/DATA/0/matrix"
row_meta_group_node = "/0/META/ROW"
col_meta_group_node = "/0/META/COL"

def parse(gctx_file_path, convert_neg_666=True, rid=None, cid=None,
          ridx=None, cidx=None, row_meta_only=False, col_meta_only=False, make_multiindex=False):
    """
    Primary method of script. Reads in path to a gctx file and parses into GCToo object.

    Input:
        Mandatory:
        - gctx_file_path (str): full path to gctx file you want to parse.

        Optional:
        - convert_neg_666 (bool): whether to convert -666 values to numpy.nan or not
            (see Note below for more details on this). Default = False.
        - rid (list of strings): list of row ids to specifically keep from gctx. Default=None.
        - cid (list of strings): list of col ids to specifically keep from gctx. Default=None.
        - ridx (list of integers): only read the rows corresponding to this
            list of integer ids. Default=None.
        - cidx (list of integers): only read the columns corresponding to this
            list of integer ids. Default=None.
        - row_meta_only (bool): Whether to load data + metadata (if False), or just row metadata (if True)
            as pandas DataFrame
        - col_meta_only (bool): Whether to load data + metadata (if False), or just col metadata (if True)
            as pandas DataFrame
        - make_multiindex (bool): whether to create a multi-index df combining
            the 3 component dfs

    Output:
        - myGCToo (GCToo): A GCToo instance containing content of parsed gctx file. Note: if meta_only = True,
            this will be a GCToo instance where the data_df is empty, i.e. data_df = pd.DataFrame(index=rids,
            columns = cids)

    Note: why does convert_neg_666 exist?
        - In CMap--for somewhat obscure historical reasons--we use "-666" as our null value
        for metadata. However (so that users can take full advantage of pandas' methods,
        including those for filtering nan's etc) we provide the option of converting these
        into numpy.NaN values, the pandas default.
    """
    full_path = os.path.expanduser(gctx_file_path)

    # Verify that the  path exists
    if not os.path.exists(full_path):
        err_msg = "The given path to the gctx file cannot be found. full_path: {}"
        logger.error(err_msg.format(full_path))
        raise Exception(err_msg.format(full_path))
    logger.info("Reading GCTX: {}".format(full_path))

    # open file
    gctx_file = h5py.File(full_path, "r")

    if row_meta_only:
        # read in row metadata
        row_dset = gctx_file[row_meta_group_node]
        row_meta = parse_metadata_df("row", row_dset, convert_neg_666)

        # validate optional input ids & get indexes to subset by
        (sorted_ridx, sorted_cidx) = check_and_order_id_inputs(rid, ridx, cid, cidx, row_meta, None)

        gctx_file.close()

        # subset if specified, then return
        row_meta = row_meta.iloc[sorted_ridx]
        return row_meta
    elif col_meta_only:
        # read in col metadata
        col_dset = gctx_file[col_meta_group_node]
        col_meta = parse_metadata_df("col", col_dset, convert_neg_666)

        # validate optional input ids & get indexes to subset by
        (sorted_ridx, sorted_cidx) = check_and_order_id_inputs(rid, ridx, cid, cidx, None, col_meta)

        gctx_file.close()

        # subset if specified, then return
        col_meta = col_meta.iloc[sorted_cidx]
        return col_meta
    else:
        # read in row metadata
        row_dset = gctx_file[row_meta_group_node]
        row_meta = parse_metadata_df("row", row_dset, convert_neg_666)

        # read in col metadata
        col_dset = gctx_file[col_meta_group_node]
        col_meta = parse_metadata_df("col", col_dset, convert_neg_666)

        # validate optional input ids & get indexes to subset by
        (sorted_ridx, sorted_cidx) = check_and_order_id_inputs(rid, ridx, cid, cidx, row_meta, col_meta)

        data_dset = gctx_file[data_node]
        data_df = parse_data_df(data_dset, sorted_ridx, sorted_cidx, row_meta, col_meta)

        # (if subsetting) subset metadata
        row_meta = row_meta.iloc[sorted_ridx]
        col_meta = col_meta.iloc[sorted_cidx]

        # get version
        my_version = gctx_file.attrs[version_node]
        if type(my_version) == np.ndarray:
            my_version = my_version[0]

        gctx_file.close()

        ### Original loading function: places dataframe into a separate, GCToo,
        ### object, which Thomas Stoeger would usually avoid upon calling cmapPy:
        ### Hence, this Python3 loader of LINCS data will differ from default one
        ### by avoiding the generation of GCToo objects, which may or may not
        ### be incompatible with Python3 (not tested)

        # make GCToo instance
        # my_gctoo = GCToo.GCToo(data_df=data_df, row_metadata_df=row_meta, col_metadata_df=col_meta,
        #                        src=full_path, version=my_version, make_multiindex=make_multiindex)
        # return my_gctoo

        return data_df

def check_and_order_id_inputs(rid, ridx, cid, cidx, row_meta_df, col_meta_df):
    """
    Makes sure that (if entered) id inputs entered are of one type (string id or index)
    Input:
        - rid (list or None): if not None, a list of rids
        - ridx (list or None): if not None, a list of indexes
        - cid (list or None): if not None, a list of cids
        - cidx (list or None): if not None, a list of indexes
    Output:
        - a tuple of the ordered ridx and cidx
    """
    (row_type, row_ids) = check_id_idx_exclusivity(rid, ridx)
    (col_type, col_ids) = check_id_idx_exclusivity(cid, cidx)

    row_ids = check_and_convert_ids(row_type, row_ids, row_meta_df)
    ordered_ridx = get_ordered_idx(row_type, row_ids, row_meta_df)

    col_ids = check_and_convert_ids(col_type, col_ids, col_meta_df)
    ordered_cidx = get_ordered_idx(col_type, col_ids, col_meta_df)
    return (ordered_ridx, ordered_cidx)

def check_id_idx_exclusivity(id, idx):
    """
    Makes sure user didn't provide both ids and idx values to subset by.

    Input:
        - id (list or None): if not None, a list of string id names
        - idx (list or None): if not None, a list of integer id indexes

    Output:
        - a tuple: first element is subset type, second is subset content
    """
    if (id is not None and idx is not None):
        msg = ("'id' and 'idx' fields can't both not be None," +
               " please specify subset in only one of these fields")
        logger.error(msg)
        raise Exception("parse_gctx.check_id_idx_exclusivity: " + msg)
    elif id is not None:
        return ("id", id)
    elif idx is not None:
        return ("idx", idx)
    else:
        return (None, [])

def check_and_convert_ids(id_type, id_list, meta_df):
    if meta_df is not None:
        if id_type == "id":
            id_list = convert_ids_to_meta_type(id_list, meta_df)
            check_id_validity(id_list, meta_df)
        else:
            check_idx_validity(id_list, meta_df)
        return id_list
    else:
        return None

def check_id_validity(id_list, meta_df):
    id_set = set(id_list)
    meta_set = set(meta_df.index)
    mismatch_ids = id_set - meta_set
    if len(mismatch_ids) > 0:
        msg = "some of the ids being used to subset the data are not present in the metadata for the file being parsed - mismatch_ids:  {}".format(
            mismatch_ids)
        logger.error(msg)
        raise Exception("parse_gctx check_id_validity " + msg)

def check_idx_validity(id_list, meta_df):
    N = meta_df.shape[0]
    out_of_range_ids = [my_id for my_id in id_list if my_id < 0 or my_id >= N]
    if len(out_of_range_ids):
        msg = "some of indexes being used to subset the data are not valid max N:  {}  out_of_range_ids:  {}".format(N,
                                                                                out_of_range_ids)
        logger.error(msg)
        raise Exception("parse_gctx check_idx_validity " + msg)

def convert_ids_to_meta_type(id_list, meta_df):
    try:
        return pd.Series(id_list).astype(meta_df.index.dtype).values
    except ValueError as ve:
        id_list_types = set([type(x) for x in id_list])
        msg = "The type of the id_list (rid or cid) being used to subset the data is not compatible with the metadata id's in the file.  Types found - meta_df.index.dtype:  {}  id_list_types:  {}".format(
            meta_df.index.dtype, id_list_types)
        logger.error(msg)
        raise Exception("parse_gctx check_if_ids_in_meta " + msg + "  ValueError ve:  {}".format(ve))

def get_ordered_idx(id_type, id_list, meta_df):
    """
    Gets index values corresponding to ids to subset and orders them.
    Input:
        - id_type (str): either "id", "idx" or None
        - id_list (list): either a list of indexes or id names
    Output:
        - a sorted list of indexes to subset a dimension by
    """
    if meta_df is not None:
        if id_type is None:
            id_list = range(0, len(list(meta_df.index)))
        elif id_type == "id":
            lookup = {x: i for (i,x) in enumerate(meta_df.index)}
            id_list = [lookup[str(i)] for i in id_list]
        return sorted(id_list)
    else:
        return None

def parse_metadata_df(dim, meta_group, convert_neg_666):
    """
    Reads in all metadata from .gctx file to pandas DataFrame
    with proper GCToo specifications.
    Input:
        - dim (str): Dimension of metadata; either "row" or "column"
        - meta_group (HDF5 group): Group from which to read metadata values
        - convert_neg_666 (bool): whether to convert "-666" values to np.nan or not
    Output:
        - meta_df (pandas DataFrame): data frame corresponding to metadata fields
            of dimension specified.
    """
    # read values from hdf5 & make a DataFrame
    header_values = {}
    array_index = 0
    for k in meta_group.keys():
        curr_dset = meta_group[k]
        temp_array = np.empty(curr_dset.shape, dtype=curr_dset.dtype)
        curr_dset.read_direct(temp_array)
        temp_array = np.core.defchararray.decode(temp_array, 'utf8')  # <- introduced for Python3 compatibility
        header_values[str(k)] = temp_array
        array_index = array_index + 1

    # need to temporarily make dtype of all values str so that to_numeric
    # works consistently with gct vs gctx parser.
    meta_df = pd.DataFrame.from_dict(header_values).astype(str)

    # save the ids for later use in the index; we do not want to convert them to
    # numeric
    ids = meta_df["id"].copy()
    del meta_df["id"]

    # Convert metadata to numeric if possible, after converting everything to string first
    # Note: This conversion first to string is to ensure consistent behavior between
    #    the gctx and gct parser (which by default reads the entire text file into a string)
    meta_df = meta_df.apply(lambda x: pd.to_numeric(x, errors="ignore"))

    meta_df.set_index(pd.Index(ids, dtype=str), inplace=True)

    # Replace -666 and -666.0 with NaN; also replace "-666" if convert_neg_666 is True
    meta_df = replace_666(meta_df, convert_neg_666)

    # set index and columns appropriately
    set_metadata_index_and_column_names(dim, meta_df)
    return meta_df

def replace_666(meta_df, convert_neg_666):
    """ Replace -666, -666.0, and optionally "-666".
    Args:
        meta_df (pandas df):
        convert_neg_666 (bool):
    Returns:
        out_df (pandas df): updated meta_df
    """
    if convert_neg_666:
        out_df = meta_df.replace([-666, "-666", -666.0], np.nan)
    else:
        out_df = meta_df.replace([-666, -666.0], "-666")
    return out_df

def set_metadata_index_and_column_names(dim, meta_df):
    """
    Sets index and column names to GCTX convention.
    Input:
        - dim (str): Dimension of metadata to read. Must be either "row" or "col"
        - meta_df (pandas.DataFrame): data frame corresponding to metadata fields
            of dimension specified.
    Output:
        None
    """
    if dim == "row":
        meta_df.index.name = "rid"
        meta_df.columns.name = "rhd"
    elif dim == "col":
        meta_df.index.name = "cid"
        meta_df.columns.name = "chd"

def parse_data_df(data_dset, ridx, cidx, row_meta, col_meta):
    """
    Parses in data_df from hdf5, subsetting if specified.

    Input:
        -data_dset (h5py dset): HDF5 dataset from which to read data_df
        -ridx (list): list of indexes to subset from data_df
            (may be all of them if no subsetting)
        -cidx (list): list of indexes to subset from data_df
            (may be all of them if no subsetting)
        -row_meta (pandas DataFrame): the parsed in row metadata
        -col_meta (pandas DataFrame): the parsed in col metadata
    """
    if len(ridx) == len(row_meta.index) and len(cidx) == len(col_meta.index):  # no subset
        data_array = np.empty(data_dset.shape, dtype=np.float32)
        data_dset.read_direct(data_array)
        data_array = data_array.transpose()
    elif len(ridx) <= len(cidx):
        first_subset = data_dset[:, ridx].astype(np.float32)
        data_array = first_subset[cidx, :].transpose()
    elif len(cidx) < len(ridx):
        first_subset = data_dset[cidx, :].astype(np.float32)
        data_array = first_subset[:, ridx].transpose()
    # make DataFrame instance
    data_df = pd.DataFrame(data_array, index=row_meta.index[ridx], columns=col_meta.index[cidx])
    return data_df

def get_column_metadata(gctx_file_path, convert_neg_666=True):
    """
    Opens .gctx file and returns only column metadata

    Input:
        Mandatory:
        - gctx_file_path (str): full path to gctx file you want to parse.

        Optional:
        - convert_neg_666 (bool): whether to convert -666 values to num

    Output:
        - col_meta (pandas DataFrame): a DataFrame of all column metadata values.
    """
    full_path = os.path.expanduser(gctx_file_path)
    # open file
    gctx_file = h5py.File(full_path, "r")
    col_dset = gctx_file[col_meta_group_node]
    col_meta = parse_metadata_df("col", col_dset, convert_neg_666)
    gctx_file.close()
    return col_meta

def get_row_metadata(gctx_file_path, convert_neg_666=True):
    """
    Opens .gctx file and returns only row metadata

    Input:
        Mandatory:
        - gctx_file_path (str): full path to gctx file you want to parse.

        Optional:
        - convert_neg_666 (bool): whether to convert -666 values to num

    Output:
        - row_meta (pandas DataFrame): a DataFrame of all row metadata values.
    """
    full_path = os.path.expanduser(gctx_file_path)
    # open file
    gctx_file = h5py.File(full_path, "r")
    row_dset = gctx_file[row_meta_group_node]
    row_meta = parse_metadata_df("row", row_dset, convert_neg_666)
    gctx_file.close()
    return row_meta


import win32con
import win32clipboard
import pywintypes
import logging

from . import _ContextUtils as ContextUtils
from . import ClipboardArchive
from . import ClipboardBackend

# Internal aliases for external names
clipboardPreserving = ClipboardArchive.clipboardPreserving

# ----------------------------------------------------------------------------
# Constants
# ----------------------------------------------------------------------------

# Max amount of time to wait for a file copy to occur, in ms.
FILE_COPY_WAIT_TIME = 2000

# ----------------------------------------------------------------------------
# Classes
# ----------------------------------------------------------------------------

class AbstractFileSelectionContext:
    """
    The abstract base class that defines the interface to
    FileSelectionContext objects.
    """

    def getSelectedFiles( self ):
        """
        Returns a list of the names of the files that are selected.
        Each element of the list is an absolute path.  If no files are
        selected, it returns None (not an empty list).
        """

        raise NotImplementedError()

class NullFileSelectionContext( AbstractFileSelectionContext ):
    """
    A FileSelectionContext that always reports that no files are
    selected.  This should be used when we know that the current
    application can't possibly have any notion of 'file selection'.
    """

    def getSelectedFiles( self ):
        """
        Returns a list of the names of the files that are selected.
        Each element of the list is an absolute path.  If no files are
        selected, it returns None (not an empty list).
        """

        return None

class DefaultFileSelectionContext( AbstractFileSelectionContext ):
    """
    The default subclass to use when in most applications.  It simply
    simulates performing a copy operation, then checks to see if the
    clipboard contains data in the CF_HDROP format.
    """

    @clipboardPreserving
    def getSelectedFiles( self ):
        """
        Returns a list of the names of the files that are selected.
        Each element of the list is an absolute path.  If no files are
        selected, it returns None (not an empty list).
        """

        ClipboardBackend.prepareForClipboardToChange()
        ContextUtils.typeCommandKey( "C" )
        success = ClipboardBackend.waitForClipboardToChange(
            FILE_COPY_WAIT_TIME
            )

        if not success:
            return None

        return self.__getHdropFiles()

    @ContextUtils.clipboardDependent
    def __getHdropFiles( self ):
        """
        Private method for fetching the clipboard format CF_HDROP,
        which represents file targets.
        """

        formatAvailable = win32clipboard.IsClipboardFormatAvailable(
            win32con.CF_HDROP
            )
        if formatAvailable:
            try:
                value = win32clipboard.GetClipboardData(
                    win32con.CF_HDROP
                    )
            except pywintypes.error as e:
                logging.warn( "Error getting CF_HDROP from clipboard: %s" \
                                 % ( str(e) ) )
                value = None
        else:
            logging.info( "Clipboard type CF_HDROP not in clipboard." )
            value = None
            # LONGTERM TODO: See whether there are other clipboard
            # formats that could give us the information we need
            # when CF_HDROP is not available.

        return value

# ----------------------------------------------------------------------------
# Public getter
# ----------------------------------------------------------------------------

def get():
    """
    Create and return an instance of the FileSelectionContext
    subclass which is appropriate to the currently active application.
    """

    windowClass = ContextUtils.getForegroundClassNameUnicode()

    if windowClass == "ConsoleWindowClass":
        fsContext = NullFileSelectionContext()
    elif windowClass == "Emacs":
        fsContext = NullFileSelectionContext()
    else:
        fsContext = DefaultFileSelectionContext()

    return fsContext


# Create setup.py
from setuptools import setup

with open('requirements.txt') as f:
    required = f.read().splitlines()

setup(
    name='lbic',
    version='0.0.1',
    packages=['lbic', 'lbic.utils'],
    package_dir={'': 'src'},
    url='https://github.com/Artucuno/lbic',
    license='MIT',
    author='Artucuno',
    description='A load balanced interactions.py client',
    python_requires='>=3.8',
    install_requires=required,

)


import numpy as np
import time
import torch

def move_data_to_device(x, device):
    if 'float' in str(x.dtype):
        x = torch.Tensor(x)
    elif 'int' in str(x.dtype):
        x = torch.LongTensor(x)
    else:
        return x

    return x.to(device)

def do_mixup(x, mixup_lambda):
    """Mixup x of even indexes (0, 2, 4, ...) with x of odd indexes
    (1, 3, 5, ...).

    Args:
      x: (batch_size * 2, ...)
      mixup_lambda: (batch_size * 2,)

    Returns:
      out: (batch_size, ...)
    """
    out = (x[0 :: 2].transpose(0, -1) * mixup_lambda[0 :: 2] + \
        x[1 :: 2].transpose(0, -1) * mixup_lambda[1 :: 2]).transpose(0, -1)
    return out

def append_to_dict(dict, key, value):
    if key in dict.keys():
        dict[key].append(value)
    else:
        dict[key] = [value]

def forward(model, generator, return_input=False,
    return_target=False):
    """Forward data to a model.

    Args:
      model: object
      generator: object
      return_input: bool
      return_target: bool

    Returns:
      audio_name: (audios_num,)
      clipwise_output: (audios_num, classes_num)
      (ifexist) segmentwise_output: (audios_num, segments_num, classes_num)
      (ifexist) framewise_output: (audios_num, frames_num, classes_num)
      (optional) return_input: (audios_num, segment_samples)
      (optional) return_target: (audios_num, classes_num)
    """
    output_dict = {}
    device = next(model.parameters()).device
    time1 = time.time()

    # Forward data to a model in mini-batches
    for n, batch_data_dict in enumerate(generator):
        print(n)
        batch_waveform = move_data_to_device(batch_data_dict['waveform'], device)

        with torch.no_grad():
            model.eval()
            batch_output = model(batch_waveform)

        append_to_dict(output_dict, 'audio_name', batch_data_dict['audio_name'])

        append_to_dict(output_dict, 'clipwise_output',
            batch_output['clipwise_output'].data.cpu().numpy())

        if 'segmentwise_output' in batch_output.keys():
            append_to_dict(output_dict, 'segmentwise_output',
                batch_output['segmentwise_output'].data.cpu().numpy())

        if 'framewise_output' in batch_output.keys():
            append_to_dict(output_dict, 'framewise_output',
                batch_output['framewise_output'].data.cpu().numpy())

        if return_input:
            append_to_dict(output_dict, 'waveform', batch_data_dict['waveform'])

        if return_target:
            if 'target' in batch_data_dict.keys():
                append_to_dict(output_dict, 'target', batch_data_dict['target'])

        if n % 10 == 0:
            print(' --- Inference time: {:.3f} s / 10 iterations ---'.format(
                time.time() - time1))
            time1 = time.time()

    for key in output_dict.keys():
        output_dict[key] = np.concatenate(output_dict[key], axis=0)

    return output_dict

def count_parameters(model):
    return sum(p.numel() for p in model.parameters() if p.requires_grad)


# UniFuncNet modules
from unifuncnet.Utils.util import (l_rn_ids_to_str,
                                   unite_possible_ids,
                                   list_has_common_items,
                                   score_match_possible_ids)
from unifuncnet.biological_components.utils.base_component import *

class Reaction(BaseComponent):
    def __init__(self, init_dictionary):
        BaseComponent.__init__(self, init_dictionary)

    def __str__(self):
        if self.get_reaction():
            res = 'Reaction\n'
            return res + self.get_reaction()
        return ''

    def get_reaction_internal_id(self):
        if not self.reaction_with_instances: return None
        reaction_dict = self.get_detail('reaction_with_instances')
        res = []
        stoichiometry = []
        for side in reaction_dict:
            for stoi, compound in reaction_dict[side]:
                if compound:
                    compound_id = str(compound.internal_id)
                else:
                    compound_id = str(compound)
                res.append([stoi, compound_id])
                stoichiometry.append(str(stoi))
        try:
            stoichiometry = ','.join(stoichiometry)
            return l_rn_ids_to_str(self.get_reaction(), res, without_stoichiometry=True), stoichiometry
        except:
            return None, None

    ###MATCHING AND UNITING###

    def is_match_reaction_instances(self, reaction_instance_2):
        rn_inst_1 = []
        rn_inst_1_dict = self.get_detail('reaction_with_instances')
        for rn_key in rn_inst_1_dict:
            rn_inst_1.extend(rn_inst_1_dict[rn_key])

        rn_inst_2 = []
        rn_inst_2_dict = reaction_instance_2.get_detail('reaction_with_instances')
        for rn_key in rn_inst_2_dict:
            rn_inst_2.extend(rn_inst_2_dict[rn_key])

        if not rn_inst_1 or not rn_inst_2:
            return False
        if len(rn_inst_1) != len(rn_inst_2):
            return False
        rn_inst_1_list = []
        rn_inst_2_list = []
        for i in range(len(rn_inst_1)):
            rn_inst_1_list.append(rn_inst_1[i][1])
            rn_inst_2_list.append(rn_inst_2[i][1])
        test = 0
        for r1 in rn_inst_1_list:
            # reaction may have Nones, we dont want these to be taken into account
            if not r1:
                return False
            for r2 in rn_inst_2_list:
                if not r2:
                    return False
                if r1.is_match_instances(r2):
                    test += 1
        if test == len(rn_inst_1):
            return True
        return False

    def score_match_instances(self, instance_2):
        c = 0
        # reaction with instances and reaction str hold more weight than IDs
        if self.is_match_reaction_instances(instance_2):
            c += 2.25
        if list_has_common_items(self.get_strs_reaction(), instance_2.get_strs_reaction()):
            c += 2
        for unique_detail in self.get_unique_details(remove_from_list=['reaction_with_instances', 'reaction_str']):
            c += score_match_possible_ids(self.get_detail(unique_detail, all_possible=True),
                                          instance_2.get_detail(unique_detail, all_possible=True))
        return c

    def unite_instances_bio_specific(self, instance_2):
        for detail_type in self.get_details_list(extra_instances=instance_2):
            if detail_type == 'reaction_str':
                self.set_detail(detail_type, instance_2.get_detail(detail_type, all_possible=True))
            elif detail_type == 'pathways':
                self.set_detail(detail_type, instance_2.get_detail(detail_type, all_possible=True))
            elif detail_type == 'reaction_with_instances':
                self.set_detail(detail_type, instance_2.get_detail(detail_type, all_possible=True))
            elif detail_type.endswith('_instances'):
                self.replace_instances(detail_type, instance_2)
            elif detail_type == 'rn_with_ids':
                for i2_rn_with_ids in instance_2.get_rn_with_ids():   self.set_detail(detail_type, i2_rn_with_ids)
            else:
                unite_possible_ids(self, instance_2, detail_type)

def test_instance_creator(test_string='test'):
    from unifuncnet.biological_components.compound import Compound
    details = ['reaction_str', 'kegg', 'rhea']
    d = {}
    p = Reaction(d)
    cpd1 = Compound()
    cpd2 = Compound()
    rn_instances = [[1, cpd1], [1, cpd2]]
    p.set_detail('reaction_with_instances')

    for d in details:
        if d == 'reaction_str':
            p.set_detail(d, test_string + ' = ' + test_string)
        else:
            p.set_detail(d, test_string)
    p.get_all_info()
    return p

if __name__ == '__main__':
    test_instance_creator()


from django.contrib.auth.models import ContentType
from .models import ReadNum

def read_statistics_once_read(request,obj):
    ct = ContentType.objects.get_for_model(obj)
    key = "%s_%s_read" %  (ct.model,obj.pk)
    if not request.COOKIES.get(key):  # 检查浏览器中是否有一个cookie，有则代表该浏览器访问过页面，不再计数，没有则浏览器未访问，计数加1，并在后面的代码中向他发送一个cookie

        if ReadNum.objects.filter(content_type=ct ,object_id=obj.pk):  # 判断该类型下是否存在记录.count()
            readnum = ReadNum.objects.get(content_type=ct ,object_id=obj.pk)  # 存在记录，获得该记录
        else:
            readnum = ReadNum(content_type=ct ,object_id=obj.pk)  # 不存在记录,则创建一个记录并获得它
        readnum.read_num += 1
        readnum.save()
    return key