from PyQt5 import QtWidgets
from tkinter import Tk, Label
import time

#возвращает массив из 8 элементов, где каждый элемент - это 32 бита
def genKeys_GOST(key256b:str):
    keys1 = key256b.encode()
    keys = []
    for i in range(8):
        keys.append(keys1[:4])
        keys1 = keys1[4:]
    keysBin = []
    for i in range(len(keys)):
        binStr = ''
        for j in keys[i]:
            binStr += bin(j)[2:].zfill(8)
        keysBin.append(binStr)
    return keysBin

def before_coding(text, flag: int):
    file = 0
    if type(text) == str:
        if flag == 1:
            textToInt = text.encode()
        else:
            textToInt = b''
            for i in text:
                textToInt += bytes([ord(i)])
    else:
        textToInt = text
        file = 1
        print('OK')

    blocks = []
    while len(textToInt) > 0:
        blocks.append(textToInt[:8])
        textToInt = textToInt[8:]

    count = 0
    if len(blocks[len(blocks) - 1]) != 8:
        while len(blocks[len(blocks) - 1]) != 8:
            count += 1
            blocks[len(blocks) - 1] += bytes([0])
        blocks[len(blocks) - 1] = blocks[len(blocks) - 1][:-1] + bytes([count])

    blocksBin = []
    for i in range(len(blocks)):
        binStr = ''
        for j in blocks[i]:
            binStr += bin(j)[2:].zfill(8)
        blocksBin.append(binStr)
    return blocksBin, file

def after_coding(file, block64Int, flag):
    if file == 0:
        if flag != 1:
            numb = block64Int[len(block64Int) - 1]
            blocksText1 = block64Int
            j = 2
            for i in range(numb-1):
                if blocksText1[-j] == 0:
                    blocksText1 = blocksText1[:-1]
                    j = 1
                else:
                    break
            if len(blocksText1) < len(block64Int):
                blocksText1 = blocksText1[:-1]
            blocksText = ''
            for i in blocksText1:
                blocksText += chr(i)
        else:
            blocksText = ''
            for i in block64Int:
                blocksText += chr(i)
    else:
        if flag != 1:
            numb = block64Int[len(block64Int) - 1]
            blocksText = block64Int
            j = 2
            for i in range(numb-1):
                if blocksText[-j] == 0:
                    blocksText = blocksText[:-1]
                    j = 1
                else:
                    break
            if len(blocksText) < len(block64Int):
                blocksText = blocksText[:-1]
        else:
            blocksText = block64Int
    return blocksText

def xor(a: str, b: str):
    if len(a) > len(b):
        a = a.zfill(len(b))
    elif len(b) > len(a):
        b = b.zfill(len(a))
    res = bin(int(a, 2) ^ int(b, 2))[2:].zfill(len(a))
    return res

def sdvig(str: str, n: int):
    arrTxt = str[n:] + str[:n]
    return arrTxt

def substitution(N1:str):
    __Sbox = [
        [9, 6, 3, 2, 8, 11, 1, 7, 10, 4, 14, 15, 12, 0, 13, 5],
        [3, 7, 14, 9, 8, 10, 15, 0, 5, 2, 6, 12, 11, 4, 13, 1],
        [14, 4, 6, 2, 11, 3, 13, 8, 12, 15, 5, 10, 0, 7, 1, 9],
        [14, 7, 10, 12, 13, 1, 3, 9, 0, 2, 11, 4, 15, 8, 5, 6],
        [11, 5, 1, 9, 8, 13, 15, 0, 14, 4, 2, 3, 12, 7, 10, 6],
        [3, 10, 13, 12, 1, 2, 0, 11, 7, 5, 9, 4, 8, 15, 14, 6],
        [1, 13, 2, 9, 7, 10, 6, 0, 8, 12, 4, 5, 15, 3, 11, 14],
        [11, 10, 15, 5, 0, 12, 14, 8, 6, 2, 3, 9, 1, 7, 13, 4]
    ]
    # 8 блоков по 4 бита
    blocks4b = []
    for i in range(8):
        blocks4b.append(N1[:4])
        N1 = N1[4:].zfill(4)
    blocksAfterSbox = ''
    for i in range(8):
        blocksAfterSbox+=bin(__Sbox[i][int(blocks4b[i], 2)])[2:].zfill(4)
    return sdvig(blocksAfterSbox, 11)

def round_feistel_scheme(L0: str, R0: str, key: str):
    # RES = (N1 + Ki) mod 2 ^ 32
    RES = bin((int(L0, 2) | int(key, 2)) % 2**32)[2:].zfill(32)

    # RES = RES -> Sbox, << 11
    RES = substitution(RES)
    L0, R0 = xor(RES, R0), L0
    return L0, R0

def feistel_scheme(block:str, keys:list, flag:int):
    L0 = block[:32]
    R0 = block[32:]
    if flag == 1:
        # K0, K1, K2, K3, K4, K5, K6, K7, K0, K1, K2, K3, K4, K5, K6, K7, K0, K1, K2, K3, K4, K5, K6, K7
        for i in range(3):
            for j in range(len(keys)):
                L0, R0 = round_feistel_scheme(L0, R0, keys[j])
        # K7, K6, K5, K4, K3, K2, K1, K0
        for i in range(len(keys)):
            L0, R0 = round_feistel_scheme(L0, R0,  keys[len(keys) - 1 - i])
        L0, R0 = R0, L0
    else:
        # K0, K1, K2, K3, K4, K5, K6, K7
        for i in range(len(keys)):
            L0, R0 = round_feistel_scheme(L0, R0, keys[i])
        # K7, K6, K5, K4, K3, K2, K1, K0, K7, K6, K5, K4, K3, K2, K1, K0, K7, K6, K5, K4, K3, K2, K1, K0
        for i in range(3):
            for j in range(len(keys)):
                L0, R0 = round_feistel_scheme(L0, R0, keys[len(keys) - 1 - j])
        L0, R0 = R0, L0
    return L0 + R0

def GOST_zamena(keys1, text, flag):
    start = time.time()
    if not keys1 or keys1 == '':
        keys = genKeys_GOST('this_is_a_pasw_for_GOST_28147_89')
    else:
        if len(keys1) != 256:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setWindowTitle("Ошибка")
            msgBox.setText("Ошибка в ключе!")
            msgBox.exec_()
            return ("")
        for i in keys1:
            if (i != '1' and i != 1 and i != '0' and i != 0) == True:
                msgBox = QtWidgets.QMessageBox()
                msgBox.setWindowTitle("Ошибка")
                msgBox.setText("Ошибка в ключе!")
                msgBox.exec_()
                return ("")
        keys = [0, 0, 0, 0, 0, 0, 0, 0]
        for i in range(8):
            keys[i] = keys1[:32]
            keys1 = keys1[32:]

    if not text:
        msgBox = QtWidgets.QMessageBox()
        msgBox.setWindowTitle("Ошибка")
        msgBox.setText("Введите текст!")
        msgBox.exec_()
        return ("")

    blocksBin, file = before_coding(text, flag)

    block64Int = b''
    for i in range(len(blocksBin)):
        block64b = feistel_scheme(blocksBin[i], keys, flag)
        for j in range(8):
            block64Int+=bytes([int(block64b[:8], 2)])
            block64b = block64b[8:]

    blocksText = after_coding(file, block64Int, flag)
    return blocksText

def GOST_gamm(keys1, text, flag, vector_init):
    start = time.time()
    if not keys1 or keys1 == '':
        keys = genKeys_GOST('this_is_a_pasw_for_GOST_28147_89')
    else:
        if len(keys1) != 256:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setWindowTitle("Ошибка")
            msgBox.setText("Ошибка в ключе!")
            msgBox.exec_()
            return ("")
        for i in keys1:
            if (i != '1' and i != 1 and i != '0' and i != 0) == True:
                msgBox = QtWidgets.QMessageBox()
                msgBox.setWindowTitle("Ошибка")
                msgBox.setText("Ошибка в ключе!")
                msgBox.exec_()
                return ("")
        keys = [0, 0, 0, 0, 0, 0, 0, 0]
        for i in range(8):
            keys[i] = keys1[:32]
            keys1 = keys1[32:]
    if not vector_init or vector_init == '':
        vector_init = '1110011110010101110010111001010010000111001010011100101001001011'
    else:
        if len(vector_init) != 64:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setWindowTitle("Ошибка")
            msgBox.setText("Ошибка в векторе инициализации!")
            msgBox.exec_()
            return ("")
        for i in vector_init:
            if (i != '1' and i != 1 and i != '0' and i != 0) == True:
                msgBox = QtWidgets.QMessageBox()
                msgBox.setWindowTitle("Ошибка")
                msgBox.setText("Ошибка в векторе инициализации!!")
                msgBox.exec_()
                return ("")
    if not text:
        msgBox = QtWidgets.QMessageBox()
        msgBox.setWindowTitle("Ошибка")
        msgBox.setText("Введите текст!")
        msgBox.exec_()
        return ("")

    blocksBin, file = before_coding(text, flag)

    percent = 100 / len(blocksBin)
    progress = 0
    normal = 0
    root = Tk()

    label = Label(text='Progressbar')
    x = (root.winfo_screenwidth() - root.winfo_reqwidth()) / 2
    y = (root.winfo_screenheight() - root.winfo_reqheight()) / 2
    root.wm_geometry("+%d+%d" % (x, y))
    label.pack()

    if flag == 1:
        N = vector_init
        block64Int = b''
        for i in range(len(blocksBin)):
            gamma = feistel_scheme(N, keys, 1)
            try:
                progress += percent
                label.config(text='\rОбработка завершена на %3d%%' % progress)
                root.update()
                # print('\rОбработка завершена на %3d%%' % progress, end = '', flush = True)
            except Exception:
                normal = 1
                pass
            block64b = xor(gamma, blocksBin[i])
            N = block64b
            for j in range(8):
                block64Int += bytes([int(block64b[:8], 2)])
                block64b = block64b[8:]
    else:
        N = vector_init
        block64Int = b''
        for i in range(len(blocksBin)):
            gamma = feistel_scheme(N, keys, 1)
            try:
                progress += percent
                label.config(text='\rОбработка завершена на %3d%%' % progress)
                root.update()
                # print('\rОбработка завершена на %3d%%' % progress, end = '', flush = True)
                time.sleep(0.01)
            except Exception:
                normal = 1
                pass
            block64b = xor(gamma, blocksBin[i])
            for j in range(8):
                block64Int += bytes([int(block64b[:8], 2)])
                block64b = block64b[8:]
            N = blocksBin[i]

    blocksText = after_coding(file, block64Int, flag)
    if normal == 0:
        root.destroy()
    print('Время выполнения: ', (time.time() - start) / 60)
    return blocksText


