#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bottle import Bottle, HTTPResponse, template
from configs.middlewares import logs, headers
from configs.constants import CONSTANTS
from configs.helpers import load_css, load_js
from helpers.error_helper import access_css, access_js

route = Bottle()
# install middlewares
route.install(logs)
route.install(headers)

@route.route('/access/<num_error>', method='GET')
def access(num_error):
    helpers = {}
    helpers['css'] = load_css(access_css())
    helpers['js'] = load_js(access_js())
    errores = {
        '404': {
            'mensaje': 'Archivo no encontrado',
            'numero': '404',
            'descripcion': 'La página que busca no se'
            + ' encuentra en el servidor',
        },
        '505': {
            'mensaje': 'Acceso restringido',
            'numero': '505',
            'descripcion': 'Necesita estar logueado',
        },
    }
    if num_error[0] != '4':
        num_error == 500
    else:
        num_error = int(num_error)
    locals = {
        'constants': CONSTANTS,
        'title': 'Error',
        'mensaje': errores[str(num_error)]['mensaje'],
        'numero': errores[str(num_error)]['numero'],
        'descripcion': errores[str(num_error)]['descripcion'],
    }
    boby_template = template(
        'templates/error/access',
        locals=locals,
        helpers=helpers
    )
    return HTTPResponse(status=num_error, body=boby_template)


# Determines input read criterion
from sys import stdin
JUDGE = 0
FILE = 1
INPUT_SRC = FILE
#INPUT_SRC = JUDGE
if INPUT_SRC == FILE:
 inputSrc = open("599.txt", "r")
else:
 inputSrc = stdin

num_cases = int(inputSrc.readline().strip())
for c in range(num_cases):
  forest = [-1] * 26
  partition_id = 0
  while True:
    line = inputSrc.readline().strip()
    print (line)
    if line[0] == "*":
      line = inputSrc.readline().strip().split(",")

      # Report here
      print (forest)
      print (len(line))
      print (sum(x > 0 for x in forest))
      print (set(forest))
      num_acorns = len(line) - sum(x > 0 for x in forest)
      num_trees = len(set(forest)) - 1
      print("There are {} tree(s) and {} acorn(s).".format(num_trees, num_acorns))
      break
    else:
      print (line[1])
      u = ord(line[1]) - ord('A')
      v = ord(line[3]) - ord('A')
      print (u,v)
      if forest[u] == -1:
        if forest[v] == -1:
          partition_id += 1
          forest[u] = forest[v] = partition_id
        else:
          forest[u] = forest[v]
      else:
        if forest[v] == -1:
          forest[v] = forest[u]
        else:
          temp = forest[u]
          for i in range(len(forest)):
            if forest[i] == temp:
              forest[i] = forest[v]


from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

driver.get("http://www.learnwebservices.com/locations/server/")

coordinates = driver.find_element(By.XPATH, "/html/body/div/table/tbody[2]/tr[578]/td[3]").text
print(coordinates)
print(type(coordinates))

driver.close()


import pytest
import numpy as np
import os
import sys
import pyCGM_Single.pyCGM_Helpers as pyCGM_Helpers
import pyCGM_Single.pycgmStatic as pycgmStatic
import pyCGM_Single.pycgmIO as pycgmIO
import pyCGM_Single.pycgmCalc as pycgmCalc

rounding_precision = 6