#!/usr/bin/env python2
import re
from sys import stdin, stdout
import json

def reducer():
    """
    Stripes reducer function

    Reads pairs of words separated by a space and a count and calculates P
    """
    # Empty dict for our output
    n = dict()
    sigma_n = dict()

    # Precompiled regex to match our input
    parse = re.compile('(\w+):(.*)')

    # Read STDIN and get counts
    line = stdin.readline()
    while line:
        # Try and match our line (skip if failed)
        m = parse.match(line)
        if not m:
            continue

        word_1 = m.group(1)
        words = json.loads(m.group(2))

        if word_1 not in n:
            n[word_1] = words
            for i in words.values():
                if word_1 not in sigma_n:
                    sigma_n[word_1] = 0
                sigma_n[word_1] += i
        else:
            for word_2, i in words.items():
                sigma_n[word_1] += i
                if word_2 in n[word_1]:
                    n[word_1][word_2] += i
                else:
                    n[word_1][word_2] = i

        line = stdin.readline()

    # Calculate P
    for word_1 in sorted(n.keys()):
        for word_2, n_word in sorted(n[word_1].items(), key=lambda x: (x[1], x[0]), reverse=True):
            p = n[word_1][word_2] / float(sigma_n[word_1])
            stdout.write("%s %s: %f\n" % (word_1, word_2, p))

if __name__ == '__main__':
    reducer()


#!/usr/bin/env python3

import threading

from flask import Flask, jsonify, request
from flask_api import status

from game_state import UserDoesntExistError, UserAlreadyExistsError, InvalidUserActionError
from session import InvalidSessionError, InvalidCredentialsError

app = Flask(__name__)

# TODO session in cookies so GET can be used

# TODO dependency injection
session_config = {
    'expiry_timeout_s': 100,
    'expiry_sliding_window_s': 60
}
from stateful_ticket_session import StatefulTicketSessionManager as SessionManager
session_manager = SessionManager(session_config)
game_config = {'alert_chance_of_multiply':0.2}
from stateful_game_state import StatefulGameState as GameState
game_state = GameState(game_config)

def create_json_error_response(msg, code):
    """
    Returns flask error response body and code pair

    :param string msg: error message

    :param int code: HTTP Status Code

    :return (json, int): json message and status code
    """
    return jsonify({'msg': msg}), code

def parse_json(req):
    return req.get_json(force=True)

def check_expired_sessions():
    expired_sessions = session_manager.check_expired_sessions()
    for id in expired_sessions.keys():
        game_state.remove_user(id)

@app.route('/login', methods=['POST'])
def login():
    check_expired_sessions()
    result = None
    try:
        credentials = parse_json(request)
        result = session_manager.new_session(credentials)
        game_state.add_user(result['id'])
    except InvalidCredentialsError as exc:
        return create_json_error_response('failed to login', status.HTTP_401_UNAUTHORIZED)
    return jsonify(result)

@app.route('/session', methods=['POST'])
def session():
    check_expired_sessions()
    result = None
    try:
        session_details = parse_json(request)
        result = session_manager.extend_session(session_details)
    except InvalidSessionError as exc:
        return create_json_error_response('failed to extend session', status.HTTP_401_UNAUTHORIZED)
    return jsonify(result)

@app.route('/signout', methods=['POST'])
def signout():
    check_expired_sessions()
    try:
        session_details = parse_json(request)
        session_manager.destroy_session(session_details)
        game_state.remove_user(session_details['id'])
    except InvalidSessionError as exc:
        return create_json_error_response('failed to destroy session', status.HTTP_401_UNAUTHORIZED)
    except UserDoesntExistError:
        return create_json_error_response('unknown error', status.HTTP_500_INTERNAL_SERVER_ERROR)
    return '', status.HTTP_200_OK

@app.route('/action', methods=['POST'])
def action():
    check_expired_sessions()
    result = None
    try:
        req = parse_json(request)
        session_manager.authenticate_session(req['session'])
        req['session'] = session_manager.extend_session(req['session'])
        result = game_state.user_action(req['session']['id'], req['user_action'])
    except InvalidSessionError:
        return create_json_error_response('cant take user action', status.HTTP_401_UNAUTHORIZED)
    except InvalidUserActionError as error:
        return create_json_error_response(
            'invalid user action ' + error.msg,
            status.HTTP_400_BAD_REQUEST
        )
    except KeyError:
        return create_json_error_response('invalid request', status.HTTP_400_BAD_REQUEST)
    except UserDoesntExistError:
        return create_json_error_response('unknown error', status.HTTP_500_INTERNAL_SERVER_ERROR)
    return jsonify(result)

if __name__ == "__main__":
    app.run()


import pytest
from azure.identity import ManagedIdentityCredential

from storage.adls import get_adls_client

@pytest.mark.parametrize(
    "name,key,container",
    [
        ("pety", "the_happy", "container"),
        ("pety", ManagedIdentityCredential(), "container"),
    ],
)
def test_get_adls_client_correctly_formats_account_string(mocker, name, key, container):
    account_url = "https://pety.dfs.core.windows.net/"

    datalake_sc_mock = mocker.patch("storage.adls.DataLakeServiceClient")
    get_adls_client(name, key, container)

    datalake_sc_mock.assert_called_once_with(account_url=account_url, credential=key)
    datalake_sc_mock().get_file_system_client.assert_called_once_with(
        file_system=container
    )


"""Tools to store information on the Variables and Dimensions in the Database"""
import netCDF4
import numpy as np

from ..utils.osutils import exists_and_isfile
#
from colt.generator import Generator

class _DBVariable(object):
    """Store info for Database and easy comparison"""

    __slots__ = ('type', 'dimensions')

    def __init__(self, typ, dim):
        self.type = typ
        self.dimensions = dim

    def __eq__(self, rhs):
        assert(isinstance(rhs, self.__class__))
        if len(self.dimensions) != len(rhs.dimensions):
            return False
        if self.type != rhs.type or any(self.dimensions[i] != rhs.dimensions[i]
                                        for i in range(len(self.dimensions))):
            return False
        return True

    def __str__(self):
        return f"_DBVariable(type = {self.type}, dimension = {self.dimensions})"

DBVariable = _DBVariable

def get_variable_info(db, key):
    """Get the info of a variable as a namedtuple"""
    variable = db.variables[key]
    return _DBVariable(variable.datatype, variable.dimensions)

def get_dimension_info(db, key):
    """Get the info of a dimension"""
    dim = db.dimensions[key]
    if dim.isunlimited():
        return 'unlimited'
    else:
        return dim.size

class DatabaseTools(object):
    """Namespace to store general tools to work with the database"""

    @staticmethod
    def get_variables(filename, keys):
        db = load_database(filename)
        result = {key: get_dimension_info(db, key) for key in keys}
        db.close()
        return result

class DatabaseGenerator(Generator):

    default = "DIM"

    leafnode_type = (str, int, _DBVariable)

    def __init__(self, string):
        tree, _keys = self._configstring_to_keys_and_tree(string, None)
        if 'vars' in tree:
            tree['variables'] = tree.pop('vars')
        if 'dims' in tree:
            tree['dimensions'] = tree.pop('dims')

        self.tree = tree

    def leaf_from_string(self, entry, *, parent=None):
        """Create a leaf from an entry in the config file

        Args:
            name (str):
                name of the entry

            value (str):
                value of the entry in the config

        Kwargs:
            parent (str):
                identifier of the parent node

        Returns:
            A leaf node

        Raises:
            ValueError:
                If the value cannot be parsed
        """
        if parent in ["vars", "variables"]:
            typ, dims = entry.value.split(self.seperator)
            # get rid of brackets
            dims = dims.replace("(", "").replace(")", "")
            # split according to , or not
            if "," in dims:
                dims = [ele.strip() for ele in dims.split(',')]
            else:
                dims = dims.split()
            # return DBVariable
            return _DBVariable(self.select_type(typ), dims)
        elif parent in ["dims", "dimensions"]:
            if entry.value in ['unlimited', 'unlim']:
                return 'unlimited'
            return int(entry.value)
        else:
            raise ValueError("Database can only have Dimensions and Variables")

    @staticmethod
    def select_type(typ):
        """select type"""
        types = {
            'int': np.int64,
            'float': np.float,
            'double': np.double,
            'complex': np.complex,
        }
        typ = typ.strip().lower()

        value = types.get(typ, None)
        if value is not None:
            return value
        raise ValueError(f"Only except values of {', '.join(key for key in types.keys())}")

class DatabaseRepresentation(object):
    """Store abstract representation of the Variables and
    Dimensions stored in the Database. This class makes
    also comparisons between different representation
    straight forward!
    """

    __slots__ = ('variables', 'dimensions', 'unlimited', '_created', '_db', '_handle')

    def __init__(self, settings):
        self._parse(settings)
        self._created = False
        self._db = None
        self._handle = None

    @classmethod
    def from_string(cls, string):
        settings = DatabaseGenerator(string).tree
        return cls(settings)

    @classmethod
    def from_db(cls, db):
        """Create DatabaseRepresentation from a database set"""
        variables = {key: get_variable_info(db, key) for key in db.variables.keys()}
        dimensions = {key: get_dimension_info(db, key) for key in db.dimensions.keys()}
        return cls({'variables': variables, 'dimensions': dimensions})

    def __str__(self):
        dims = ", ".join(item for item in self['dimensions'])
        var = ", ".join(item for item in self['dimensions'])
        return f"""Database:
                    dimensions: {dims}
                    variables: {var}
                """

    def _parse(self, settings):
        """Parse given database"""
        self.dimensions = {}
        self.unlimited = None
        # at least one dimension need to be defined!!!
        for dim_name, dim in settings['dimensions'].items():
            if dim == 'unlimited':
                if self.unlimited is None:
                    self.unlimited = dim_name
                else:
                    raise Exception("Only a single unlimited dimension allowed!")
            self.dimensions[dim_name] = dim
        # can be that 0 variables are defined, doesnt make sense, but possible
        self.variables = {var_name: variable
                          for var_name, variable in settings.get('variables', {}).items()}

    def __getitem__(self, key):
        if key == 'dimensions':
            return self.dimensions
        elif key == 'variables':
            return self.variables
        else:
            raise KeyError("Only ['dimension', 'variables'] are allowed keys!")

    def create_database(self, filename, read_only=False):
        """Create the database from the representation"""
        if self._created is True:
            return self._db, self._handle

        if read_only is True:
            if not exists_and_isfile(filename):
                raise Exception(f"Database {filename} needs to exists")
            else:
                self._created = True
                self._db, self._handle = self._load_database(filename)
                return self._db, self._handle

        if exists_and_isfile(filename):
            self._db, self._handle = self._load_database(filename)
        else:
            self._db, self._handle = self._init_database(filename)
        #
        self._created = True
        return self._db, self._handle

    def __eq__(self, rhs):
        """"Compare two representations"""
        assert(isinstance(rhs, self.__class__))
        # check dimensions
        if (set(rhs['dimensions'].keys()) != set(self['dimensions'].keys())):
            return False
        # check that dimensions are exactly the same
        if not all(rhs['dimensions'][dim_name] == self['dimensions'][dim_name]
                   for dim_name in self['dimensions'].keys()):
            return False

        # check variables
        if (set(rhs['variables'].keys()) != set(self['variables'].keys())):
            print("variables keys not the same?")
            return False
        if any(rhs['variables'][var_name] != self['variables'][var_name]
               for var_name in rhs['variables'].keys()):
            return False
        return True

    def _init_database(self, filename):
        """Create a new database"""
        return create_dataset(filename, self)

    def _load_database(self, filename, read_only=False):
        """Load an existing database and check
           that it is compatable with the existing one"""
        if read_only is True:
            db = load_database(filename, io_options='r')
        else:
            db = load_database(filename)
        ref = DatabaseRepresentation.from_db(db)

        if ref != self:
            raise Exception('Database is not in agreement with ask settings!')
        return db, db.variables

def create_dataset(filename, settings):
    #
    nc = netCDF4.Dataset(filename, 'w')
    # create dimensions
    for dim_name, dim in settings['dimensions'].items():
        if dim == 'unlimited':
            dim = None
        nc.createDimension(dim_name, dim)
    # create variables
    handle = {}
    for var_name, variable in settings['variables'].items():
        handle[var_name] = nc.createVariable(var_name, variable.type, variable.dimensions)
    return nc, handle

def load_database(filename, io_options='a'):
    return netCDF4.Dataset(filename, io_options)


from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common import keys
#     cd C:\Program Files\Google\Chrome\Application
#     chrome.exe -remote-debugging-port=9222 -user-data-dir=C:\Chomedata
opt = Options()
opt.add_experimental_option("debuggerAddress","localhost:9222")
url = "https://kite.zerodha.com/dashboard"
driver = webdriver.Chrome(options=opt)
driver.get(url)
for i in range(1,130):
        i = i + 1
        n1 = ActionChains(driver)
        ideabse1 = driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[1]/div/div[2]/div/div/div/div/span[1]")
        n1.move_to_element(ideabse1).perform()
        ideabse2 = driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[1]/div/div[2]/div/div[1]/div/span/span[3]/button/span")
        ideabse2.click()
        time.sleep(1)
        bserate = "/html/body/div[1]/div[2]/div[1]/div/div[2]/div/div[1]/div/div[2]/div[1]/div/table[1]/tbody/tr[1]/td[1]"
        time.sleep(1)
        bsevalue = driver.find_element_by_xpath(bserate).text
        print(bsevalue)
        ideabse2.click()
        ideanse1 = driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div/div/span[1]")
        n1.move_to_element(ideanse1).perform()
        ideanse2 = driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div/span/span[3]/button/span")
        ideanse2.click()
        time.sleep(1)
        nserate = "/html/body/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div/div[2]/div[1]/div[1]/table[1]/tbody/tr[1]/td[1]"
        time.sleep(1)
        nsevalue = driver.find_element_by_xpath(nserate).text
        print(nsevalue)
        ideanse2.click()


import unittest
from portal_src.bin.utils.json_.config import *
from pathlib import Path

class TestJsonUtils(unittest.TestCase):

    def test_json_dict(self):
        jd = JsonDict("""
        {
            "test": 24,
            "test2" : [1,2,"34", { "testin": 23 }],
            "bla" : {
                "blubb": "test"
            }
        }
        """)
        d = jd.value()
        self.assertEqual(d['test'], 24)
        self.assertEqual(d['bla']['blubb'], "test")

    def test_json_fail(self):
        jd = JsonDict("""
        {
            "test": 24,
            "test2" : [1,2,"34", { "testin": 23 }],
            "bla" : {
                "blubb": "test"

        """)
        self.assertIsNone(jd.value())
        self.assertFalse(jd.valid())

    def test_read_json(self):
        path = Path(__file__).parent / "test.json"
        reader = JsonConfigReader(path)
        result = reader.read()
        d = result.value()
        self.assertEqual(d['test'], 24)
        self.assertEqual(d['bla']['blubb'], "testäöüßß")

    def test_read_json_fail(self):
        path = Path(__file__).parent / "test1.json"
        reader = JsonConfigReader(path)
        result = reader.read()
        self.assertIsNone(result)

    def test_write_json(self):
        jd = JsonDict("""
        {
            "test": 24,
            "test2" : [1,2,"34", { "testin": 23 }],
            "bla" : {
                "blubb": "testäöüßß"
            }
        }
        """)
        path = Path(__file__).parent / "test2.json"
        writer = JsonConfigWriter(path)
        writer.write(jd)

    def test_write_json_fail(self):
        jd = JsonDict("""
        {
            "test": 24,
            "test2" : [1,2,"34", { "testin": 23 }],
            "bla" : {
                "blubb": "testäöüßß"

        """)
        path = Path(__file__).parent / "test3.json"
        writer = JsonConfigWriter(path)
        writer.write(jd)

    def test_json_obj(self):
        path = Path(__file__).parent / "test.json"
        reader = JsonConfigReader(path)
        result = reader.read()
        obj = JsonConfigObject(result).obj()
        self.assertTrue(hasattr(obj, "test"))
        self.assertEqual(obj.test, 24)

    def test_json_obj_fail(self):
        jd = JsonDict("""
        {
            "test": 24,
            "test2" : [1,2,"34", { "testin": 23 }],
            "bla" : {
                "blubb": "testäöüßß"

        """)
        obj = JsonConfigObject(jd).obj()
        if obj is not None:
            raise AssertionError("object should be none")

    def test_json_config(self):
        path = Path(__file__).parent / "config.json"
        config = JsonConfig(path)
        confobj = config.get()
        self.assertTrue(hasattr(confobj, "test"))
        self.assertEqual(confobj.test, 24)
        self.assertTrue(hasattr(confobj, "test2"))
        self.assertTrue(isinstance(confobj.test2, list))
        confobj.test2.append(1)
        config.save()

    def test_json_config_fail(self):
        path = Path(__file__).parent / "config2.json"
        config = JsonConfig(path)
        confobj = config.get()
        self.assertEqual(confobj, None)


# -*- coding: utf-8 -*-
import logging
from os.path import join

LOGGER_INSTANCE = {}
logging.getLogger().addHandler(logging.NullHandler())

def get_logger(name, logger=None, **kargs):
    if name not in LOGGER_INSTANCE:
        LOGGER_INSTANCE[name] = Logger(name, logger, **kargs)
    return LOGGER_INSTANCE[name]

def getHandler(hdlr_cls, lvl=logging.DEBUG, format=None, *args, **kargs):
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(message)s" if not format \
                                      else format)
    hdlr = hdlr_cls(*args, **kargs)
    hdlr.setFormatter(formatter)
    if lvl:
        hdlr.setLevel(lvl)
    return hdlr

def getFileHandler(logfile, lvl=logging.DEBUG, format=None):
    return getHandler(logging.FileHandler, lvl, format, logfile)

class Logger:
    Logger_config = {}
    Logger_rootlogger = logging.getLogger("Pixiu")

    @classmethod
    def configure(cls,**kargs):
        cls.Logger_config.update(kargs)
        if kargs.get("if_verbose", False):
            cls.Logger_rootlogger.addHandler(getHandler(logging.StreamHandler,
                                                        lvl=logging.DEBUG))
        cls.Logger_rootlogger.setLevel(logging.DEBUG if kargs.get("if_debug", False)
                                       else logging.ERROR)

    @property
    def rootlogger(self):
        return type(self).Logger_rootlogger

    def __init__(self, name, logger=None, **kargs):
        self.name = name
        self.config = {**type(self).Logger_config, **kargs}
        self.logger = type(self).Logger_rootlogger.getChild(name) if not logger\
            else logger
        self._logger_setup()
        if not logger:
            self.logger.setLevel(logging.DEBUG if self.config.get("if_debug", False)
                                 else logging.ERROR)

    def _logger_setup(self):
        if self.config.get("if_debug", False):
            if not self.config.get("if_verbose", False):
                self.logger.addHandler(getHandler(logging.StreamHandler,
                                                  lvl=logging.DEBUG))

            dbglog = self.config.get("dbglog", "") or join(self.config.get("loghome", "log"),
                                          "{name}_debug.log".format(name=self.name))
            self.logger.addHandler(getFileHandler(dbglog, logging.DEBUG))

        errlog = self.config.get("errlog", "") or join(self.config.get("loghome", "log"),
                                      "{name}_error.log".format(name=self.name))
        self.logger.addHandler(getFileHandler(errlog, logging.ERROR))

    def __getattr__(self, item):
        return object.__getattribute__(object.__getattribute__(self, "logger"), item)

    def getChild(self, name, **kargs):
        return LOGGER_INSTANCE.setdefault('.'.join((self.name, name)),
                                          Logger(name='.'.join((self.name, name)), **kargs))


"""Test utils for rule generator scanners."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import yaml

from deploy.rule_generator import project_config

_OVERALL_DICT = {
    'domain': 'domain.com',
    'organization_id': '246801357924',
    'folder_id': '357801357924',
    'billing_account': '012345-6789AB-CDEF01',
    'allowed_apis': ['compute.googleapis.com', 'storage.googleapis.com'],
}

_PROJECT_YAML = """
projects:
- project_id: %(project_id)s
  owners_group: %(project_id)s-owners@domain.com
  auditors_group: %(project_id)s-auditors@domain.com
  data_readwrite_groups:
  - %(project_id)s-readwrite@domain.com
  data_readonly_groups:
  - %(project_id)s-readonly@domain.com
  - %(project_id)s-readonly-external@domain.com
  data_buckets:
  - name_suffix: '-bucket'
    location: US-CENTRAL1
    storage_class: REGIONAL
  gce_instances:
  - name: 'instance'
    zone: 'us-central1-f'
    machine_type: 'n1-standard-1'
    existing_boot_image: 'projects/debian-cloud/global/images/family/debian-9'
    start_vm: true
  audit_logs:
    logs_gcs_bucket:
      location: US
      storage_class: MULTI_REGIONAL
      ttl_days: 365
    logs_bigquery_dataset:
      location: US