class TestPycgmStaticUtils():
    """
    This class tests the utils functions in pycgmStatic.py:
    rotmat
    getDist
    getStatic
    average
    IADcalculation
    headoffCalc
    staticCalculation
    getankleangle
    norm2d
    norm3d
    normDiv
    matrixmult
    cross
    """
    nan_3d = [np.nan, np.nan, np.nan]
    rand_coor = [np.random.randint(0, 10), np.random.randint(0, 10), np.random.randint(0, 10)]

    @pytest.mark.parametrize(["x", "y", "z", "expected_results"], [
        (0.0, 0.0, 180, [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]),
        (0, 0, 0, [[1, 0, 0], [0, 1, 0], [0, 0, 1]]),
        (90, 0, 0, [[1, 0, 0], [0, 0, -1], [0, 1, 0]]),
        (0, 135, 0, [[-0.70710678, 0, 0.70710678], [0, 1, 0], [-0.70710678, 0, -0.70710678]]),
        (0, 0, -60, [[0.5, 0.8660254, 0], [-0.8660254, 0.5, 0], [0, 0, 1]]),
        (90, 0, 90, [[0, -1, 0], [0, 0, -1], [1, 0, 0]]),
        (0, 150, -30, [[-0.75, -0.4330127, 0.5], [-0.5, 0.8660254, 0], [-0.4330127, -0.25, -0.8660254]]),
        (90, 180, -90, [[0, -1, 0], [0, 0, 1], [-1, 0, 0]])])
    def test_rotmat(self, x, y, z, expected_results):
        """
        This test provides coverage of the rotmat function in pycgmStatic.py, defined as rotmat(x, y, z)
        where x, y, and z are all floats that represent the angle of rotation in a particular dimension.

        This test takes 4 parameters:
        x: angle to be rotated in the x axis
        y: angle to be rotated in the y axis
        z: angle to be rotated in the z axis
        expected_results: the expected rotation matrix from calling rotmat on x, y, and z. This will be a transformation
        matrix that can be used to perform a rotation in the x, y, and z directions at the values inputted.
        """
        result = pycgmStatic.rotmat(x, y, z)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_rotmat_datatypes(self):
        """
        This test provides coverage of the rotmat function in pycgmStatic.py, defined as rotmat(x, y, z)
        where x, y, and z are all floats that represent the angle of rotation in a particular dimension.

        This test checks that the resulting output from calling rotmat is correct when called with ints or floats.
         """
        result_int = pycgmStatic.rotmat(0, 150, -30)
        result_float = pycgmStatic.rotmat(0.0, 150.0, -30.0)
        expected_results = [[-0.75, -0.4330127, 0.5], [-0.5, 0.8660254, 0], [-0.4330127, -0.25, -0.8660254]]

        np.testing.assert_almost_equal(result_int, expected_results, rounding_precision)
        np.testing.assert_almost_equal(result_float, expected_results, rounding_precision)

    @pytest.mark.parametrize(["p0", "p1", "expected_results"], [
        ([0, 0, 0], [1, 0, 0], 1),
        ([0, 5, 0], [0, 0, 0], 5),
        ([0, 0, 0], [0, 0, -8], 8),
        ([0, 0, 0], [0, 3, 4], 5),
        ([8, 0, -3], [0, 0, 0], 8.54400374531753),
        ([0, 4, 0], [0, 0, 2], 4.47213595499958),
        ([1, 0, 3], [0, -2, 8], 5.477225575051661),
        ([3, 3, 0], [3, 0, 3], 4.242640687119285),
        ([7, 0, -4], [7, 0, 2], 6),
        ([7, -2, 5], [1, -4, 9], 7.483314773547883)])
    def test_getDist(self, p0, p1, expected_results):
        """
        This test provides coverage of the getDist function in pycgmStatic.py, defined as getDist(p0, p1)

        This test takes 3 parameters:
        p0: position of first x,y,z coordinate
        p1: position of second x,y,z coordinate
        expected_results: the expected result from calling getDist on p0 and p1. This will be the distance between p0 and p1

        Given the points p0 and p1, the distance between them is defined as:
        .. math::
            distance = \sqrt{(p0_x-p1_x)^2 + (p0_y-p1_y)^2 + (p0_z-p1_z)^2}
        where :math:`p0_x` is the x-coordinate of the point p0

        This unit test ensures that:
        - the distance is measured correctly when some coordinates are the same, all coordinates are the same, and all
        coordinates are different
        - the distance is measured correctly given positive, negative and zero values
        """
        result = pycgmStatic.getDist(p0, p1)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_getDist_datatypes(self):
        """
        This test provides coverage of the getDist function in pycgmStatic.py, defined as getDist(p0, p1)

        This test checks that the resulting output from calling getDist is correct when called with a list of ints,
        a numpy array of ints, a list of floats, and a numpy array of floats.
        """
        p0_int = [7, -2, 5]
        p1_int = [1, -4, 9]
        p0_float = [7.0, -2.0, 5.0]
        p1_float = [1.0, -4.0, 9.0]
        expected_results = 7.483314773547883

        # Check that calling getDist on a list of ints yields the expected results
        result_int_list = pycgmStatic.getDist(p0_int, p1_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling getDist on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.getDist(np.array(p0_int, dtype='int'), np.array(p1_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling getDist on a list of floats yields the expected results
        result_float_list = pycgmStatic.getDist(p0_float, p1_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling getDist on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.getDist(np.array(p0_float, dtype='float'), np.array(p1_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["list", "expected_results"], [
        ([0], 0),
        ([3], 3),
        ([-1], -1),
        ([1, 2], 1.5),
        ([-1, 3], 1),
        ([-3, 1], -1),
        ([-2, 0, 2], 0),
        ([1, 2, 3, 4, 5], 3),
        ([-1, -2, -3, -4, -5], -3),
        ([0.1, 0.2, 0.3, 0.4, 0.5], 0.3)])
    def test_average(self, list, expected_results):
        """
        This test provides coverage of the average function in pycgmStatic.py, defined as average(list)

        This test takes 2 parameters:
        list: list or array of values
        expected_results: the expected result from calling average on list. This will be the average of all the values given in list
        """
        result = pycgmStatic.average(list)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_average_datatypes(self):
        """
        This test provides coverage of the average function in pycgmStatic.py, defined as average(list)

        This test checks that the resulting output from calling average is correct when called with a list of ints,
        a numpy array of ints, a list of floats, and a numpy array of floats.
        """
        list_int = [-1, -2, -3, -4, -5]
        list_float = [-1.0, -2.0, -3.0, -4.0, -5.0]
        expected_results = -3

        # Check that calling average on a list of ints yields the expected results
        result_int_list = pycgmStatic.average(list_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling average on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.average(np.array(list_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling average on a list of floats yields the expected results
        result_float_list = pycgmStatic.average(list_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling average on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.average(np.array(list_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["frame", "expected_results"], [
        ({'RASI': np.array([0, 0, 0]), 'LASI': np.array([0, 0, 0])}, 0),
        ({'RASI': np.array([1, 0, 0]), 'LASI': np.array([0, 0, 0])}, 1),
        ({'RASI': np.array([0, 0, 0]), 'LASI': np.array([2, 0, 0])}, 2),
        ({'RASI': np.array([0, 1, 0]), 'LASI': np.array([0, 1, 0])}, 0),
        ({'RASI': np.array([4, 0, 0]), 'LASI': np.array([2, 0, 0])}, 2),
        ({'RASI': np.array([4, 0, 0]), 'LASI': np.array([-2, 0, 0])}, 6),
        ({'RASI': np.array([0, 2, 1]), 'LASI': np.array([0, 4, 1])}, 2),
        ({'RASI': np.array([-5, 3, 0]), 'LASI': np.array([0, 3, 0])}, 5),
        ({'RASI': np.array([0, 3, -6]), 'LASI': np.array([0, 2, -5])}, 1.4142135623730951),
        ({'RASI': np.array([-6, 4, 0]), 'LASI': np.array([0, 6, -8])}, 10.198039027185569),
        ({'RASI': np.array([7, 2, -6]), 'LASI': np.array([3, -7, 2])}, 12.68857754044952),
        # Testing that when frame is composed of lists of ints
        ({'RASI': [7, 2, -6], 'LASI': [3, -7, 2]}, 12.68857754044952),
        # Testing that when frame is composed of numpy arrays of ints
        ({'RASI': np.array([7, 2, -6], dtype='int'), 'LASI': np.array([3, -7, 2], dtype='int')}, 12.68857754044952),
        # Testing that when frame is composed of lists of floats
        ({'RASI': [7.0, 2.0, -6.0], 'LASI': [3.0, -7.0, 2.0]}, 12.68857754044952),
        # Testing that when frame is composed ofe numpy arrays of floats
        ({'RASI': np.array([7.0, 2.0, -6.0], dtype='float'), 'LASI': np.array([3.0, -7.0, 2.0], dtype='float')}, 12.68857754044952)])
    def test_IADcalculation(self, frame, expected_results):
        """
        This test provides coverage of the IADcalculation function in pycgmStatic.py, defined as IADcalculation(frame)

        This test takes 2 parameters:
        frame: dictionary of marker lists
        expected_results: the expected result from calling IADcalculation on frame. This is the Inter ASIS Distance
        (IAD), or the distance between the two markers RASI and LASI in frame.

        Given the markers RASI and LASI in frame, the Inter ASIS Distance is defined as:
        .. math::
            InterASISDist = \sqrt{(RASI_x-LASI_x)^2 + (RASI_y-LASI_y)^2 + (RASI_z-LASI_z)^2}
        where :math:`RASI_x` is the x-coordinate of the RASI marker in frame

        This unit test ensures that:
        - the distance is measured correctly when some coordinates are the same, all coordinates are the same, and all
        coordinates are different
        - the distance is measured correctly given positive, negative and zero values
        - the resulting output is correct when frame is composed of lists of ints, numpy arrays of ints, lists of
        floats, and numpy arrays of floats.
        """
        result = pycgmStatic.IADcalculation(frame)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    @pytest.mark.parametrize(["xRot", "yRot", "zRot", "expected_results"], [
        (0, 0, 0, [0]),
        # X rotations
        (90, 0, 0, [0]), (30, 0, 0, [0]), (-30, 0, 0, [0]), (120, 0, 0, [0]), (-120, 0, 0, [0]), (180, 0, 0, [0]),
        # Y rotations
        (0, 90, 0, [-1.570796]), (0, 30, 0, [-0.523599]), (0, -30, 0, [0.523599]), (0, 120, 0, [1.047198]), (0, -120, 0, [-1.047198]), (0, 180, 0, [0]),
        # Z rotations
        (0, 0, 90, [0]), (0, 0, 30, [0]), (0, 0, -30, [0]), (0, 0, 120, [0]), (0, 0, -120, [0]), (0, 0, 180, [0]),
        # Multiple Rotations
        (150, 30, 0, [-0.523599]), (45, 0, 60, [0.713724]), (0, 90, 120, [1.570796]), (135, 45, 90, [-0.955317])])
    def test_headoffCalc(self, xRot, yRot, zRot, expected_results):
        """
        This test provides coverage of the headoffCalc function in pycgmStatic.py, defined as headoffCalc(axisP, axisD)

        This test takes 3 parameters:
        axisP: the unit vector of axisP, the position of the proximal axis
        axisD: the unit vector of axisD, the position of the distal axis
        expected_results: the expected result from calling headoffCalc on axisP and axisD. This returns the y-rotation
        from a rotational matrix calculated by matrix multiplication of axisD and the inverse of axisP. This angle is in
        radians, not degrees.

        The y angle is defined as:
        .. math::
            \[ result = \arctan{\frac{M[0][2]}{M[2][2]}} \]
        where M is the rotation matrix produced from multiplying axisD and :math:`axisP^{-1}`

        This unit test ensures that:
        - Rotations in only the x or z direction will return a angle of 0
        - Rotations in only the y direction will return the same angle
        - Rotations in multiple axes will return a value based off of the all the rotations used in the rotation matrix
        """
        # Create axisP as a rotational matrix using the x, y, and z rotations given
        axisP = pycgmStatic.rotmat(xRot, yRot, zRot)
        axisD = pycgmStatic.rotmat(0, 0, 0)
        result = pycgmStatic.headoffCalc(axisP, axisD)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_headoffCalc_datatypes(self):
        """
        This test provides coverage of the headoffCalc function in pycgmStatic.py, defined as headoffCalc(axisP, axisD)

        This test checks that the resulting output from calling headoffCalc is correct when called with a list of ints,
        a numpy array of ints, a list of floats, and a numpy array of floats.
        """
        axisD = pycgmStatic.rotmat(0, 0, 0)
        axisP_floats = pycgmStatic.rotmat(90, 90, 90)
        axisP_ints = [[int(y) for y in x] for x in axisP_floats]
        expected_results = [1.570796]

        # Check that calling headoffCalc on a list of ints yields the expected results
        result_int_list = pycgmStatic.headoffCalc(axisP_ints, axisD)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling headoffCalc on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.headoffCalc(np.array(axisP_ints, dtype='int'), np.array(axisD, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling headoffCalc on a list of floats yields the expected results
        result_float_list = pycgmStatic.headoffCalc(axisP_floats, axisD)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling headoffCalc on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.headoffCalc(np.array(axisP_floats, dtype='float'), np.array(axisD, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["frame", "ankle_JC", "flat_foot", "vsk", "expected_results"], [
        # Test from running sample data
        ({'RTOE': np.array([433.33508301, 354.97229004, 44.27765274]),
          'LTOE': np.array([31.77310181, 331.23657227, 42.15322876]),
          'RHEE': np.array([381.88534546, 148.47607422, 49.99120331]),
          'LHEE': np.array([122.18766785, 138.55477905, 46.29433441])},
         [np.array([397.45738291, 217.50712216, 87.83068433]), np.array([112.28082818, 175.83265027, 80.98477997]),
          [[np.array(rand_coor), np.array([396.73749179, 218.18875543, 87.69979179]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([111.34886681, 175.49163538, 81.10789314]), np.array(rand_coor)]]],
         False,
         {},
         [[-0.015688860223839234, 0.2703999495115947, -0.15237642705642993],
          [0.009550866847196991, 0.20242596489042683, -0.019420801722458948]]),
        # Testing with zeros for all params
        ({'RTOE': np.array([0, 0, 0]), 'LTOE': np.array([0, 0, 0]),
          'RHEE': np.array([0, 0, 0]), 'LHEE': np.array([0, 0, 0])},
         [np.array([0, 0, 0]), np.array([0, 0, 0]),
          [[np.array(rand_coor), np.array([0, 0, 0]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([0, 0, 0]), np.array(rand_coor)]]],
         False,
         {},
         [nan_3d, nan_3d]),
        # Testing with values for frame
        ({'RTOE': np.array([1, -4, -1]), 'LTOE': np.array([1, -1, -5]),
          'RHEE': np.array([1, -7, -4]), 'LHEE': np.array([-6, -5, 1])},
         [np.array([0, 0, 0]), np.array([0, 0, 0]),
          [[np.array(rand_coor), np.array([0, 0, 0]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([0, 0, 0]), np.array(rand_coor)]]],
         False,
         {},
         [nan_3d, nan_3d]),
        # Testing with values for ankle_JC
        ({'RTOE': np.array([0, 0, 0]), 'LTOE': np.array([0, 0, 0]),
          'RHEE': np.array([0, 0, 0]), 'LHEE': np.array([0, 0, 0])},
         [np.array([3, 3, -2]), np.array([5, 9, -4]),
          [[np.array(rand_coor), np.array([6, -9, 9]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([-5, 6, 9]), np.array(rand_coor)]]],
         False,
         {},
         [nan_3d, nan_3d]),
        # Testing with values for vsk
        ({'RTOE': np.array([0, 0, 0]), 'LTOE': np.array([0, 0, 0]),
          'RHEE': np.array([0, 0, 0]), 'LHEE': np.array([0, 0, 0])},
         [np.array([0, 0, 0]), np.array([0, 0, 0]),
          [[np.array(rand_coor), np.array([0, 0, 0]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([0, 0, 0]), np.array(rand_coor)]]],
         False,
         {'RightSoleDelta': 0.64, 'LeftSoleDelta': 0.19},
         [nan_3d, nan_3d]),
        # Testing with values for frame and ankle_JC
        ({'RTOE': np.array([1, -4, -1]), 'LTOE': np.array([1, -1, -5]),
          'RHEE': np.array([1, -7, -4]), 'LHEE': np.array([-6, -5, 1])},
         [np.array([3, 3, -2]), np.array([5, 9, -4]),
          [[np.array(rand_coor), np.array([6, -9, 9]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([-5, 6, 9]), np.array(rand_coor)]]],
         False,
         {},
         [[-0.590828, -0.802097, -0.554384], [0.955226, 0.156745, 0.166848]]),
        # Testing with values for frame, ankle_JC, and vsk
        ({'RTOE': np.array([1, -4, -1]), 'LTOE': np.array([1, -1, -5]),
          'RHEE': np.array([1, -7, -4]), 'LHEE': np.array([-6, -5, 1])},
         [np.array([3, 3, -2]), np.array([5, 9, -4]),
          [[np.array(rand_coor), np.array([6, -9, 9]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([-5, 6, 9]), np.array(rand_coor)]]],
         False,
         {'RightSoleDelta': 0.64, 'LeftSoleDelta': 0.19},
         [[-0.590828, -0.802097, -0.554384], [0.955226, 0.156745, 0.166848]]),
        # Testing with values for frame, ankle_JC, vsk and flat_foot = True
        ({'RTOE': np.array([1, -4, -1]), 'LTOE': np.array([1, -1, -5]),
          'RHEE': np.array([1, -7, -4]), 'LHEE': np.array([-6, -5, 1])},
         [np.array([3, 3, -2]), np.array([5, 9, -4]),
          [[np.array(rand_coor), np.array([6, -9, 9]), np.array(rand_coor)],
           [np.array(rand_coor), np.array([-5, 6, 9]), np.array(rand_coor)]]],
         True,
         {'RightSoleDelta': 0.64, 'LeftSoleDelta': 0.19},
         [[0.041042018208567545, -0.3065439019577841, -0.3106927663413161], [0.39326377295256626, 0.5657243847333632, 0.2128595189127902]]),
        # Testing that when frame and ankle_JC are composed of lists of ints and vsk values are ints
        ({'RTOE': [1, -4, -1], 'LTOE': [1, -1, -5], 'RHEE': [1, -7, -4], 'LHEE': [-6, -5, 1]},
         [[3, 3, -2], [5, 9, -4],
          [[rand_coor, [6, -9, 9], rand_coor],
           [rand_coor, [-5, 6, 9], rand_coor]]],
         True,
         {'RightSoleDelta': 1, 'LeftSoleDelta': -1},
         [[0.041042018208567545, -0.30654390195778408, -0.30110158620693045],
          [00.3932637729525662, 0.56572438473336295, 0.22802611517428609]]),
        # Testing that when frame and ankle_JC are composed of numpy arrays of ints and vsk values are ints
        ({'RTOE': np.array([1, -4, -1], dtype='int'), 'LTOE': np.array([1, -1, -5], dtype='int'),
          'RHEE': np.array([1, -7, -4], dtype='int'), 'LHEE': np.array([-6, -5, 1], dtype='int')},
         [np.array([3, 3, -2], dtype='int'), np.array([5, 9, -4], dtype='int'),
          [np.array([rand_coor, [6, -9, 9], rand_coor], dtype='int'),
           np.array([rand_coor, [-5, 6, 9], rand_coor], dtype='int')]],
         True,
         {'RightSoleDelta': 1, 'LeftSoleDelta': -1},
         [[0.041042018208567545, -0.30654390195778408, -0.30110158620693045],
          [00.3932637729525662, 0.56572438473336295, 0.22802611517428609]]),
        # Testing that when frame and ankle_JC are composed of lists of floats and vsk values are floats
        ({'RTOE': [1.0, -4.0, -1.0], 'LTOE': [1.0, -1.0, -5.0], 'RHEE': [1.0, -7.0, -4.0], 'LHEE': [-6.0, -5.0, 1.0]},
         [[3.0, 3.0, -2.0], [5.0, 9.0, -4.0],
          [[rand_coor, [6.0, -9.0, 9.0], rand_coor],
           [rand_coor, [-5.0, 6.0, 9.0], rand_coor]]],
         True,
         {'RightSoleDelta': 1.0, 'LeftSoleDelta': -1.0},
         [[0.041042018208567545, -0.30654390195778408, -0.30110158620693045],
          [00.3932637729525662, 0.56572438473336295, 0.22802611517428609]]),
        # Testing that when frame and ankle_JC are composed of numpy arrays of floats and vsk values are floats
        ({'RTOE': np.array([1.0, -4.0, -1.0], dtype='float'), 'LTOE': np.array([1.0, -1.0, -5.0], dtype='float'),
          'RHEE': np.array([1.0, -7.0, -4.0], dtype='float'), 'LHEE': np.array([-6.0, -5.0, 1.0], dtype='float')},
         [np.array([3.0, 3.0, -2.0], dtype='float'), np.array([5.0, 9.0, -4.0], dtype='float'),
          [np.array([rand_coor, [6.0, -9.0, 9.0], rand_coor], dtype='float'),
           np.array([rand_coor, [-5.0, 6.0, 9.0], rand_coor], dtype='float')]],
         True,
         {'RightSoleDelta': 1.0, 'LeftSoleDelta': -1.0},
         [[0.041042018208567545, -0.30654390195778408, -0.30110158620693045],
          [00.3932637729525662, 0.56572438473336295, 0.22802611517428609]])])
    def test_staticCalculation(self, frame, ankle_JC, flat_foot, vsk, expected_results):
        """
        This test provides coverage of the staticCalculation function in pycgmStatic.py, defined as staticCalculation(frame, ankle_JC, knee_JC, flat_foot, vsk)

        This test takes 5 parameters:
        frame: dictionary of marker lists
        ankle_JC: array containing the x,y,z axes marker positions of the ankle joint center
        flat_foot: boolean indicating if the feet are flat or not
        vsk: dictionary containing subject measurements from a VSK file
        expected_results: the expected result from calling staticCalculation on frame, ankle_JC, flat_foot, and vsk

        This function first calculates the anatomically incorrect foot axis by calling uncorrect_footaxis. It then
        calculates the anatomically correct foot joint center and axis using either rotaxis_footflat or
        rotaxis_nonfootflat depending on if foot_flat is True or False. It then does some array manipulation and calls
        getankleangle with the anatomically correct and anatomically incorrect axes, once for the left and once for the
        right, to calculate the offset angle between the two axes.

        This test ensures that:
        - Different offset angles are returned depending on whether flat_foot is True or not
        - The resulting output is correct when frame and ankle_JC are composed of lists of ints, numpy arrays of ints,
        lists of floats, and numpy arrays of floats and when the vsk values are ints and floats.
        """
        result = pycgmStatic.staticCalculation(frame, ankle_JC, None, flat_foot, vsk)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    @pytest.mark.parametrize(["xRot", "yRot", "zRot", "expected_results"], [
        (0, 0, 0, [0, 0, 0]),
        # X rotations
        (90, 0, 0, [-1.570796, 0, 0]), (30, 0, 0, [-0.523599, 0, 0]), (-30, 0, 0, [0.523599, 0, 0]),
        (120, 0, 0, [-1.047198, 0, 0]), (-120, 0, 0, [1.047198, 0, 0]), (180, 0, 0, [0, 0, 0]),
        # Y rotations
        (0, 90, 0, [0, -1.570796, 0]), (0, 30, 0, [0, -0.523599, 0]), (0, -30, 0, [0, 0.523599, 0]),
        (0, 120, 0, [0, 1.047198, 0]), (0, -120, 0, [0, -1.047198, 0]), (0, 180, 0, [0, 0, 0]),
        # Z rotations
        (0, 0, 90, [0, 0, -1.570796]), (0, 0, 30, [0, 0, -0.523599]), (0, 0, -30, [0, 0, 0.523599]),
        (0, 0, 120, [0, 0, 1.047198]), (0, 0, -120, [0, 0, -1.047198]), (0, 0, 180, [0, 0, 0]),
        # Multiple Rotations
        (150, 30, 0, [-0.447832,  0.588003,  0.281035]), (45, 0, 60, [-0.785398, -0, -1.047198]),
        (0, 90, 120, [0, -1.570796,  1.047198]), (135, 45, 90, [-0.523599,  0.955317, -0.955317])])
    def test_getankleangle(self, xRot, yRot, zRot, expected_results):
        """
        This test provides coverage of the getankleangle function in pycgmStatic.py, defined as getankleangle(axisP, axisD)

        This test takes 3 parameters:
        axisP: the unit vector of axisP, the position of the proximal axis
        axisD: the unit vector of axisD, the position of the distal axis
        expected_results: the expected result from calling getankleangle on axisP and axisD. This returns the x, y, z angles
        from a XYZ Euler angle calculation from a rotational matrix. This rotational matrix is calculated by matrix
        multiplication of axisD and the inverse of axisP. This angle is in radians, not degrees.

        The x, y, and z angles are defined as:
        .. math::
            \[ x = \arctan{\frac{M[2][1]}{\sqrt{M[2][0]^2 + M[2][2]^2}}} \]
            \[ y = \arctan{\frac{-M[2][0]}{M[2][2]}} \]
            \[ z = \arctan{\frac{-M[0][1]}{M[1][1]}} \]
        where M is the rotation matrix produced from multiplying axisD and :math:`axisP^{-1}`

        This test ensures that:
        - A rotation in one axis will only effect the resulting angle in the corresponding axes
        - A rotation in multiple axes can effect the angles in other axes due to XYZ order
        """
        # Create axisP as a rotatinal matrix using the x, y, and z rotations given
        axisP = pycgmStatic.rotmat(xRot, yRot, zRot)
        axisD = pycgmStatic.rotmat(0, 0, 0)
        result = pycgmStatic.getankleangle(axisP, axisD)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_getankleangle_datatypes(self):
        """
        This test provides coverage of the getankleangle function in pycgmStatic.py, defined as getankleangle(axisP, axisD)

        This test checks that the resulting output from calling getankleangle is correct when called with a list of ints,
        a numpy array of ints, a list of floats, and a numpy array of floats.
        """
        axisD = pycgmStatic.rotmat(0, 0, 0)
        axisP_floats = pycgmStatic.rotmat(90, 90, 90)
        axisP_ints = [[int(y) for y in x] for x in axisP_floats]
        expected_results = [0, -1.570796, 0]

        # Check that calling getankleangle on a list of ints yields the expected results
        result_int_list = pycgmStatic.getankleangle(axisP_ints, axisD)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling getankleangle on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.getankleangle(np.array(axisP_ints, dtype='int'), np.array(axisD, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling getankleangle on a list of floats yields the expected results
        result_float_list = pycgmStatic.getankleangle(axisP_floats, axisD)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling getankleangle on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.getankleangle(np.array(axisP_floats, dtype='float'), np.array(axisD, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["v", "expected_results"], [
        ([-9944.089508486479, -20189.20612828088, 150.42955108569652], 22505.812344655435),
        ([0, 0, 0], 0),
        ([2, 0, 0], 2),
        ([0, 0, -1], 1),
        ([0, 3, 4], 5),
        ([-3, 0, 4], 5),
        ([6, -8, 0], 10),
        ([-5, 0, -12], 13),
        ([1, -1, np.sqrt(2)], 2)])
    def test_norm2d(self, v, expected_results):
        """
        This test provides coverage of the norm2d function in pycgmStatic.py, defined as norm2d(v) where v is a 3D vector.

        This test takes 2 parameters:
        v: 3D vector
        expected_results: the expected result from calling norm2d on v. This will be the value of the normalization of vector v,
        returned as a float.

        Given the vector v, the normalization is defined by:
        normalization = :math:`\sqrt{v_x^2 + v_y^2 + v_z^2}`
        where :math:`v_x` is the x-coordinate of the vector v
        """
        result = pycgmStatic.norm2d(v)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_norm2d_datatypes(self):
        """
        This test provides coverage of the norm2d function in pycgmStatic.py, defined as norm2d(v) where v is a 3D vector.

        This test checks that the resulting output from calling norm2d is correct when called with a list of ints, a
        numpy array of ints, a list of floats, and a numpy array of floats.
        """
        v_int = [6, 0, -8]
        v_float = [6.0, 0, -8.0]
        expected_results = 10

        # Check that calling norm2d on a list of ints yields the expected results
        result_int_list = pycgmStatic.norm2d(v_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling norm2d on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.norm2d(np.array(v_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling norm2d on a list of floats yields the expected results
        result_float_list = pycgmStatic.norm2d(v_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling norm2d on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.norm2d(np.array(v_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["v", "expected_results"], [
        ([-212.5847168, 28.09841919, -4.15808105], np.array(214.47394390603984)),
        ([0, 0, 0], np.array(0)),
        ([2, 0, 0], np.array(2)),
        ([0, 0, -1], np.array(1)),
        ([0, 3, 4], np.array(5)),
        ([-3, 0, 4], np.array(5)),
        ([-6, 8, 0], np.array(10)),
        ([-5, 0, -12], np.array(13)),
        ([1, -1, np.sqrt(2)], np.array(2))])
    def test_norm3d(self, v, expected_results):
        """
        This test provides coverage of the norm3d function in pycgmStatic.py, defined as norm3d(v) where v is a 3D vector.

        This test takes 2 parameters:
        v: 3D vector
        expected_results: the expected result from calling norm3d on v. This will be the normalization of the vector v,
        inside of a numpy array.

        Given the vector v, the normalization is defined by:
        normalization = :math:`\sqrt{v_x^2 + v_y^2 + v_z^2}`
        where :math:`v_x` is the x-coordinate of the vector v
        """
        result = pycgmStatic.norm3d(v)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_norm3d_datatypes(self):
        """
        This test provides coverage of the norm3d function in pycgmStatic.py, defined as norm3d(v) where v is a 3D vector.

        This test checks that the resulting output from calling norm3d is correct when called with a list of ints, a
        numpy array of ints, a list of floats, and a numpy array of floats.
        """
        v_int = [-6, 0, 8]
        v_float = [-6.0, 0, 8.0]
        expected_results = np.array(10)

        # Check that calling norm3d on a list of ints yields the expected results
        result_int_list = pycgmStatic.norm3d(v_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling norm3d on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.norm3d(np.array(v_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling norm3d on a list of floats yields the expected results
        result_float_list = pycgmStatic.norm3d(v_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling norm3d on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.norm3d(np.array(v_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["v", "expected_results"], [
        ([-212.5847168, 28.09841919, -4.15808105], np.array([-4.62150006e-03,  6.10847515e-04, -9.03948887e-05])),
        ([0, 0, 0], np.array([np.nan, np.nan, np.nan])),
        ([2, 0, 0], np.array([0.5, 0, 0])),
        ([0, 0, -1], np.array([0, 0, -1])),
        ([0, 3, 4], np.array([0, 0.12, 0.16])),
        ([-3, 0, 4], np.array([-0.12, 0, 0.16])),
        ([-6, 8, 0], np.array([-0.06, 0.08, 0])),
        ([-5, 0, -12], np.array([-0.0295858, 0, -0.07100592])),
        ([1, -1, np.sqrt(2)], np.array([0.25, -0.25, 0.35355339]))
    ])
    def test_normDiv(self, v, expected_results):
        """
        This test provides coverage of the normDiv function in pycgmStatic.py, defined as normDiv(v) where v is a 3D vector.
        This test takes 2 parameters:
        v: 3D vector
        expected_results: the expected result from calling norm3d on v. This function returns the wrong result. It is supposed
        to return the normalization division, but in the function divides the vector by the normalization twice.

        Given the vector v, the normalization is defined by:
        normalization = :math:`\sqrt{v_x^2 + v_y^2 + v_z^2}`
        where :math:`v_x` is the x-coordinate of the vector v

        The mathematically correct result would be defined by:
        .. math::
            \[ result = [\frac{v_x}{norm}, \frac{v_y}{norm}, \frac{v_z}{norm}] \]

        But this function has an error where it divides the vector twice:
        .. math::
            \[ result = [\frac{v_x}{norm^2}, \frac{v_y}{norm^2}, \frac{v_z}{norm^2}] \]
        """
        result = pycgmStatic.normDiv(v)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_normDiv_datatypes(self):
        """
        This test provides coverage of the normDiv function in pycgmStatic.py, defined as normDiv(v) where v is a 3D vector.

        This test checks that the resulting output from calling normDiv is correct when called with a list of ints, a
        numpy array of ints, a list of floats, and a numpy array of floats.
        """
        v_int = [-6, 0, 8]
        v_float = [-6.0, 0, 8.0]
        expected_results = np.array([-0.06, 0, 0.08])

        # Check that calling normDiv on a list of ints yields the expected results
        result_int_list = pycgmStatic.normDiv(v_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling normDiv on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.normDiv(np.array(v_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling normDiv on a list of floats yields the expected results
        result_float_list = pycgmStatic.normDiv(v_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling normDiv on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.normDiv(np.array(v_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["A", "B", "expected_results"], [
        ([[1, 0, 0], [0, 1.0, -0.0], [0, 0.0, 1.0]], [[1.0, 0, 0.0], [0, 1, 0], [-0.0, 0, 1.0]], [[1.0, 0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]),
        ([[1]], [[1]], [[1]]),
        # Invalid matrix dimensions
        ([[1, 2]], [[1]], [[1]]),
        ([[2], [1]], [[1, 2]], [[2, 4], [1, 2]]),
        # Invalid matrix dimensions
        ([[1, 2, 0], [0, 1, 2]], [[2, 1], [1, 4]], [[4, 9], [1, 4]]),
        ([[11, 12, 13], [14, 15, 16]], [[1, 2], [3, 4], [5, 6]], [[112, 148], [139, 184]]),
        ([[1, 2, 3], [4, 5, 6]], [[7, 8], [9, 10], [11, 12]], [[58, 64], [139, 154]])])
    def test_matrixmult(self, A, B, expected_results):
        """
        This test provides coverage of the matrixmult function in pyCGM.py, defined as matrixmult(a, b)
        where a and b are both lists that represent a matrix to be multiplied.

        This test takes 3 parameters:
        A: a matrix, 2D array format
        B: a matrix, 2D array format
        expected_results: the expected matrix from calling matrixmult on A and B. This is the result of multiplying the two
        matrices A and B. It gives the correct result for multiplying two valid matrices, but still gives a result
        in some cases when the two matrices can't be multiplied. For two matrices to be multiplied, len(A[0]) need to
        be equal to len(B), but this function gives an output even when this isn't true
        """
        result = pycgmStatic.matrixmult(A, B)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_matrixmult_datatypes(self):
        """
        This test provides coverage of the matrixmult function in pycgmStatic.py, defined as matrixmult(a, b)
        where a and b are both lists that represent a matrix to be multiplied.

        This test checks that the resulting output from calling matrixmult is correct when called with a list of ints,
        a numpy array of ints, a list of floats, and a numpy array of floats.
        """
        A_int = [[1, 2, 0], [0, 1, 2]]
        B_int = [[2, 1], [1, 4]]
        A_float = [[1.0, 2.0, 0.0], [0.0, 1.0, 2.0]]
        B_float = [[2.0, 1.0], [1.0, 4.0]]
        expected_results = [[4, 9], [1, 4]]

        # Check that calling matrixmult on a list of ints yields the expected results
        result_int_list = pycgmStatic.matrixmult(A_int, B_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling matrixmult on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.matrixmult(np.array(A_int, dtype='int'), np.array(B_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling matrixmult on a list of floats yields the expected results
        result_float_list = pycgmStatic.matrixmult(A_float, B_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling matrixmult on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.matrixmult(np.array(A_float, dtype='float'), np.array(B_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

    @pytest.mark.parametrize(["a", "b", "expected_results"], [
        ([0.13232936, 0.98562946, -0.10499292], [-0.99119134, 0.13101088, -0.01938735],
         [-0.005353527183234709, 0.10663358915485248, 0.994283972218527]),
        ([0, 0, 0], [0, 0, 0], [0, 0, 0]),
        ([1, 1, 1], [1, 1, 1], [0, 0, 0]),
        ([0, 0, -2], [0, 4, 0], [8, 0, 0]),
        ([0, 0, 4], [-0.5, 0, 0], [0, -2, 0]),
        ([-1.5, 0, 0], [0, 4, 0], [0, 0, -6]),
        ([1, 0, 1], [0, 1, 0], [-1, 0, 1]),
        ([1, 2, 3], [3, 2, 1], [-4, 8, -4]),
        ([-2, 3, 1], [4, -1, 5], [16, 14, -10])])
    def test_cross(self, a, b, expected_results):
        """
        This test provides coverage of the cross function in pycgmStatic.py, defined as cross(a, b) where a and b are both 3D vectors.

        This test takes 3 parameters:
        a: 3D vector
        b: 3D vector
        expected_results: the expected result from calling cross on a and b. This result is the cross product of the vectors
        a and b.
        """
        result = pycgmStatic.cross(a, b)
        np.testing.assert_almost_equal(result, expected_results, rounding_precision)

    def test_cross_datatypes(self):
        """
        This test provides coverage of the cross function in pycgmStatic.py, defined as cross(a, b) where a and b are both 3D vectors.

        This test checks that the resulting output from calling cross is correct when called with a list of ints, a numpy
        array of ints, a list of floats, and a numpy array of floats.
        """
        A_int = [-2, 3, 1]
        A_float = [-2.0, 3.0, 1.0]
        B_int = [4, -1, 5]
        B_float = [4.0, -1.0, 5.0]
        expected_results = [16, 14, -10]

        # Check that calling cross on a list of ints yields the expected results
        result_int_list = pycgmStatic.cross(A_int, B_int)
        np.testing.assert_almost_equal(result_int_list, expected_results, rounding_precision)

        # Check that calling cross on a numpy array of ints yields the expected results
        result_int_nparray = pycgmStatic.cross(np.array(A_int, dtype='int'), np.array(B_int, dtype='int'))
        np.testing.assert_almost_equal(result_int_nparray, expected_results, rounding_precision)

        # Check that calling cross on a list of floats yields the expected results
        result_float_list = pycgmStatic.cross(A_float, B_float)
        np.testing.assert_almost_equal(result_float_list, expected_results, rounding_precision)

        # Check that calling cross on a numpy array of floats yields the expected results
        result_float_nparray = pycgmStatic.cross(np.array(A_float, dtype='float'), np.array(B_float, dtype='float'))
        np.testing.assert_almost_equal(result_float_nparray, expected_results, rounding_precision)

class TestPycgmStaticGetStatic():
    """
    This class tests the getStatic function in pycgmStatic.py:
    """

    @classmethod
    def setup_class(cls):
        """
        Called once for all tests. Loads filenames to be used for testing getStatic() from SampleData/ROM/.
        """
        cwd = os.getcwd()
        if (cwd.split(os.sep)[-1] == "pyCGM_Single"):
            parent = os.path.dirname(cwd)
            os.chdir(parent)
        cls.cwd = os.getcwd()

        dynamic_trial, static_trial, vsk_file, _, _ = pyCGM_Helpers.getfilenames(x=2)
        cls.motion_data = pycgmIO.loadData(os.path.join(cls.cwd, static_trial))
        cls.vsk_data_original = pycgmIO.loadVSK(os.path.join(cls.cwd, vsk_file), dict=False)
        cls.vsk_data = cls.vsk_data_original.copy()

    def setup_method(self):
        """
        Called once before all tests in TestPycgmStaticGetStatic. Resets the vsk_data dictionary to its original state
        as returned from pycgmIO.loadVSK from the file SampleData/ROM/Sample_SM.vsk.
        """
        self.vsk_data = self.vsk_data_original.copy()

    @pytest.mark.parametrize("key", [
        ('LeftLegLength'),
        ('RightLegLength'),
        ('Bodymass'),
        ('LeftAsisTrocanterDistance'),
        ('InterAsisDistance'),
        ('LeftTibialTorsion'),
        ('RightTibialTorsion'),
        ('LeftShoulderOffset'),
        ('RightShoulderOffset'),
        ('LeftElbowWidth'),
        ('RightElbowWidth'),
        ('LeftWristWidth'),
        ('RightWristWidth'),
        ('LeftHandThickness'),
        ('RightHandThickness')])
    def test_getStatic_required_markers(self, key):
        """
        This function tests that an exception is raised when removing given keys from the vsk_data dictionary. All
        of the tested markers are required to exist in the vsk_data dictionary to run pycgmStatic.getStatic(), so
        deleting those keys should raise an exception.
        """
        del self.vsk_data[key]
        with pytest.raises(Exception):
            pycgmStatic.getStatic(self.motion_data, self.vsk_data)

    @pytest.mark.parametrize("key", [
        ('RightKneeWidth'),
        ('LeftKneeWidth'),
        ('RightAnkleWidth'),
        ('LeftAnkleWidth')])
    def test_getStatic_zero_markers(self, key):
        """
        This function tests that when deleting given keys from the vsk_data dictionary, the value in the resulting
        calSM is 0. All of the tested markers are set to 0 if they don't exist in pycgmStatic.getStatic(), so
        deleting these keys should not raise an exception.
        """
        del self.vsk_data[key]
        result = pycgmStatic.getStatic(self.motion_data, self.vsk_data)
        np.testing.assert_almost_equal(result[key], 0, rounding_precision)

    @pytest.mark.parametrize(["key", "keyVal"], [
        ('Bodymass', 95),
        ('InterAsisDistance', 28),
        ('RightKneeWidth', -11),
        ('LeftKneeWidth', 30),
        ('RightAnkleWidth', -41),
        ('LeftAnkleWidth', -5),
        ('LeftTibialTorsion', 28),
        ('RightTibialTorsion', -37),
        ('LeftShoulderOffset', 48),
        ('RightShoulderOffset', 93),
        ('LeftElbowWidth', -10),
        ('RightElbowWidth', -4),
        ('LeftWristWidth', 71),
        ('RightWristWidth', 9),
        ('LeftHandThickness', 15),
        ('RightHandThickness', -21),
        ('InterAsisDistance', -10)])
    def test_getStatic_marker_assignment(self, key, keyVal):
        """
        This function tests that when assigning a value to the given keys from the vsk_data dictionary, the value in
        the resulting calSM corresponds. All of the tested markers are assigned to calSM in pycgmStatic.getStatic()
        """
        self.vsk_data[key] = keyVal
        result = pycgmStatic.getStatic(self.motion_data, self.vsk_data)
        np.testing.assert_almost_equal(result[key], keyVal, rounding_precision)

    @pytest.mark.parametrize(["LeftLegLength", "RightLegLength", "MeanLegLengthExpected"], [
        (0, 0, 0),
        (0, 40, 20),
        (-34, 0, -17),
        (-15, 15, 0),
        (5, 46, 25.5)])
    def test_getStatic_MeanLegLength(self, LeftLegLength, RightLegLength, MeanLegLengthExpected):
        """
        This function tests that pycgmStatic.getStatic() properly calculates calSM['MeanLegLength'] by averaging the
        values in vsk_data['LeftLegLength'] and vsk_data['RightLegLength']
        """
        self.vsk_data['LeftLegLength'] = LeftLegLength
        self.vsk_data['RightLegLength'] = RightLegLength
        result = pycgmStatic.getStatic(self.motion_data, self.vsk_data)
        np.testing.assert_almost_equal(result['MeanLegLength'], MeanLegLengthExpected, rounding_precision)

    @pytest.mark.parametrize(["leftVal", "rightVal", "leftExpected", "rightExpected"], [
        # Test where left and right are 0
        (0, 0, 72.512, 72.512),
        # Test where left is 0
        (85, 0, 72.512, 72.512),
        # Test where right is 0
        (0, 61, 72.512, 72.512),
        # Test where left and right aren't 0
        (85, 61, 85, 61)])
    def test_getStatic_AsisToTrocanterMeasure(self, leftVal, rightVal, leftExpected, rightExpected):
        """
        Tests that if LeftAsisTrocanterDistance or RightAsisTrocanterDistance are 0 in the input vsk dictionary, their
        corresponding values in calSM will be calculated from LeftLegLength and RightLegLength, but if they both have
        values than they will be assigned from the vsk dictionary
        """
        self.vsk_data['LeftAsisTrocanterDistance'] = leftVal
        self.vsk_data['RightAsisTrocanterDistance'] = rightVal
        result = pycgmStatic.getStatic(self.motion_data, self.vsk_data)
        np.testing.assert_almost_equal(result['L_AsisToTrocanterMeasure'], leftExpected, rounding_precision)
        np.testing.assert_almost_equal(result['R_AsisToTrocanterMeasure'], rightExpected, rounding_precision)

    def test_getStatic_InterAsisDistance(self):
        """
        This function tests that when pycgmStatic.getStatic() is called with vsk_data['InterAsisDistance'] is 0, that
        the value for calSM['InterAsisDistance'] is calculated from motionData
        """
        self.vsk_data['InterAsisDistance'] = 0
        result = pycgmStatic.getStatic(self.motion_data, self.vsk_data)
        np.testing.assert_almost_equal(result['InterAsisDistance'], 215.9094195515741, rounding_precision)

    def test_gen(self):
        """
        This function tests that the correct values are returned in calSM['RightStaticRotOff'],
        calSM['RightStaticPlantFlex'], calSM['LeftStaticRotOff'], calSM['LeftStaticPlantFlex'], and calSM['HeadOffset'].
        All of these values are calculated from calls to staticCalculation and staticCalculationHead for every frame
        in motionData
        """
        result = pycgmStatic.getStatic(self.motion_data, self.vsk_data)
        np.testing.assert_almost_equal(result['RightStaticRotOff'], 0.015683497632642041, rounding_precision)
        np.testing.assert_almost_equal(result['RightStaticPlantFlex'], 0.27024179070027576, rounding_precision)
        np.testing.assert_almost_equal(result['LeftStaticRotOff'], 0.0094029102924030206, rounding_precision)
        np.testing.assert_almost_equal(result['LeftStaticPlantFlex'], 0.20251085737834015, rounding_precision)
        np.testing.assert_almost_equal(result['HeadOffset'], 0.25719904693106527, rounding_precision)


# -*- coding: utf-8 -*-
import os
import time
from datetime import datetime, timedelta
from configs.path import DOWNLOAD_PATH
from helpers._selenium import ClientSideCrawler
from configs.url import KRX
from helpers._pd import parse_html_to_excel

def kospi_spider():
    browser = ClientSideCrawler(KRX)
    driver = browser.driver

    try:
        # Click the Stock id.
        kospi_btn = driver.find_element_by_css_selector('input.schdate[value=STK]')
        kospi_btn.click()
        print('The radio button is clicked %s' % kospi_btn)

        # if next_date:
        _next_date = datetime.strftime(datetime.now() - timedelta(1), '%Y%m%d')
        date_input = driver.find_element_by_css_selector('.cal-area input.schdate')
        date_input.clear()
        date_input.send_keys(_next_date)

        # Click the search button.
        submit_btn = driver.find_element_by_css_selector('button.btn-board-search')
        submit_btn.click()

        # Download the xml.
        download_btn = driver.find_element_by_css_selector(
            'button.btn-board-download')
        download_btn.click()

        timeout = 5
        seconds = 0
        files = os.listdir(DOWNLOAD_PATH)

        while seconds < timeout:
            time.sleep(1)
            next_files = os.listdir(DOWNLOAD_PATH)

            print('Counting down %s' % seconds)

            if len(next_files) > len(files):
                print('Done. Please read the file in %s' % DOWNLOAD_PATH)
                driver.close()
            seconds += 1

        browser.tear_down()
    except Exception as inst:
        print('Error occurs while running TOPIX')
        print(inst)
        browser.tear_down()

if __name__ == '__main__':
    kospi_spider()


import tkinter as tk

main = tk.Tk()
main_window = tk.Label(
    bg = "black",
    fg = "white",
    width = 50,
    height = 25
)
video = tk.Entry()
prompt = tk.Label(text="Choose how you would like to download your file", fg="white")
main_window.pack()
main.mainloop()


import sys
sys.path.append('./')
sys.path.append('./../')
import openai, os, time, torch, sys, importlib, json, copy
import matplotlib.pyplot as plt
import numpy as np
from functools import partial
import numpy as np
from models import lora_gptj
from sklearn.metrics import precision_score, recall_score, accuracy_score, f1_score

from utils.helper import log

def get_accuracy(y_pred_val, y_val):
    acc_val = (np.array(y_pred_val) == np.array(y_val)).mean()
    acc_val = round(acc_val * 100, 2)
    return acc_val

class GPTJFineTuner(object):
    def __init__(self,config:dict,train_jsonl,valid_jsonl,cuda_idx = 0):
        self.config = config
        self.train_jsonl=train_jsonl
        self.valid_jsonl=valid_jsonl

        self.device = torch.device('cuda:%d' % cuda_idx) if torch.cuda.is_available() else 'cpu'
        torch.cuda.set_device(cuda_idx)

    def init_model(self):
        print('=====Initialize a new GPTJ Model=====')
        self.ft_model = lora_gptj.LoRaQGPTJ(adapter=True, device=self.device)

    def fine_tune(self):
        self.init_model()

    def generate(self, gpt, text_lst, max_token=10, batch_size=2):
        gpt.model.eval()
        outputs = []
        for i in np.arange(0, len(text_lst), batch_size):
            texts = text_lst[i:min(i + batch_size, len(text_lst))]
            prompt = gpt.tokenizer(texts, truncation=True, padding = True, max_length=1024, return_tensors='pt')
            prompt = {key: value.to(gpt.device) for key, value in prompt.items()}
            outs = gpt.model.generate(**prompt, max_new_tokens=max_token, pad_token_id=gpt.tokenizer.eos_token_id, do_sample=True, early_stopping = True)
            outs = gpt.tokenizer.batch_decode(outs, skip_special_tokens=True)
            outputs += outs
        return outputs

    def prompt2value(self, x):
        # print("Output:",x)
        c = x.strip().split('@@@')[0]
        return float(c)

    def query(self, gpt, prompts, bs=10):
        outputs = self.generate(gpt, prompts, batch_size=bs)
        ans = []
        for txt in outputs:
            try:
                output = self.prompt2value(txt.split('@@@')[-1].split('###')[0])
            except:
                output = None
            ans.append(output)
        return ans

    def eval(self,valid_prompts,valid_df,test_prompts,test_df,logf,y_name='y',train_df = None,imbalance=False,flip=False):
        """
            number of valid samples
            L2 error on the valid samples
        """
        y_valid_outputs_, y_test_outputs_, len_valid_valid_y_, val_acc_list, test_acc_list = [], [], [], [], []
        best_idx = 0
        for model_idx in range(len(self.config['epochs'])):
            config = copy.deepcopy(self.config)
            epochs_ran = 0 if model_idx == 0 else self.config['epochs'][model_idx-1]
            config['epochs'] = self.config['epochs'][model_idx] - epochs_ran
            print('==== Epoch %.4f ====' % self.config['epochs'][model_idx])
            self.ft_model.finetune(self.train_jsonl,
                self.valid_jsonl,
                config,
                saving_checkpoint = False)

            # validation
            y_valid_outputs = self.query(self.ft_model, valid_prompts, bs = 15)
            y_valid_outputs_.append(y_valid_outputs)

            valid_valid_y = [valid_df[y_name][i] for i in range(len(y_valid_outputs)) if y_valid_outputs[i] != None]
            valid_valid_y_outputs = [y_valid_outputs[i] for i in range(len(y_valid_outputs)) if y_valid_outputs[i] != None]

            len_valid_valid_y = len(valid_valid_y)
            print("| Valid Val #outputs/Total #outputs:%d/%d" % (len_valid_valid_y,len(y_valid_outputs)))
            len_valid_valid_y_.append(len_valid_valid_y)

            print(type(valid_valid_y_outputs), type(valid_valid_y))
            # from IPython import embed; embed()

            val_acc = get_accuracy(valid_valid_y_outputs, valid_valid_y)
            val_acc_list.append(val_acc)

            print('| Val Acc     : %.2f' % val_acc)
            if (val_acc < val_acc_list[best_idx]) or (np.isnan(val_acc_list[best_idx])):
                best_idx = model_idx

            # Testing
            y_test_outputs = self.query(self.ft_model, test_prompts, bs = 10)
            y_test_outputs_.append(y_test_outputs)

            valid_test_y = [test_df[y_name][i] for i in range(len(y_test_outputs)) if y_test_outputs[i] != None]
            valid_test_y_outputs = [y_test_outputs[i] for i in range(len(y_test_outputs)) if y_test_outputs[i] != None]
            print("Valid Test #outputs/Total #outputs:%d/%d" % (len(valid_test_y),len(y_test_outputs)))
            test_acc = get_accuracy(valid_test_y_outputs, valid_test_y)
            test_acc_list.append(test_acc)
            print('| Test Acc     : %.2f' % test_acc)

            if imbalance:
                if flip:
                    valid_valid_y = (-1*(valid_valid_y-1)).astype("int")
                    valid_valid_y_outputs = (-1*(valid_valid_y_outputs-1)).astype("int")
                    valid_test_y = (-1*(valid_test_y-1)).astype("int")
                    valid_test_y_outputs = (-1*(valid_test_y_outputs-1)).astype("int")

                precision_val = round(precision_score(valid_valid_y, valid_valid_y_outputs) * 100, 2)
                recall_val = round(recall_score(valid_valid_y, valid_valid_y_outputs) * 100, 2)
                f1_val = round(f1_score(valid_valid_y, valid_valid_y_outputs) * 100, 2)

                precision = round(precision_score(valid_test_y, valid_test_y_outputs) * 100, 2)
                recall = round(recall_score(valid_test_y, valid_test_y_outputs) * 100, 2)
                f1 = round(f1_score(valid_test_y, valid_test_y_outputs) * 100, 2)
                log(logf, f"val {self.config['epochs'][model_idx]} {val_acc} {f1_val} {precision_val} {recall_val}")
                log(logf, f"test {self.config['epochs'][model_idx]} {test_acc} {f1} {precision} {recall}")
            else:
                log(logf, f"{self.config['epochs'][model_idx]} {val_acc} {test_acc}")

        print('Selected epoch: %.4f' % self.config['epochs'][best_idx])
        self.best_idx = best_idx

        return y_test_outputs_[best_idx], len_valid_valid_y_,val_acc_list, test_acc_list


#!/usr/bin/env python
from __future__ import division
import math
import rospy
import time
from numpy import sign
#from sensor_msgs.msg import Joy
from duckietown_msgs.msg import LanePose , Twist2DStamped

class PID():
        def __init__(self):

                rospy.Subscriber("~lane_pose", LanePose, self.callback)
                self.pub = rospy.Publisher("~car_cmd", Twist2DStamped, queue_size=1)
#                self.pub_joystick = rospy.Publisher("/jafar/joy", Joy, queue_size=1)
                self.d = 0.0
                self.phi = 0.0
                self.d_ref = 0.0
                self.phi_ref = 0.0
                self.er_d = 0.0
                self.er_phi = 0.0
                self.velocity = 0.5
                self.omega = 0.0
                self.kp_d=10
                self.ki_d=0.3
                self.kd_d=0.1
                self.kp_phi=5
                self.ki_phi=0.0
                self.kd_phi=0.0
                self.proportional_d=0.0
                self.integral_d=0.0
                self.derivative_d=0.0
                self.last_er_d=0.0
                self.proportional_phi=0.0
                self.integral_phi=0.0
                self.derivative_phi=0.0
                self.last_er_phi=0.0
                self.d_t=0.001
                self.u_phi= 0.0
                self.u_d= 0.0
#               self.key_handle = "empty"

        def callback(self, data):
                self.d = data.d
                self.phi = data.phi
                self.d_ref = data.d_ref
                self.phi_ref = data.phi_ref
                self.last_er_d = self.er_d
                self.last_er_phi = self.er_phi
                self.er_d = self.d_ref-self.d
                self.er_phi = self.phi_ref-self.phi

                #PID for d
                self.proportional_d = self.kp_d * self.er_d
                self.integral_d += self.ki_d * self.er_d * self.d_t
                self.d_er_d = self.er_d - self.last_er_d
                self.derivative_d = self.kd_d * self.d_er_d/self.d_t
                self.u_d = self.proportional_d + self.integral_d + self.derivative_d

                #PID for phi
                self.proportional_phi = self.kp_phi * self.er_phi
                self.integral_phi += self.ki_phi * self.er_phi * self.d_t
                self.d_er_phi = self.er_phi - self.last_er_phi
                self.derivative_phi = self.kd_phi * self.d_er_phi/self.d_t
                self.u_phi = self.proportional_phi + self.integral_phi + self.derivative_phi

                self.omega = self.u_d + self.u_phi

                if math.fabs(self.omega)>= 5  :
                        self.omega =5 * self.omega/math.fabs(self.omega)

                output = Twist2DStamped()
                output.v = self.velocity
                output.omega = self.omega
                output.header = data.header
                self.pub.publish(output)

 #               msg = Joy()
 #               msg.header = data.header
 #               msg.axes = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
 #               if self.key_handle == "a" :
 #                       msg.buttons = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
#                       self.key_handle = "empty"
 #               key = raw_input()
 #               if key == "a" :
#                       self.key_handle = "a"
 #                       msg.buttons = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
 #               if key == "s" :
 #                       msg.buttons = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
 #               key="empty"

#                self.pub_joystick.publish(msg)

if __name__ == '__main__':
        rospy.init_node('lane_controller_node', anonymous=True)
        PID()
        rospy.spin()


# Сделать так, чтобы в программе дно рождения кроме того, чтобы узнать,
# есть ли твой день рождения в числе пи, можно было узнать, в каком месте числа ПИ  оно находится

name_of_file = "files/pi.txt"
print("Пришло время узнать, есть ли ваша дата рождения в числе Пи")

pi_str = ''
with open(name_of_file) as file:
    lines = file.readlines()
    for line in lines:
        pi_str += line.strip()

birth = input("Введите дату вашего рождения?: ")

result = pi_str.find(birth) - 1 #отнимаем 1, чтобы считать, начиная с 1-го символа после точки
if result > 0:
    print("Здорово! Дата вашего рождения в числе ПИ на ", result, "-", result+len(birth)-1, "символах после точки!")
else:
    print("К сожалению, вашего дня рождения нет в числе Пи")


# This is a sample Python script.

# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.

import random
import itertools
import sys

class Automaton:
    def __init__(self, atype=None, states=None, alphabet=None, instructions=None, initial_states=None):
        self.atype = type
        self.__states = set()
        self.__alphabet = set()
        if not instructions:
            self.__instructions = {}
        else:
            self.__instructions = instructions
        self.__initial_states = set()
        self.__curr_state = None
        self._tape = ''
        self._position = -1

    @property
    def alphabet(self):
        return self.__alphabet

    @alphabet.setter
    def alphabet(self, abet):
        self.__alphabet = set(abet)

    @property
    def initial_states(self):
        return self.__initial_states

    def set_initial_state(self, state):
        if state not in self.states:
            self.__states.add(state)
        self.__initial_states = {state}

    @initial_states.setter
    def initial_states(self, states):
        # states should be a set
        if not states <= self.__states:
            self.__states = self.__states | states
        self.__initial_states = states

    @property
    def states(self) -> set:
        return self.__states

    @states.setter
    def states(self, states):
        self.__states = set(states)

    def add_instruction(self, left, right):
        self.__instructions[left] = right

    @property
    def instructions(self):
        return self.__instructions

    @instructions.setter
    def instructions(self, instructions):
        self.__instructions = instructions

    @property
    def state(self):
        return self.__curr_state

    @state.setter
    def state(self, state):
        self.__curr_state = state

    def step(self):
        pass

    @property
    def configuration(self):
        return self.__curr_state, self._tape, self._position

    @configuration.setter
    def configuration(self, conf):
        if conf[0] not in self.__states:
            raise f"Wrong configuration {conf} - unknown state"
        self.__curr_state = conf[0]
        self._tape = conf[1]
        self._position = conf[2]

class nrNFAwtl(Automaton):
    def __init__(self, atype="nrNFAwtl", states=None, alphabet=None, instructions=None, initial_states=None):
        super().__init__(type, states, alphabet, instructions, initial_states)
        if instructions is None:
            instructions = {}
        if alphabet is None:
            alphabet = set()
        self._endmarker = '$'
        self.__transparency = {}
        if states:
            for st in states:
                self.__transparency[st] = set()

    @property
    def transparency(self) -> dict:
        return self.__transparency

    @transparency.setter
    def transparency(self, states_transparency):
        self.__transparency = states_transparency

    def step(self):
        while self._tape[self._position] in self.transparency[self.state]:
            self._position += 1
        symbol = self._tape[self._position]
        if symbol not in self.alphabet and symbol != self._endmarker:
            raise Exception(f"Symbol {symbol} is not in the automaton's alphabet")
        if (self.state, symbol) not in self.instructions:
            return "Reject"
        self.state = one_of(self.instructions[(self.state, symbol)])
        if self._tape[self._position] == self._endmarker:
            self._position = 0
        else:
            self._tape = self._tape[:self._position] + self._tape[self._position + 1:]
        return self.state

    def next_configs(self, state, tape, position):
        while tape[position] in self.transparency[state]:
            position += 1
        symbol = tape[position]
        if symbol not in self.alphabet and symbol != self._endmarker:
            raise Exception(f"Symbol {symbol} is not in the automaton's alphabet")
        if (state, symbol) not in self.instructions:
            return []
        next_states = self.instructions[(state, symbol)]
        if tape[position] == self._endmarker:
            next_position = 0
            next_tape = tape
        else:
            next_position = position
            next_tape = tape[:position] + tape[position + 1:]

        return [(st, next_tape, next_position) for st in next_states]

    def accepts_from_configuration(self, state, tape, position):
        if state == 'Accept':
            return True
        next_configs = self.next_configs(state, tape, position)
        for c in next_configs:
            if self.accepts_from_configuration(c[0], c[1], c[2]):
                return True
        return False

    def accepts(self, word):
        orig_recursion_limit = sys.getrecursionlimit()
        tape = word + self._endmarker
        if len(tape) > orig_recursion_limit + 20:
            sys.setrecursionlimit(len(tape) + 20)
        for state in self.initial_states:
            if self.accepts_from_configuration(state, tape, 0):
                if sys.getrecursionlimit() > orig_recursion_limit:
                    sys.setrecursionlimit(orig_recursion_limit)
                return True
        if sys.getrecursionlimit() > orig_recursion_limit:
            sys.setrecursionlimit(orig_recursion_limit)
        return False

def one_of(state_set):
    if not state_set:
        return None
    else:
        return random.choice(list(state_set))

def accepted_words(aut, max_len):
    res = []
    for l in range(max_len + 1):
        for w in itertools.product(aut.alphabet, repeat=l):
            word = ''.join(w)
            if aut.accepts(word):
                res.append(word)
    return res

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    aut = nrNFAwtl('nrNFAwtl')
    aut.alphabet = ['a', 'b', 'c']
    aut.states = ['q0', 'q1', 'q2', 'q3', 'q4', 'q5', 'q6', 'q7', 'q8', 'q9', 'q10', 'q11', 'qI', 'qI\'']
    aut.transparency = {'q0': {'a', 'c'}, 'q1': set(), 'q2': {'a', 'b'},
                        'q3': set(), 'q4': {'b', 'c'}, 'q5': set(),
                        'q6': {'c'}, 'q7': {'a'}, 'q8': {'b'},
                        'q9': {'c'}, 'q10': set(), 'q11': set(), 'qI': {'a'}, 'qI\'': set()}
    aut.set_initial_state('qI')
    print("Alphabet:", aut.alphabet)
    print("Set of states:", aut.states)
    print("Initial states:", aut.initial_states)

    aut.state = 'qI'
    print("Current state:", aut.state)

    aut.add_instruction(('qI', 'b'), {'q1'})
    aut.add_instruction(('qI', '$'), {'qI\''})
    aut.add_instruction(('qI\'', '$'), {'Accept'})
    aut.add_instruction(('q0', 'b'), {'q1'})
    aut.add_instruction(('q0', '$'), {'q6'})
    aut.add_instruction(('q1', 'c'), {'q2'})
    aut.add_instruction(('q2', 'c'), {'q3'})
    aut.add_instruction(('q2', '$'), {'q10'})
    aut.add_instruction(('q3', 'a'), {'q4'})
    aut.add_instruction(('q4', 'a'), {'q5'})
    aut.add_instruction(('q5', 'b'), {'q0'})
    aut.add_instruction(('q6', 'a'), {'q7'})
    aut.add_instruction(('q6', '$'), {'Accept'})
    aut.add_instruction(('q7', 'b'), {'q8'})
    aut.add_instruction(('q8', 'c'), {'q9'})
    aut.add_instruction(('q9', 'a'), {'q7'})
    aut.add_instruction(('q9', '$'), {'q0'})
    aut.add_instruction(('q10', 'a'), {'q11'})
    aut.add_instruction(('q11', '$'), {'Accept'})

    aut.configuration = ('qI', 'abc$', 0)

    state = aut.configuration[0]
    print(aut.configuration)
    while state != 'Reject' and state != 'Accept':
        state = aut.step()
        print(aut.configuration)

    print("End of computation:", state)

    aut.configuration = ('qI', 'abcabcabcabc$', 0)

    state = aut.configuration[0]
    print(aut.configuration)
    while state != 'Reject' and state != 'Accept':
        state = aut.step()
        print(aut.configuration)

    print('End of computation:', state)

    print('-------------------')

    print(aut.accepts('abc'))

    print(accepted_words(aut, 15))

    print('-------------------')
    print('Accepted numbers of repeats of "abc"')

    for k in range(1100):
        w = 'abc' * k
        if aut.accepts(w):
            print(k)

    print('-------------------------------')
    print('-- another example automaton --')
    print('-------------------------------')

# See PyCharm help at https://www.jetbrains.com/help/pycharm/


import sys
input = sys.stdin.readline

n, s = map(int, input().split())
arr = list(map(int, input().split()))

left = 0
right = n - 1
ans = sum(arr)

while left + 1< right and ans > s:
    if arr[left] < arr[right]:
        if ans - arr[left] >= s:
            ans -= arr[left]
            left += 1
        elif ans - arr[right] >= s:
            arr -= arr[right]
            right -= 1
        else:
            break
    else:
        if ans - arr[right] >= s:
            ans -= arr[right]
            right -= 1
        elif ans - arr[left] >= s:
            ans -= arr[left]
            left += 1
        else:
            break

if ans < s:
    print(ans)
else:
    print(right - left + 1)


from openfisca_aotearoa.entities import Person
from openfisca_core.model_api import *

class jobseeker_support__is_prepared_for_employment(Variable):
    value_type = bool
    default_value = True
    entity = Person
    label = u"Is prepared for employment?"
    definition_period = MONTH
    reference = "TODO"

class jobseeker_support__meets_age_threshold(Variable):
    value_type = bool
    default_value = True
    entity = Person
    label = u"Meets the age test for Jobseeker Support?"
    definition_period = MONTH
    reference = "http://legislation.govt.nz/act/public/1964/0136/latest/DLM5478527.html"

    def formula(persons, period, parameters):
        # over the simpler age threshold
        jobseeker_age = parameters(period).entitlements.social_security.jobseeker_support.age_threshold
        over_age_threshold = persons("age", period.start) >= jobseeker_age

        # over the threshold for appliants with a dependent child
        jobseeker_age_with_dependent_child = parameters(period).entitlements.social_security.jobseeker_support.age_threshold_with_dependent_child
        has_dependent_child = persons('social_security__has_dependant_child', period)
        over_age_threshold_with_dependent_child = (persons("age", period.start) >= jobseeker_age_with_dependent_child) * has_dependent_child

        return over_age_threshold + over_age_threshold_with_dependent_child

class social_security__eligible_for_jobseeker_support(Variable):
    value_type = bool
    entity = Person
    definition_period = MONTH
    label = "Eligible for Job Seeker Support"
    reference = "http://legislation.govt.nz/act/public/1964/0136/latest/DLM5478527.html"

    def formula(persons, period, parameters):
        # The applicant
        residency_requirements = persons('social_security__meets_residential_requirements_for_certain_benefits', period)

        age_requirement = persons('jobseeker_support__meets_age_threshold', period)

        # income low enough?
        income = persons('jobseeker_support__below_income_threshold', period)

        # Prepared to work
        prepared = persons('jobseeker_support__is_prepared_for_employment', period)

        return age_requirement * income * prepared * residency_requirements


import sys

input = sys.stdin.readline

# 11723 집합
# 집합에서의 삽입, 삭제, 검색, 토글, 채우기, 비우기 연산을 구현하는 문제
# list 나 set 을 사용하여 해결할 수도 있지만 연습을 위해 비트마스크를 사용하여 해결해보았다.
def sol11723():
    # 집합
    s = 0
    for _ in range(int(input())):
        # 명령어
        cmd = input().split()

        # 명령어에 인자가 없을 경우 - all 또는 empty
        if len(cmd) == 1:
            # all 명령어
            # s의 모든 비트값을 1로 초기화
            if cmd[0][0] == 'a':
                s = (1 << 21) - 1

            # empty 명령어
            # s를 0으로 초기화
            else:
                s = 0

        # 명령어에 인자가 존재하는 경우 - add, remove, toggle, check
        else:
            # 인자값의 비트마스크
            e = 1 << int(cmd[1])

            # add 명령어
            # 인자값의 비트마스크와 집합의 비트마스크를 bitwise-or 연산
            if cmd[0][0] == 'a':
                s |= e

            # remove 연산
            # 인자값의 비트마스크에 bitwise-not을 취한 값과 집합의 비트마스크를 bitwise-and 연산
            elif cmd[0][0] == 'r':
                s &= ~e

            # toggle 연산
            # 인자값의 비트마스크와 집합의 비트마스크를 집합의 비트마스크와 bitwise-xor 연산
            elif cmd[0][0] == 't':
                s ^= e

            # 인자값의 비트마스크와 집합의 비트마스크를 bitwise-and 연산한 결과가 0이라면 0
            # 0이 아니라면 1을 출력
            else:
                sys.stdout.write('1\n' if s & e else '0\n')


#!/usr/bin/env python3

import json
import os
import pprint
import random
import time

import taskcluster
from natsort import natsorted

from worker_health import tc_helpers

# class goal: see if a worker is working

class Status:
    tc_wm = None
    root_url = "https://firefox-ci-tc.services.mozilla.com"

    def __init__(self, provisioner, worker_type):
        self.provisioner = provisioner
        self.worker_type = worker_type

        with open(os.path.expanduser("~/.tc_token")) as json_file:
            data = json.load(json_file)
        creds = {"clientId": data["clientId"], "accessToken": data["accessToken"]}

        self.tc_wm = taskcluster.WorkerManager({"rootUrl": self.root_url, "credentials": creds})
        self.tc_h = tc_helpers.TCHelper(provisioner=self.provisioner)

    def wait_until_no_jobs_running(self, hosts, sleep_seconds=15, show_indicator=True):
        we_have_waited = False
        while True:
            jrd = self.get_hosts_running_jobs(hosts)
            if len(jrd) == 0:
                if show_indicator and we_have_waited:
                    print("")
                break
            time.sleep(sleep_seconds)
            we_have_waited = True
            if show_indicator:
                print(".", end="")

    # given list of hosts, return one that's idle (once one is available)
    def wait_for_idle_host(self, hosts, sleep_time=15):
        return random.choice(self.wait_for_idle_hosts(hosts, sleep_time))

    # given list of hosts, return those that are idle (once one is available)
    def wait_for_idle_hosts(self, hosts, sleep_time=15, show_indicator=True):
        hosts_set = set(hosts)
        while True:
            if show_indicator:
                print(".", end="", flush=True)
            hosts_with_non_completed_or_failed_jobs_set = set(self.get_hosts_running_jobs(hosts))
            hosts_idle = hosts_set - hosts_with_non_completed_or_failed_jobs_set
            if hosts_idle:
                if show_indicator:
                    print("")
                return list(hosts_idle)
            if show_indicator:
                print("z", end="", flush=True)
            time.sleep(sleep_time)

    def get_hosts_running_jobs(self, hosts, verbose=False):
        worker_groups = self.tc_h.get_worker_groups(self.worker_type)
        worker_group = worker_groups[0]

        hosts_with_non_completed_or_failed_jobs = []
        hosts_checked = []
        for host in hosts:
            hosts_checked.append(host)
            results = self.tc_h.get_worker_jobs(self.worker_type, worker_group, host)
            # pprint.pprint(results)
            if "recentTasks" not in results:
                # if no recent tasks, host is not running jobs
                if verbose:
                    print(f"get_hosts_running_jobs: {host}: no recentTasks")
                continue

            for result in results["recentTasks"]:
                task_id = result["taskId"]
                # pprint.pprint(task_id)
                _tid, status_blob, _exc = self.tc_h.get_task_status(task_id)
                # pprint.pprint(status_blob)
                try:
                    t_status = status_blob["status"]["state"]
                except KeyError:
                    # TODO: do additional checking if problems occur with this...
                    #   example response that we are catching here:
                    #
                    #      {'code': 'ResourceNotFound',
                    #       'message': '`NpY_UNDIRAW8Jaix-kc-SA` does not correspond to a task that '
                    #                  'exists.\n'
                    #                  'Are you sure this task exists?\n'
                    #                  '\n'
                    #                  '---\n'
                    #                  '\n'
                    #                  '* method:     status\n'
                    #                  '* errorCode:  ResourceNotFound\n'
                    #                  '* statusCode: 404\n'
                    #                  '* time:       2023-06-28T19:39:09.337Z',
                    #       'requestInfo': {'method': 'status',
                    #                       'params': {'taskId': 'NpY_UNDIRAW8Jaix-kc-SA'},
                    #                       'payload': {},
                    #                       'time': '2023-06-28T19:39:09.337Z'}}

                    # print(f"{task_id}: no task[status][state] assuming task is not running.")
                    continue
                if t_status != "completed" and t_status != "failed" and t_status != "exception":
                    # TODO: show task id and state if in verbose?
                    # pprint.pprint(status_blob["status"]["state"])
                    hosts_with_non_completed_or_failed_jobs.append(host)
        return hosts_with_non_completed_or_failed_jobs

    # TOOD: rename/decompose (fetch and present) this function
    def show_jobs_running_report(self, hosts):
        hosts_with_non_completed_or_failed_jobs = self.get_hosts_running_jobs(hosts)
        hosts_checked = hosts

        # TODO: move this print into get_hosts_running_jobs()
        #   - less useful now that it's just a len call vs the internal value from above?
        print(f"hosts checked ({len(hosts_checked)}): {hosts_checked}")
        print(
            f"hosts_with_non_completed_or_failed_jobs ({len(hosts_with_non_completed_or_failed_jobs)}): "
            f"{hosts_with_non_completed_or_failed_jobs}",
        )

        # return hosts not idle
        return hosts_with_non_completed_or_failed_jobs

    def list_workers_human(self):
        results = self.tc_wm.listWorkers(self.provisioner, self.worker_type)
        return_str = ""
        # TODO: fix natsorting, copy how _py does it?
        for result in natsorted(results["workers"]):
            return_str += f"{result['workerPoolId']} {result['workerGroup']} {result['workerId']}\n"
        print(return_str)
        return return_str

    def list_workers_csv(self):
        results = self.tc_wm.listWorkers(self.provisioner, self.worker_type)
        return_str = ""
        # TODO: fix natsorting, copy how _py does it?
        for result in natsorted(results["workers"]):
            return_str += f"{result['workerId']},"
        # trim trailing comma
        print(return_str[:-1])

    def list_workers_py(self):
        results = self.tc_wm.listWorkers(self.provisioner, self.worker_type)
        return_arr = []
        for result in results["workers"]:
            return_arr.append(result["workerId"])
        pprint.pprint(natsorted(return_arr))

if __name__ == "__main__":
    si = Status("releng-hardware", "gecko-t-osx-1015-r8")
    # example usage
    # si.show_jobs_running_report(
    #     [
    #         "macmini-r8-1",
    #         # "macmini-r8-2",
    #         # "macmini-r8-3",
    #         # "macmini-r8-4",
    #         # "macmini-r8-5",
    #         # "macmini-r8-7",
    #         # "macmini-r8-8",
    #         # "macmini-r8-9",
    #         # "macmini-r8-10",
    #     ],
    # )
    # for futher debugging
    # import ipdb; ipdb.set_trace()

    # TODO: pull out into binary `list_workers`
    # si.list_workers_human()
    # si.list_workers_csv()
    # si.list_workers_py()