"""

_GENERATED_FIELDS = """
generated_fields:
  forseti:
    service_account: forseti@sample-forseti.iam.gserviceaccount.com
    server_bucket: gs://forseti-project-server/
  projects:
    %(project_id)s:
      project_number: %(project_num)s
      log_sink_service_account: audit-logs-bq@logging-%(project_num)s.iam.gserviceaccount.com
      gce_instance_info:
      - name: 'instance'
        id: '123'
    forseti-project:
      project_number: 9999
      log_sink_service_account: forseti-logs@logging-9999.iam.gserviceaccount.com
"""

def create_test_global_config():
  """Creates a global config dictionary for tests."""
  return _OVERALL_DICT.copy()

def create_test_project(project_id, project_num, extra_fields=None,
                        audit_logs_project=None):
  """Create a test project with optional extra project_config fields."""
  config_dict = yaml.load(_PROJECT_YAML % {
      'project_id': project_id, 'project_num': project_num})
  project = config_dict['projects'][0]
  generated_fields = yaml.load(_GENERATED_FIELDS % {
      'project_id': project_id,
      'project_num': project_num
  })
  if extra_fields:
    project.update(extra_fields)
  print(generated_fields)
  print('xxxxxxxxxxxxxxxxxxxxxx')
  return project_config.ProjectConfig(
      project=project,
      audit_logs_project=audit_logs_project,
      generated_fields=generated_fields['generated_fields'])

def create_test_projects(num_projects):
  """Create a list of test projects."""
  return [
      create_test_project(project_id='project-%s' % i, project_num=1000000 + i)
      for i in range(num_projects)
  ]


from pathlib import Path
import logging
import pandas as pd
import numpy as np

HC = 'HC'
PA = 'Patients'
GAIT = 'gaitRaw'
HW = 'handwriting'
METADATA = 'metadata.csv'
LABEL = 'label'
ID = 'ID'

class ParkLoader(object):
    """Loads a parkinson data folder"""
    def __init__(self, path):
        """
        :param path: Path to mulltimodal parkinsons dataset
        possible splits: handwriting_all, gait_all, handwriting_by_word, gait_by_distance
        Text files in it are in the format PatientID_TaskID.txt
        """
        self._path = Path(path)
        if not self._path.is_dir():
            logging.error("{} is not a directory.".format(path))
            raise NotADirectoryError("Given parkinsons data directory does not exist")

        self._files = list(self._path.glob("**/*.txt"))

        def classes(x):
            if x < 21:
                return 1
            elif 20 < x < 40:
                return 2
            else:
                return 3
        hc_ids = sorted(list(set([f.stem.split('_')[0] for f in self._files if HC in f.parts])))
        tmp = pd.read_csv(str(self._path / METADATA))
        tmp[LABEL] = tmp['updrs_total'].apply(classes)
        self._metadata = tmp[[ID, LABEL]]
        for id in hc_ids:
            self._metadata = self._metadata.append({ID: id, LABEL: 0}, ignore_index=True)

        self._data_sets = {}
        for n in self.names:
            self._data_sets[n] = [f for f in self._files if n in str(f.stem)]

    @property
    def names(self):
        """
        Dataset names
        """

        return list(set(f.stem.split('_')[-1] for f in self._files))

    def load(self, name, z_norm=False):
        """
        Load dataset from disk
        :param name: name of dataset
        :return: UCRData object
        """
        try:
            return ParkData.from_paths(self._data_sets.get(name), name, self._metadata)
        except KeyError:
            logging.error("Data{} not available in {}".format(name, self._path))

class ParkData(object):
    """Can be either gait or handwriting data"""
    def __init__(self, name: str, data):
        """
        :param name: Name of task
        :param data: dataframe containing data, labels and patient_id needed for splitting
        """
        self.name = name
        self.data = data

    @classmethod
    def from_paths(cls, paths: list, name: str, metadata):
        """
        Load single dataset add given path
        :param paths: list containing paths matching a single dataset
        :param name: name of task to load
        :return: ParkData
        """
        logging.info("Loading {}".format(name))
        header = None if HW in str(paths[0]) else 0
        delim = ';' if HW in str(paths[0]) else ' '
        data = cls._read_files(paths, header, delim, metadata)
        return cls(name, data)

    def leave_one_out(self, z_norm=False):
        for pid in [p for p in self.data[ID].unique() if HC not in p]:
            train = self.data.where(self.data[ID] != pid).dropna()
            test = self.data.where(self.data[ID] == pid).dropna()
            if len(test) < 1:
                continue
            train_data = np.asarray(train['data'].values)
            test_data = np.asarray(test['data'].values)
            train_labels = np.asarray(train[LABEL].values)
            test_labels = np.asarray(test[LABEL].values)
            if z_norm:
                train_data, test_data = self._z_norm(train_data, test_data)
                yield train_data, test_data, train_labels, test_labels, pid
            else:
                yield train_data, test_data, train_labels, test_labels, pid

    @staticmethod
    def _split(data):
        """Split into labels and values. last column are labels"""
        labels = [int(d[1]) for d in data]
        values = [d[0] for d in data]
        return labels, values

    @staticmethod
    def _read_files(paths, header, delim, metadata):
        def get_labels(p):
            pid = p.stem.split('_')[0]
            pid = pid if pid[-1].isdigit() else pid[:-1]
            label = metadata.where(metadata[ID].str.startswith(pid)).dropna()[LABEL].iloc[0]
            return label, pid
        data = []
        for p in paths:
            try:
                df = pd.read_csv(str(p), header=header, sep=delim)
                lbl, pid = get_labels(p)
                # dirty fucking hack: if header is none, then HW data. only first 6 values needed/valid
                vals = df.values[:, 0:6] if header is None else df.values
                data.append((vals, lbl, pid))
            except Exception as e:
                logging.info("Loading {} has failed".format(p))
                logging.error(e)
                continue

        return pd.DataFrame(data, columns=['data', LABEL, ID])

    @staticmethod
    def _z_norm(train_data, test_data):
        axis = 0
        ddof = 0

        # Calculate mean and std on train data
        mns = np.nanmean([v for ts in train_data for v in ts])
        sstd = np.nanstd([v for ts in train_data for v in ts])

        def norm(a):
            a = np.asanyarray(a)
            if axis and mns.ndim < a.ndim:
                return ((a - np.expand_dims(mns, axis=axis)) /
                        np.expand_dims(sstd, axis=axis))
            else:
                return (a - mns) / sstd

        return np.asarray([norm(t) for t in train_data]), np.asarray([norm(t) for t in test_data])


"""Produces the html folder for analysis. This is essentially just copying
the html/ folder and preprocessing certain ids.
"""

from ignite_simple.analarams import AnalysisSettings
import json
from bs4 import BeautifulSoup
import os
import shutil
import math
import numpy as np

def _set_all(soup, iden, val):
    for ele in soup.find_all(id=iden):
        ele.string = str(val)

def find_referenced_images(html):
    """Searches the given html file for images which are referenced in the standard way
    (src attribute on img tag) and returns them as they are written."""
    with open(html, 'r') as infile:
        soup = BeautifulSoup(infile.read(), 'html.parser')

    return set(img['src'] for img in soup.find_all('img'))

HTML_REFD_IMAGES = find_referenced_images(os.path.join(
    os.path.dirname(__file__), '../html/index.html'))

# we strip the ../ that the images are referenced with
HTML_REFD_IMAGES = set(i[3:] for i in HTML_REFD_IMAGES)

def text_analyze(settings: AnalysisSettings, folder: str):
    """Analyzes the given folder produced by the model manager, storing the
    results in folder/analysis/html

    Args:
        settings (AnalysisSettings): the analysis settings.
        folder (str): the folder that was passed to the model manager.
    """

    with open(os.path.join(folder, 'hparams', 'misc.json')) as infile:
        misc = json.load(infile)

    with np.load(os.path.join(folder, 'results.npz')) as infile:
        results = dict(infile.items())

    in_html_folder = os.path.join(os.path.dirname(__file__), '../html')
    in_html_folder = os.path.abspath(in_html_folder)

    out_html_folder = os.path.abspath(os.path.join(folder, 'analysis', 'html'))

    cwd = os.getcwd()
    if os.path.exists(out_html_folder):
        shutil.rmtree(out_html_folder)

    shutil.copytree(in_html_folder, out_html_folder)
    os.chdir(cwd)

    with open(os.path.join(in_html_folder, 'index.html'), 'r') as infile:
        soup = BeautifulSoup(infile.read(), 'html.parser')

    for key, val in misc.items():
        _set_all(soup, key.replace('_', '-'), val)

    _set_all(soup, 'trials-count', results['final_perf_train'].shape[0])
    _set_all(soup, 'trials-train-best-performance', results['final_perf_train'].max())
    _set_all(soup, 'trials-train-best-loss', results['final_loss_train'].min())
    _set_all(soup, 'trials-train-mean-performance', results['final_perf_train'].mean())
    _set_all(soup, 'trials-train-std-performance', results['final_perf_train'].std())
    _set_all(soup, 'trials-train-mean-loss', results['final_loss_train'].mean())
    _set_all(soup, 'trials-train-std-loss', results['final_loss_train'].std())
    _set_all(soup, 'trials-val-best-performance', results['final_perf_val'].max())
    _set_all(soup, 'trials-val-best-loss', results['final_loss_val'].min())
    _set_all(soup, 'trials-val-mean-performance', results['final_perf_val'].mean())
    _set_all(soup, 'trials-val-std-performance', results['final_perf_val'].std())
    _set_all(soup, 'trials-val-mean-loss', results['final_loss_val'].mean())
    _set_all(soup, 'trials-val-std-loss', results['final_loss_val'].std())

    _set_all(soup, 'initial-half-cycle', misc['initial_cycle_time'] // 2)

    if misc['batch_sweep_trials_each'] <= 0:
        soup.find(id='batch-size-sweep-other').string = ''
    else:
        soup.find(id='batch-size-sweep-fastest').string = ''

    if math.isnan(misc['second_lr_num_trials']):
        soup.find(id='second-lr-sweep').string = ''
    else:
        soup.find(id='no-second-lr-sweep').string = ''

    if not settings.hparam_selection_specifics:
        soup.find(id='initial-lr-sweep').string = ''
        soup.find(id='batch-size-sweep').string = ''
        soup.find(id='no-second-lr-sweep').string = ''
        soup.find(id='second-lr-sweep').string = ''

    if not settings.hparam_selection_specific_imgs:
        for div in soup.select('.hparam-figures'):
            div.string = ''

    if not settings.training_metric_imgs:
        for div in soup.select('.trial-figures'):
            div.string = ''

    with open(os.path.join(out_html_folder, 'index.html'), 'w') as outfile:
        outfile.write(str(soup))


import glob
import re
import shutil
import datetime
import codecs
import os
import xml.dom.minidom as md
import xml.etree.ElementTree as et
from pathlib import Path

# ディレクトリ名の昇順でソート
sl = list()
for path in glob.glob("../Songs/*"):
    sl.append(path)
sl.sort(key=str.lower)

smfl = list()
for path in glob.glob("../Songs/*/*"):
    smfl.append(path)
smfl.sort(key=str.lower)

stats_src = "/Users/okada-toshiki/Library/Preferences/StepMania 5/LocalProfiles/00000000/Stats.xml"
stats_dst = "../Stats/stats_{0:%m%d}.xml".format(datetime.datetime.now())
shutil.copyfile(stats_src, stats_dst)

stats = open(stats_dst)
root = et.fromstring(stats.read())
doc = md.parseString(et.tostring(root, 'utf-8'))
st_lines = doc.toxml().split('\n')

try:
    os.remove("../Analysed/table_{0:%m%d}.tsv".format(datetime.datetime.now()))
    os.remove("../Analysed/clear_ratio_{0:%m%d}.tsv".format(datetime.datetime.now()))
    os.remove("../Analysed/not_cleared_{0:%m%d}.tsv".format(datetime.datetime.now()))
    os.remove("../Analysed/cleared_{0:%m%d}.tsv".format(datetime.datetime.now()))
except IOError:
    pass

clear_count = [0] * 8
total_count = [0] * 8
clear_count_raw = [0] * 18

def print_clear_ratio():
    for i in range(0, 8):
        print(str(total_count[i] - clear_count[i]) +
            "\t" + str(clear_count[i]) + "\t" + str(total_count[i]),
            file=codecs.open("../Analysed/clear_ratio_{0:%m%d}.tsv".format(datetime.datetime.now()), 'a', 'utf-8'))

def format_clear_count():
    sum_u8 = 0
    sum_o15 = 0
    for i in range(0, 8):
        sum_u8 += clear_count_raw[i]
    clear_count[0] = sum_u8
    for i in range(8, 15):
        clear_count[i-7] = clear_count_raw[i]
    for i in range(15, 18):
        sum_o15 += clear_count_raw[i]
    clear_count[7] = sum_o15

def get_keys_from_value(d, val):
    return [k for k, v in d.items() if v == val]

def listup_not_cleared(dif, res):
    for i in range(9, 17):
        for level in get_keys_from_value(dif, str(i)):
            if res[level] == '未' or res[level] == 'F':
                print(str(i) + "\t" + dif["title"] + "\t" + level + "\t" + res[level],
                    file=codecs.open("../Analysed/not_cleared_{0:%m%d}.tsv".format(datetime.datetime.now()), 'a', 'utf-8'))
            elif res[level] != "--":
                print(str(i) + "\t" + dif["title"] + "\t" + level + "\t" + res[level],
                    file=codecs.open("../Analysed/cleared_{0:%m%d}.tsv".format(datetime.datetime.now()), 'a', 'utf-8'))

def sum_clear_ratio(dif, res):
    for v in dif.values():
        try:
            if   int(v) <= 8:  total_count[0] += 1
            elif int(v) == 9:  total_count[1] += 1
            elif int(v) == 10: total_count[2] += 1
            elif int(v) == 11: total_count[3] += 1
            elif int(v) == 12: total_count[4] += 1
            elif int(v) == 13: total_count[5] += 1
            elif int(v) == 14: total_count[6] += 1
            elif int(v) >= 15: total_count[7] += 1
        except Exception:
            pass

    for i in range(1, 18):
        if dif["Beginner"] != "-" and int(dif["Beginner"]) == i and res["Beginner"] != "未" and res["Beginner"] != "F":
            clear_count_raw[i-1] += 1
        if dif["Easy"] != "-" and int(dif["Easy"]) == i and res["Easy"] != "未" and res["Easy"] != "F":
            clear_count_raw[i-1] += 1
        if dif["Medium"] != "-" and int(dif["Medium"]) == i and res["Medium"] != "未" and res["Medium"] != "F":
            clear_count_raw[i-1] += 1
        if dif["Hard"] != "-" and int(dif["Hard"]) == i and res["Hard"] != "未" and res["Hard"] != "F":
            clear_count_raw[i-1] += 1
        if dif["Challenge"] != "-" and int(dif["Challenge"]) == i and res["Challenge"] != "未" and res["Challenge"] != "F":
            clear_count_raw[i-1] += 1

def print_result_table(fcount, dict, dict_res):
    print(fcount + "\t" + dict["version"] + "\t" + dict["title"] + "\t"
        + dict["Beginner"] + "\t" + dict_res["Beginner"] + "\t"
        + dict["Easy"] + "\t" + dict_res["Easy"] + "\t"
        + dict["Medium"] + "\t" + dict_res["Medium"] + "\t"
        + dict["Hard"] + "\t" + dict_res["Hard"] + "\t"
        + dict["Challenge"] + "\t" + dict_res["Challenge"] + "\t" + dict["Next"],
        file=codecs.open("../Analysed/table_{0:%m%d}.tsv".format(datetime.datetime.now()), 'a', 'utf-8'))

def has_cleared_high_difficulty(difficulty, org):
    if difficulty != "未" and difficulty != "-" and difficulty != "F" and org == "未": return "--"
    else: return org

def convert_res(res_line):
    if   "Tier01" in res_line: return "AAA"
    elif "Tier02" in res_line: return "AA"
    elif "Tier03" in res_line: return "A"
    elif "Tier04" in res_line: return "B"
    elif "Tier05" in res_line: return "C"
    elif "Tier06" in res_line: return "D"
    elif "Tier07" in res_line: return "E"
    elif "Failed" in res_line: return "F"
    else: return "未"

def has_difficulty(difficulty, org):
    if difficulty == "-": return "-"
    else: return org

def judge_next_level(res):
    if res["Beginner"] == "未" or res["Beginner"] == "F": return "習"
    if res["Easy"] == "未" or res["Easy"] == "F": return "楽"
    if res["Medium"] == "未" or res["Medium"] == "F": return "踊"
    if res["Hard"] == "未" or res["Hard"] == "F": return "激"
    if res["Challenge"] == "未" or res["Challenge"] == "F": return "鬼"
    else: return "-"

fcount = 0

for smf in smfl:
    for path in list(Path(smf).glob("*.sm")):
        with open(path) as f:
            fcount += 1
            smlines = f.readlines()
            smline_num = 0
            dict = {"dirname":"sample", "title":"sample", "version":"sample", "Beginner":"-", "Easy":"-", "Medium":"-", "Hard":"-", "Challenge":"-", "Next":"-"}
            for smline in smlines:
                if '#TITLE:' in smline:
                    title = re.search(r"(?<=\:).+?(?=\;)", smline)
                    dict["title"] = title.group()
                    dict["version"] = os.path.dirname(smf)[9:]
                    dict["dirname"] = os.path.dirname(path)[3:]
                if 'dance-single:' in smline:
                    if smlines[smline_num+2].rstrip(':\n').lstrip(' ') == "Beginner":
                        dict["Beginner"] = smlines[smline_num+3].rstrip(':\n').lstrip(' ')
                    elif smlines[smline_num+2].rstrip(':\n').lstrip(' ') == "Easy":
                        dict["Easy"] = smlines[smline_num+3].rstrip(':\n').lstrip(' ')
                    elif smlines[smline_num+2].rstrip(':\n').lstrip(' ') == "Medium":
                        dict["Medium"] = smlines[smline_num+3].rstrip(':\n').lstrip(' ')
                    elif smlines[smline_num+2].rstrip(':\n').lstrip(' ') == "Hard":
                        dict["Hard"] = smlines[smline_num+3].rstrip(':\n').lstrip(' ')
                    elif smlines[smline_num+2].rstrip(':\n').lstrip(' ') == "Challenge":
                        dict["Challenge"] = smlines[smline_num+3].rstrip(':\n').lstrip(' ')
                smline_num += 1

            stline_num = 0
            dict_res = {"dirname":"sample", "Beginner":"未", "Easy":"未", "Medium":"未", "Hard":"未", "Challenge":"未"}
            for st_line in st_lines:
                if "&" in st_line:
                    st_line = st_line.replace("&", "&")
                if 'Song Dir=' in st_line and dict["dirname"] in st_line and '/>' not in st_line:
                    dict_res["dirname"] = dict["dirname"]
                    stline_num_inner = stline_num
                    for st_line in st_lines[stline_num:]:
                        if 'Steps Difficulty="Beginner"' in st_line:
                            dict_res["Beginner"] = convert_res(st_lines[stline_num_inner+4])
                        elif 'Steps Difficulty="Easy"' in st_line:
                            dict_res["Easy"] = convert_res(st_lines[stline_num_inner+4])
                        elif 'Steps Difficulty="Medium"' in st_line:
                            dict_res["Medium"] = convert_res(st_lines[stline_num_inner+4])
                        elif 'Steps Difficulty="Hard"' in st_line:
                            dict_res["Hard"] = convert_res(st_lines[stline_num_inner+4])
                        elif 'Steps Difficulty="Challenge"' in st_line:
                            dict_res["Challenge"] = convert_res(st_lines[stline_num_inner+4])
                        if "</Song>" in st_line:
                            break
                        stline_num_inner += 1
                stline_num += 1

            # そもそもその難易度が存在しなければ　"-" とする
            dict_res["Beginner"] = has_difficulty(dict["Beginner"], dict_res["Beginner"])
            dict_res["Easy"] = has_difficulty(dict["Easy"], dict_res["Easy"])
            dict_res["Medium"] = has_difficulty(dict["Medium"], dict_res["Medium"])
            dict_res["Hard"] = has_difficulty(dict["Hard"], dict_res["Hard"])
            dict_res["Challenge"] = has_difficulty(dict["Challenge"], dict_res["Challenge"])

            # 上の難易度をクリアしていれば、それ以下の難易度は "--" とする
            dict_res["Hard"] = has_cleared_high_difficulty(dict_res["Challenge"], dict_res["Hard"])
            dict_res["Medium"] = has_cleared_high_difficulty(dict_res["Hard"], dict_res["Medium"])
            dict_res["Easy"] = has_cleared_high_difficulty(dict_res["Medium"], dict_res["Easy"])
            dict_res["Beginner"] = has_cleared_high_difficulty(dict_res["Easy"], dict_res["Beginner"])

            # 次に挑戦すべきレベルを判定
            dict["Next"] = judge_next_level(dict_res)

            # 結果をまとめたテーブルを出力
            print_result_table(str(fcount), dict, dict_res)

            sum_clear_ratio(dict, dict_res)
            listup_not_cleared(dict, dict_res)

format_clear_count()
print_clear_ratio()


#!/usr/bin/python3
""" Class Base: """
import json
from os import path

class Base:
    """ private class attribute __nb_objects = 0 """
    __nb_objects = 0
    """  class constructor """
    def __init__(self, id=None):
        """ if id is not None, assign the public
        instance attribute id with this argument
        value - you can assume id is an integer and
        you don’t need to test the type of it """
        if id is not None:
            """pide at.. publico"""
            self.id = id
        else:
            """ otherwise, increment __nb_objects
            and assign the new value to the public
            instance attribute id """
            Base.__nb_objects += 1
            self.id = Base.__nb_objects

    @staticmethod
    def to_json_string(list_dictionaries):
        """ returns the JSON string representation
        of list_dictionaries"""
        if list_dictionaries is None or len(list_dictionaries) == 0:
            return "[]"
        return json.dumps(list_dictionaries)

    @classmethod
    def save_to_file(cls, list_objs):
        """class method def save_to_file(cls, list_objs):
        that writes the JSON string representation
        of list_objs to a file:"""
        filename = cls.__name__ + ".json"

        if list_objs is not None:
                list_objs = [i.to_dictionary() for i in list_objs]

        """If list_objs is None, save an empty list"""
        """You must overwrite the file if it already exists"""
        with open(filename, 'w', encoding="utf-8") as myfn:
            """You must use the static method to_json_string"""
            myfn.write(cls.to_json_string(list_objs))

    @staticmethod
    def from_json_string(json_string):
        """the static method def from_json_string
        (json_string): that returns the list of the
        JSON string representation json_string:"""
        if json_string is None or len(json_string) == 0:
            return []
        else:
            return json.loads(json_string)

    @classmethod
    def create(cls, **dictionary):
        """the class method def create(cls, **dictionary):
        that returns an instance with all attributes already set:
            - **dictionary can be thought of as double pointer to a dictionary
            - To use the update method to assign all
        attributes, you must create a “dummy” instance before:
                - Create a Rectangle
                or Square instance with
                “dummy” mandatory attributes (width, height, size, etc.)
                - Call update instance method
                to this “dummy” instance to apply
                your real values
            - You must use the method def update(self, *args, **kwargs)
            - **dictionary must be used as **kwargs of the method update"""
        if cls.__name__ == 'Rectangle':
            dummyNew = cls(1, 1)
        elif cls.__name__ == 'Square':
            dummyNew = cls(1, 0)
        dummyNew.update(**dictionary)
        return dummyNew

    @classmethod
    def load_from_file(cls):
        """the class method def load_from_file(cls):
        that returns a list of instances"""
        filename = cls.__name__ + ".json"
        instanceList = []
        """ If the file doesn’t exist, return an empty list """
        if path.exists(filename) is None or path.exists(filename) is False:
            return []
        else:
            """ Otherwise, return a list of instances - the type of these instances
            depends on cls (current class using this method) """
            with open(filename, 'r', encoding="utf-8") as myfn:
                f = myfn.read()
                myList = cls.from_json_string(f)
            """i = dict - el recorrido"""
            for i in myList:
                instanceList.append(cls.create(**i))
            return instanceList


from collections import OrderedDict

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import urllib
import pathlib
import os
import sys
import requests
import numpy as np
import warnings

warnings.filterwarnings("ignore")
from torchxrayvision.models import model_urls

class ResNet(nn.Module):
    def __init__(
        self, weights=None, apply_sigmoid=False, weights_filename_local=None,
    ):
        super(ResNet, self).__init__()

        self.apply_sigmoid = apply_sigmoid
        self.weights = weights
        self.weights_filename_local = weights_filename_local

        if not self.weights in model_urls.keys():
            possible_weights = [k for k in model_urls.keys() if k.startswith("resnet")]
            raise Exception("Weights value must be in {}".format(possible_weights))

        self.weights_dict = model_urls[weights]
        self.pathologies = model_urls[weights]["labels"]

        if self.weights.startswith("resnet101"):
            self.model = torchvision.models.resnet101(
                num_classes=len(self.weights_dict["labels"]), pretrained=False
            )
            # patch for single channel
            self.model.conv1 = torch.nn.Conv2d(
                1, 64, kernel_size=7, stride=2, padding=3, bias=False
            )

        elif self.weights.startswith("resnet50"):
            self.model = torchvision.models.resnet50(
                num_classes=len(self.weights_dict["labels"]), pretrained=False
            )
            # patch for single channel
            self.model.conv1 = torch.nn.Conv2d(
                1, 64, kernel_size=7, stride=2, padding=3, bias=False
            )

        try:
            self.model.load_state_dict(torch.load(self.weights_filename_local))
        except Exception as e:
            print("Loading failure. Check weights file:", self.weights_filename_local)
            raise e

        if "op_threshs" in model_urls[weights]:
            self.register_buffer(
                "op_threshs", torch.tensor(model_urls[weights]["op_threshs"])
            )

        self.upsample = nn.Upsample(
            size=(512, 512), mode="bilinear", align_corners=False
        )

        self.eval()

    def __repr__(self):
        if self.weights != None:
            return "XRV-ResNet-{}".format(self.weights)
        else:
            return "XRV-ResNet"

    def features(self, x):

        x = fix_resolution(x, 512, self)

        x = self.model.conv1(x)
        x = self.model.bn1(x)
        x = self.model.relu(x)
        x = self.model.maxpool(x)

        x = self.model.layer1(x)
        x = self.model.layer2(x)
        x = self.model.layer3(x)
        x = self.model.layer4(x)

        x = self.model.avgpool(x)
        x = torch.flatten(x, 1)
        return x

    def forward(self, x):

        x = fix_resolution(x, 512, self)

        out = self.model(x)

        if hasattr(self, "apply_sigmoid") and self.apply_sigmoid:
            out = torch.sigmoid(out)

        if hasattr(self, "op_threshs") and (self.op_threshs != None):
            out = torch.sigmoid(out)
            out = op_norm(out, self.op_threshs)
        return out

warning_log = {}

def fix_resolution(x, resolution, model):
    """
    Check resolution of input and resize to match requested
    """

    # just skip it if upsample was removed somehow
    if not hasattr(model, "upsample") or (model.upsample == None):
        return x

    if (x.shape[2] != resolution) | (x.shape[3] != resolution):
        if not hash(model) in warning_log:
            print(
                "Warning: Input size ({}x{}) is not the native resolution ({}x{}) for this model. A resize will be performed but this could impact performance.".format(
                    x.shape[2], x.shape[3], resolution, resolution
                )
            )
            warning_log[hash(model)] = True
        return model.upsample(x)
    return x

def op_norm(outputs, op_threshs):
    """normalize outputs according to operating points for a given model.
    Args:
        outputs: outputs of self.classifier(). torch.Size(batch_size, num_tasks)
        op_threshs_arr: torch.Size(batch_size, num_tasks) with self.op_threshs expanded.
    Returns:
        outputs_new: normalized outputs, torch.Size(batch_size, num_tasks)
    """
    # expand to batch size so we can do parallel comp
    op_threshs = op_threshs.expand(outputs.shape[0], -1)

    # initial values will be 0.5
    outputs_new = torch.zeros(outputs.shape, device=outputs.device) + 0.5

    # only select non-nan elements otherwise the gradient breaks
    mask_leq = (outputs < op_threshs) & ~torch.isnan(op_threshs)
    mask_gt = ~(outputs < op_threshs) & ~torch.isnan(op_threshs)

    # scale outputs less than thresh
    outputs_new[mask_leq] = outputs[mask_leq] / (op_threshs[mask_leq] * 2)
    # scale outputs greater than thresh
    outputs_new[mask_gt] = 1.0 - (
        (1.0 - outputs[mask_gt]) / ((1 - op_threshs[mask_gt]) * 2)
    )

    return outputs_new

def get_densenet_params(arch):
    assert "dense" in arch
    if arch == "densenet161":
        ret = dict(growth_rate=48, block_config=(6, 12, 36, 24), num_init_features=96)
    elif arch == "densenet169":
        ret = dict(growth_rate=32, block_config=(6, 12, 32, 32), num_init_features=64)
    elif arch == "densenet201":
        ret = dict(growth_rate=32, block_config=(6, 12, 48, 32), num_init_features=64)
    else:
        # default configuration: densenet121
        ret = dict(growth_rate=32, block_config=(6, 12, 24, 16), num_init_features=64)
    return ret

def get_model(weights, **kwargs):
    if weights.startswith("densenet"):
        return DenseNet(weights=weights, **kwargs)
    else:
        raise Exception("Unknown model")


from flask import Flask
from flask_restful import Api, Resource, reqparse, abort, fields, marshal_with
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask import  request, jsonify
app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db = SQLAlchemy(app)
ma = Marshmallow(app)

class catalog(db.Model):
	item_id = db.Column(db.String, primary_key=True)
	number_in_stock = db.Column(db.Integer ,nullable=False)
	cost=  db.Column(db.Integer, nullable=False)
	topic = db.Column(db.String(100), nullable=False)
	titel=db.Column(db.String(100), nullable=False)

	def __repr__(self):
		return f"catalog2(number_in_stock = {number_in_stock}, cost = {cost}, topic = {topic},titel={titel})"

db.create_all()
class ProductSchema(ma.Schema):
  class Meta:
    fields = ('item_id', 'number_in_stock', 'cost', 'topic','titel')

# Init schema
product_schema = ProductSchema()
products_schema = ProductSchema(many=True)
catalog_put_args = reqparse.RequestParser()
catalog_put_args.add_argument("number_in_stock", type=int, help="#stock not avalible", required=True)
catalog_put_args.add_argument("cost", type=int, help="cost not", required=True)
catalog_put_args.add_argument("topic", type=str, help="topic not", required=True)
catalog_put_args.add_argument("titel", type=str, help="topic not", required=True)
catalog_update_args = reqparse.RequestParser()
catalog_update_args.add_argument("number_in_stock", type=int, help="#stock not avalible")
catalog_update_args.add_argument("cost", type=int, help="cost not")
catalog_update_args.add_argument("topic", type=str, help="topic not")

catalog_update_args2 = reqparse.RequestParser()

catalog_update_args2.add_argument("item_id", type=str, help="#id")

catalog_update_args2.add_argument("topic", type=str, help="topic not")

catalog77_update_args = reqparse.RequestParser()

catalog77_update_args.add_argument("item_id", type=str, help="#id")

catalog88_update_args = reqparse.RequestParser()

catalog88_update_args.add_argument("cost", type=int, help="#id")
catalog88_update_args.add_argument("number_in_stock", type=int, help="#id")

resource_fields = {
	'item_id': fields.String,
	'number_in_stock': fields.Integer,
	'cost': fields.Integer,
	'topic': fields.String

}

class catalog2(Resource):
	@marshal_with(resource_fields)
	def get(self):
		args = catalog_update_args2.parse_args()
		t= not args['item_id']
		y=not args['topic']
		if t and y :

			abort(404,message="spesify in the body of  the message the topic if yoy want to search using cost or  spesify iteme id if you want to search by item id ")
		if args['item_id']:
			result = catalog.query.filter_by(item_id=args['item_id']).first()
		elif args['topic']:
			all_products = catalog.query.filter_by(topic=args['topic']).all()
			result = products_schema.dump(all_products)

		if not result:
			abort(404, message="book doesn't exist")

		return result
api.add_resource(catalog2, "/get_by_id_or_by_cost")
class catalog3(Resource):
	@marshal_with(resource_fields)
	def put(self, video_id):
		args = catalog_put_args.parse_args()
		result = catalog.query.filter_by(item_id=video_id).first()
		if result:
			abort(409, message="book id already  taken...")

		video = catalog(item_id=video_id, number_in_stock=args['number_in_stock'], cost=args['cost'], topic=args['topic'],titel=args['titel'])
		db.session.add(video)
		db.session.commit()
		return video, 201
api.add_resource(catalog3, "/create_book1/<int:video_id>")
class catalog4(Resource):
	@marshal_with(resource_fields)
	def post(self, video_id):
		args = catalog_update_args.parse_args()
		result = catalog.query.filter_by(item_id=video_id).first()
		if not result:
			abort(404, message="book doesn't exist")
		x=	not args['number_in_stock']
		y=  not  args['cost']
		z=  not args['topic']
		if x and y and z:
			abort(4004,message="spesify one at least of the cost or topic or number_in_stock")
		elif args['number_in_stock']:
			result.number_in_stock = args['number_in_stock']
		elif args['cost']:
			result.cost = args['cost']
		elif args['topic']:
			result.topic = args['topic']
		db.session.commit()
		return result

api.add_resource(catalog4, "/update_book_cost_or_topic_or_number_in_stock/<int:video_id>")

@app.route('/GET_ALL_BOOKS', methods=['GET'])
def get_products():
  all_products = catalog.query.all()
  result = products_schema.dump(all_products)
  return jsonify(result)

@app.route('/update_book_cost_and_number_in_stock/<id>', methods=['POST'])
def update_product(id):
	args = catalog88_update_args.parse_args()
	product = catalog.query.get(id)
	x= args['number_in_stock']
	y= args['cost']
	if(x):
	  number_in_stock = request.json['number_in_stock']
	  product.number_in_stock = number_in_stock
	if(y) :
	  cost = request.json['cost']
	  product.cost = cost
	db.session.commit()
	return product_schema.jsonify(product)

@app.route('/book_decraese_in_stock', methods=['POST'])
def update_product5():
	catalog89_update_args = reqparse.RequestParser()
	catalog89_update_args.add_argument("item_id", type=str, help="#id")
	args = catalog89_update_args.parse_args()
	product = catalog.query.get(args['item_id'])
	if not product :

	  return " book does not exist"
	if product.number_in_stock == 0:
	  return "number in stock is zero we can not decrement it"
	product.number_in_stock = product.number_in_stock -1
	db.session.commit()
	return product_schema.jsonify(product)

@app.route('/book_incraese_in_stock', methods=['POST'])

def update_product6():
	catalog89_update_args = reqparse.RequestParser()
	catalog89_update_args.add_argument("item_id", type=str, help="#id")
	args = catalog89_update_args.parse_args()
	product = catalog.query.get(args['item_id'])
	if not product :
		return "book does not exsist"
	product.number_in_stock = product.number_in_stock + 1
	db.session.commit()
	return product_schema.jsonify(product)

@app.route('/delete_book/<id>', methods=['DELETE'])
def delete_product(id):
  product = catalog.query.get(id)
  if not product:
	  return jsonify({'message' : 'book does not exsit!'})
  db.session.delete(product)
  db.session.commit()

  return product_schema.jsonify(product)

@app.route('/new_book/<id>', methods=['POST'])
def add_product(id):

  number_in_stock = request.json['number_in_stock']
  cost = request.json['cost']
  topic = request.json['topic']
  titel = request.json['titel']
  product = catalog.query.get(id)
  if (not cost) or  (not topic) or   (not titel) or  (not number_in_stock) :
	  return "please enter cost and topic and titel and number_in_stock in  body in json format"
  if product:
	  return "already existing  book"
  new_product = catalog(item_id=id,cost=cost, topic=topic, titel=titel, number_in_stock=number_in_stock)
  db.session.add(new_product)
  db.session.commit()
  return product_schema.jsonify(new_product)

@app.route('/lookup', methods=['GET'])
def get_product_byid():
	catalog89_update_args = reqparse.RequestParser()
	catalog89_update_args.add_argument("item_id", type=str, help="#id")
	args = catalog89_update_args.parse_args()
	product = catalog.query.get( args['item_id'])
	if not product :
		return " does not  exists" ,404
	return product_schema.jsonify(product)

@app.route('/search', methods=['GET'])
def get_product_bytopic():
	catalog89_update_args = reqparse.RequestParser()
	catalog89_update_args.add_argument("topic", type=str, help="#id")
	args = catalog89_update_args.parse_args()

	all_products = catalog.query.filter_by(topic=args['topic']).all()
	if not all_products :
	  return "no such topic"
	#result = products_schema.dump(all_products)
	output = {}
	for booky in all_products:
		output[booky.titel]=booky.item_id

	return jsonify({'items' : output})

@app.route('/updatecost_by_json/<id>', methods=['PUT'])
def update_product_cost_by_json(id):
  product = catalog.query.get(id)
  if( not product):
	  return "no  such book like that"

  catalog_update_args2 = reqparse.RequestParser()
  catalog_update_args2.add_argument("cost", type=int, help="#id")
  args = catalog_update_args2.parse_args()
  if not args['cost'] :
	  return " please spesify cost as json object"
  cost = request.json['cost']
  if(cost<0) :
	  return "cosst can not be nagative"

  product.cost = cost
  db.session.commit()
  return product_schema.jsonify(product)

@app.route('/updatecost_by_url/<id>/<cost>', methods=['PUT'])
def update_product_cost_url(id,cost):
  product = catalog.query.get(id)
  if( not product):
	  return "no  such book like that"
  if(cost <0):
	  return "cost can not be  negative"
  product.cost = cost
  db.session.commit()
  return product_schema.jsonify(product)
@app.route('/updatetopicbyjson/<id>', methods=['PUT'])
def update_product_topic_by_json(id):
  product = catalog.query.get(id)
  if( not product):
	  return "no  such book like that"

  catalog_update_args2 = reqparse.RequestParser()
  catalog_update_args2.add_argument("topic", type=str, help="#id")
  args = catalog_update_args2.parse_args()
  if not args['topic'] :
	  return " please spesify topic as json object"
  topic = request.json['topic']
  product.topic = topic
  db.session.commit()
  return product_schema.jsonify(product)

@app.route('/updatetopic_by_url/<id>/<topic>', methods=['PUT'])
def update_product_topic_url(id,topic):
  product = catalog.query.get(id)
  if( not product):
	  return "no  such book like that"

  product.topic = topic
  db.session.commit()
  return product_schema.jsonify(product)

if __name__ == "__main__":
	app.run(host="0.0.0.0", debug=True, port="6000")


# -*- coding: utf-8 -*-
"""
Created on Wed May 22 22:24:06 2019

@author: MPAZ
"""

import ccxt
import claves

#ACCESAR A BINANCE
usuario=claves.api_key
clave=claves.secret

#instancia mediante id a Binance con claves
exchange_id= 'binance'
exchange_class = getattr(ccxt, exchange_id)
exchange= exchange_class({
	'apiKey':usuario,
	'secret':clave,
	'timeout':30000,
	'enableRateLimit:': True,
})

casas_cambio=ccxt.exchanges
mercados=exchange.load_markets(True)
monedas= exchange.currencies
simbolos=exchange.symbols
metodos=dir(exchange)

print("empezamos")

saldob1=exchange.fetch_balance()['ETC']['free']
saldoq1=exchange.fetch_balance()['SKY']['free']

#ordenes_cerradas=exchange.fetch_closed_orders(par1) # LISTADO ORDENES CERRADAS
print("ORDEN CERRADA !!! ")

#prueba3=exchange.fetch_my_trades(par1)


"""
Helper functions for scoring best-worst trials. Provides various options for
scoring data, including Elo, Rescorla-Wagner, Value Scoring, and various
count-based methods. See README.txt for further info on the scoring methods.

Created by Geoff Hollis
http://www.ualberta.ca/~hollis
hollis at ualberta dot ca

This software is released under the Creative Commons licence:
  Attribution-NonCommerical-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
  https://creativecommons.org/licenses/by-nc-sa/4.0/

For published academic research using these tools, please cite:
  Hollis, G. (2017). Scoring best/worst data in unbalanced, many-item designs,
    with applications to crowdsourcing semantic judgments. Behavior Research
    Methods, XX(X), 1-19. doi: 10.3758/s13428-017-0898-2
"""
import random, math
from spreadsheet import Spreadsheet

################################################################################
# VARIABLES
################################################################################

# A table mapping the names of scoring methods to their appropriate function
# calls.
scoring_methods = {
    # data taken from TRIALS
    "Best"           : lambda item: item.best,
    "Worst"          : lambda item: item.worst,
    "Unchosen"       : lambda item: item.trials - item.best - item.worst,
    "BestWorst"      : lambda item: item.bestworst_score(),
    "BestWorstLogit" : lambda item: item.bestworst_score(),
    "ABW"            : lambda item: item.abw_score(),
    "David"          : lambda item: item.david_unbalanced_score(),

    # data taken from PAIRINGS
    "Wins"         : lambda item: item.wins,
    "Losses"       : lambda item: item.losses,
    "Ties"         : lambda item: item.unranked,
    "WinLoss"      : lambda item: item.winloss_norm_score(),
    "WinLossLogit" : lambda item: item.winloss_logit_score(),

    # Tournament methods, data taken from PAIRINGS
    "Elo"          : lambda item: item.elo,
    "Value"        : lambda item: item.value,
    "RW"           : lambda item: item.reswag_score(),
    "EloLogit"     : lambda item,eloMax,eloMin: item.elo_logit_score(eloMin,eloMax),
    "ValueLogit"   : lambda item: item.value_logit_score(),
    "RWLogit"      : lambda item: item.reswag_logit_score(),
    }

################################################################################
# CLASSES
################################################################################
class ItemEntry(object):
    """Contains an entry for a single item in your best-worst experiment. Used
       for tracking wins, losses, and ratings for various scoring methods.
    """
    def __init__(self, entity, base=0):
        self.entity = entity

        # for elo scoring
        self.elo    = base

        # for win-loss SCORING
        self.wins   = 0
        self.losses = 0

        # for win-loss COUNTING
        self.trials  = 0
        self.best    = 0
        self.worst   = 0
        self.unranked= 0

        # for value scoring
        self.value = 0.5

        # for rescorla-wagner scoring
        self.reswag_win  = 0.0
        self.reswag_lose = 0.0

        # opponents beat and lost to
        self.beat        = set()
        self.lose        = set()

    def win(winner, loser, iteration=1):
        winner.win_elo(loser, iteration)
        winner.win_value_discrim(loser, iteration)
        winner.win_reswag(loser, iteration)

        winner.beat.add(loser)
        loser.lose.add(winner)

    def win_value_discrim(winner, loser, iteration):
        """Update Value Score based on win/loss
        """
        rate = 0.025 / iteration

        rwin = winner.value / (1.0 - winner.value)
        rlos = loser.value  / (1.0 - loser.value)
        salience = 1.0 - rwin / (rwin + rlos)

        # handle the rescorla-wagner updates
        Dw = salience * rate * (1.0 - winner.value)
        Dl = salience * rate * (0   - loser.value)
        winner.value += Dw
        loser.value  += Dl

    def win_reswag(winner, loser, iteration):
        """Updates Rescrola-Wagner scores based on win/loss
        """
        # set the rate of learning.
        rate = 0.025 / iteration

        # calculate total association strengths
        w_v_tot = winner.reswag_win + winner.reswag_lose
        l_v_tot = loser.reswag_win + loser.reswag_lose

        # calculate the probabily of winning for each player --
        # 50/50 in the case of no exposure
        try:
            w_pwin = winner.reswag_win / w_v_tot
        except:
            w_pwin = 0.5
        try:
            l_pwin = loser.reswag_win  / l_v_tot
        except:
            l_pwin = 0.5

        # calculate the salience of the outcome
        rwin = w_pwin / max(0.0001, (1.0 - w_pwin))
        rlos = l_pwin  / max(0.0001, (1.0 - l_pwin))
        try:
            salience = 1.0 - rwin / (rwin + rlos)
        except:
            salience = 1.0
        w_salience = salience
        l_salience = salience

        # handle the rescorla-wagner updates
        winner.reswag_win += w_salience * rate * (1.0 - w_v_tot)
        loser.reswag_lose += l_salience * rate * (1.0 - l_v_tot)

    def win_elo(winner, loser, iteration):
        """Updates Elo scores based on win/loss
        """
        winner.wins  += 1
        loser.losses += 1

        Qw = 10 ** (winner.elo / 400.)
        Ql = 10 ** (loser.elo / 400.)
        Ew = Qw / (Qw + Ql)
        delta = float(30.0 * (1. - Ew))
        winner.elo += delta
        loser.elo  -= delta

    ############################################################################
    # SCORING FUNCTIONS
    ############################################################################
    def david_unbalanced_score(self):
        """Calculates the score proposed by H. David (1987)
        """
        wsum = sum([opp.wins for opp in self.beat])
        lsum = sum([opp.losses for opp in self.lose])
        return wsum - lsum

    def winloss_norm_score(self):
        # should range between [-1, 1]
        winloss = (self.wins - self.losses) / max(1.0, float(self.wins + self.losses + self.unranked))

        # normalize to [0, 1]
        winloss = (winloss + 1.0) / 2.0
        return winloss

    def winloss_logit_score(self):
        wln = self.winloss_norm_score()

        # to avoid div0 errors
        wln = min(max(wln, 0.0001), 0.9999)
        return math.log(winloss / (1.0-winloss))

    def bestworst_score(self):
        """normalized bestworst score"""
        # scales between [-1, 1]
        bestworst = (self.wins - self.losses) / float(self.trials)

        # rescale to [0, 1]
        return (bestworst + 1.0) / 2.0

    def bestworst_logit_score(self):
        bw = self.bestworst_score()
        # avoid div0 errors
        bw = min(max(bw, 0.0001), 0.9999)
        return math.log(bw/(1.0-bw))

    def abw_score(self):
        """calculates analytic best-worst score (Marley, Islam, & Hawkins, 2016)
        """
        ratio = (self.best - self.worst) / float(self.trials)
        # to avoid div0 errors
        ratio = min(max(ratio, -0.9999), 0.9999)

        NUM = 1.0 + ratio
        DEN = 1.0 - ratio
        return math.log(NUM/DEN)

    def value_logit_score(self):
        # to avoid div0 errors
        value = min(max(self.value,0.0001), 0.9999)
        return math.log(value/(1.0-value))

    def reswag_score(self):
        """calculates rescorla-wagner score based on associations with win
           and loss outcomes
        """
        if self.reswag_win + self.reswag_lose == 0:
            win_weight = 0.5
        else:
            win_weight = self.reswag_win / (self.reswag_win + self.reswag_lose)
        return win_weight

    def reswag_logit_score(self):
        """logit-adjusted rescorla-wagner score
        """
        rw = self.reswag_score()
        # to avoid div0 errors
        rw = min(max(rw, 0.0001), 0.9999)
        return math.log(rw/(1.0-rw))

    def elo_logit_score(self, eloMin, eloMax):
        """Calculates the logit elo value after scaling between min and max
           elo values.
        """
        scaleelo = (self.elo - eloMin) / (eloMax-eloMin)
        # avoid div0 errors
        scaleelo = min(max(scaleelo, 0.0001), 0.9999)
        return math.log(scaleelo / (1.0 - scaleelo))

################################################################################
# SUPPORT FUNCTIONS
################################################################################
def parse_bestworst_data(file, bestCol="best", worstCol="worst", sep=None):
    """parses best-worst data from file, where each trial is returned as tuple:
         (best, worst, (unchosen1, unchosen2, ..., unchosen[K-2]))

       A list of parsed trials is returned.
    """
    # figure out our seperator first
    if sep == None and file.endswith(".tsv"):
        sep = "\t"
    elif sep == None:
        sep = ","

    # read in the trials
    ss = Spreadsheet.read_csv(file, delimiter=sep)
    trials = [ ]
    for row in ss:
        # read best and worst choices
        best  = row[bestCol]
        worst = row[worstCol]
        opts  = [ ]

        # read all options that were choosable
        i = 1
        while True:
            col = "option%d" % i
            if col in ss.header:
                opts.append(row[col])
                i  += 1
            else:
                break

        # strip best and worst choices from the list of other options
        if best in opts:
            opts.remove(best)
        if worst in opts:
            opts.remove(worst)

        trials.append((best, worst, tuple(opts)))

    # return the parsed trials
    return trials

def compile_pairings(trials):
    """Takes a list of trials in the format (best, worst, (others)) and
       generates win/loss pairings based on the trial. Pairings are always
       returned as a tuple in the format (winner, loser)
    """
    pairings = [ ]
    for trial in trials:
        best, worst, others = trial

        pairings.append((best,worst))
        for other in others:
            pairings.append((best,other))
            pairings.append((other,worst))
    return pairings

def run_error_correction_scoring(item_data, pairings, iters=100):
    """run our various error-correction scoring methods on entries in item_data
       according to the (winner, loser) pairings supplied. Makes changes to
       item_data in place, and returns the results as well.
    """
    # repeat iter number of times
    for i in range(iters):
        # shuffle our data to eliminate order effects
        random.shuffle(pairings)

        # register a pairing in the item data
        for winner,loser in pairings:
            winner_data, loser_data = item_data[winner], item_data[loser]
            winner_data.win(loser_data, iteration=(i+1))

    # values were updated in-place; return original data structure
    return item_data

def score_trials(trials, methods, iters=100, dummy=True):
    """The wrapper function for scoring trials. Parameters are:
         iters   = for error-correction methods (elo, Value, RescorlaWagner),the
                   number of iterations over the data to perform when scoring.
         dummy   = Whether always-win and always-lose dummy players should be
                   added to keep items in a bounded range for error-correction
                   methods. Highly suggested.
         methods = The different scoring methods to apply.
    """
    # first, extract out all of our unique items
    items = set()
    for trial in trials:
        best, worst, others = trial
        items.add(best)
        items.add(worst)
        for other in others:
            items.add(other)

    # create data for each item
    item_data = { }
    for item in items:
        item_data[item] = ItemEntry(item)

    # calculate scores from count-based methods
    for trial in trials:
        winner, loser, others      = trial
        item_data[winner].best    += 1
        item_data[loser].worst    += 1
        for item in (winner, loser) + others:
            item_data[item].trials += 1
        # track how many unranked MATCHES (not TRIALS) we had, used for
        # PAIRINGS methods
        for item in others:
            item_data[item].unranked += len(others)-1

    # now that count-based methods are done, use error-correction methods for
    # scoring. We need to reformat trials into a series of pairings where we
    # know winners and losers, and then calculate scores based on match wins
    # and losses. See Hollis (2017; reference in file header) for details.

    # generate pairings from trials
    pairings = compile_pairings(trials)

    # if we have dummy players, add those as well. Also add pairings for each
    # item and the two dummies.
    if dummy == True:
        BEST_WINNER = object()
        WORST_LOSER = object()
        item_data[BEST_WINNER] = ItemEntry(BEST_WINNER)
        item_data[WORST_LOSER] = ItemEntry(WORST_LOSER)
        for item in items:
            pairings.append([BEST_WINNER, item])
            pairings.append([item, WORST_LOSER])

    # apply our various error-correction scoring methods
    item_data = run_error_correction_scoring(item_data, pairings, iters=iters)
    return item_data