import pygame
import numpy as np
from random import random
import sys

ORTHO = False
RANDDELS = False

size = (800, 800)
scl = 3 / (100 * ORTHO + 1)
fullDist = 3

spd = 0.03
maxSpd = 0.003

angles = [
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0
]

delAngles = [
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0
]

centerMatrix = np.matrix([[250], [250], [250]])

pygame.init()
pygame.display.set_caption('5D to 4D to 3D to 2D Projection')
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()

pointCol = (255, 255, 255)
lineCol = (255, 255, 255)

def mapp(n, A, B, C, D):
    return (n-A)/(B-A) * (D-C) + C

if RANDDELS:
    for i in range(len(delAngles)):
        delAngles[i] = mapp(random(), 0, 1, -1, 1)

def bg():
    screen.fill((0, 0, 0))

def point(pos):

    pos = [ int(x) for x in pos ]

    pygame.draw.circle(screen, pointCol, pos, 3)

def sphere(pos, team):

    pos = [ int(x) for x in pos ]

    pygame.draw.circle(screen, pointCol, pos, 10)

def line(pos1, pos2):
    pos1 = [ int(x) for x in pos1 ]
    pos2 = [ int(x) for x in pos2 ]

    pygame.draw.line(screen, lineCol, pos1, pos2, 1)

def showObject(obj, orig):
    if orig['type'] == 0:
        def dist(a, b):
            return np.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2+(a[2]-b[2])**2+(a[3]-b[3])**2+(a[4]-b[4])**2)
        for i in range(len(obj)):
            point(obj[i])

            curr = orig['verts'][i]
            for other in range(len(orig['verts'])):
                if dist(curr, orig['verts'][other]) <= orig['conn']:
                    line(obj[i], obj[other])
    elif orig['type'] == 1:
        for i in range(len(obj)):
            sphere(obj[i], 0)

def draw():
    bg()

    projectAndDraw(penteract)

def projectObject5Dto4D(obj):
    newObj = []
    for vert in obj:
        distance = fullDist

        s = np.sin
        c = np.cos
        a = angles

        rots = [
            np.matrix( [[c(a[0]), -s(a[0]), 0, 0, 0], [s(a[0]), c(a[0]), 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]] ),   # XY
            np.matrix( [[c(a[1]), 0, -s(a[1]), 0, 0], [0, 1, 0, 0, 0], [s(a[1]), 0, c(a[1]), 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]] ),   # XZ
            np.matrix( [[c(a[2]), 0, 0, -s(a[2]), 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [s(a[2]), 0, 0, c(a[2]), 0], [0, 0, 0, 0, 1]] ),   # XW
            np.matrix( [[c(a[3]), 0, 0, 0, -s(a[3])], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [s(a[3]), 0, 0, 0, c(a[3])]] ),   # XV
            np.matrix( [[1, 0, 0, 0, 0], [0, c(a[4]), -s(a[4]), 0, 0], [0, s(a[4]), c(a[4]), 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]] ),   # YZ
            np.matrix( [[1, 0, 0, 0, 0], [0, c(a[5]), 0, -s(a[5]), 0], [0, 0, 1, 0, 0], [0, s(a[5]), 0, c(a[5]), 0], [0, 0, 0, 0, 1]] ),   # YW
            np.matrix( [[1, 0, 0, 0, 0], [0, c(a[6]), 0, 0, -s(a[6])], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, s(a[6]), 0, 0, c(a[6])]] ),   # YV
            np.matrix( [[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, c(a[7]), -s(a[7]), 0], [0, 0, s(a[7]), c(a[7]), 0], [0, 0, 0, 0, 1]] ),   # ZW
            np.matrix( [[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, c(a[8]), 0, -s(a[8])], [0, 0, 0, 1, 0], [0, 0, s(a[8]), 0, c(a[8])]] ),   # ZV
            np.matrix( [[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, c(a[9]), -s(a[9])], [0, 0, 0, s(a[9]), c(a[9])]] )    # WV
        ]

        pVert = np.matrix([ [vert[0]], [vert[1]], [vert[2]], [vert[3]], [vert[4]] ])

        for rot in rots:
            pVert = rot * pVert

        d = distance
        if not ORTHO:
            d = 1/(distance - pVert.item(4))

        projMatrix = np.matrix([[d, 0, 0, 0, 0], [0, d, 0, 0, 0], [0, 0, d, 0, 0], [0, 0, 0, d, 0]])

        pVert = projMatrix * pVert

        newObj.append([pVert.item(0), pVert.item(1), pVert.item(2), pVert.item(3)])
    return newObj

def projectObject4Dto3D(obj):
    newObj = []
    for vert in obj:
        distance = fullDist

        pVert = np.matrix([[vert[0]], [vert[1]], [vert[2]], [vert[3]]])

        d = distance
        if not ORTHO:
            d = 1/(distance - pVert.item(3))

        projMatrix = np.matrix([[d, 0, 0, 0], [0, d, 0, 0], [0, 0, d, 0]])

        #pVert = (pVert * 300)
        pVert = projMatrix * pVert

        #newObj.append([pVert.item((0))+250, pVert.item((1))+250])
        newObj.append([pVert.item((0)), pVert.item((1)), pVert.item((2))])
    return newObj

def projectObject3Dto2D(obj):
    newObj = []
    for vert in obj:
        distance = fullDist

        pVert = np.matrix([[vert[0]], [vert[1]], [vert[2]]])

        d = distance
        if not ORTHO:
            d = 1/(distance - pVert.item(2))
        #mapp(vert[2], 0, 500, 0, 1)

        projMatrix = np.matrix([[d, 0, 0], [0, d, 0]])

        pVert = (pVert * size[0] * scl)
        pVert = projMatrix * pVert

        newObj.append([pVert.item((0))+size[0]/2, pVert.item((1))+size[1]/2])
    return newObj

def projectAndDraw(obj):
    obj4D = projectObject5Dto4D(obj['verts'])
    obj3D = projectObject4Dto3D(obj4D)
    obj2D = projectObject3Dto2D(obj3D)

    showObject(obj2D, obj)

h = 1
l = -1
"""
hyperCube = {
    'type' : 0,
    'conn' : 2,
    'verts' : [
        [l, l, l, l],
        [l, l, l, h],
        [l, l, h, l],
        [l, l, h, h],
        [l, h, l, l],
        [l, h, l, h],
        [l, h, h, l],
        [l, h, h, h],
        [h, l, l, l],
        [h, l, l, h],
        [h, l, h, l],
        [h, l, h, h],
        [h, h, l, l],
        [h, h, l, h],
        [h, h, h, l],
        [h, h, h, h]
    ]
}
"""

penteract = {
    'type' : 0,
    'conn' : 2,
    'verts' : [
        [l, l, l, l, l],
        [l, l, l, l, h],
        [l, l, l, h, l],
        [l, l, l, h, h],
        [l, l, h, l, l],
        [l, l, h, l, h],
        [l, l, h, h, l],
        [l, l, h, h, h],
        [l, h, l, l, l],
        [l, h, l, l, h],
        [l, h, l, h, l],
        [l, h, l, h, h],
        [l, h, h, l, l],
        [l, h, h, l, h],
        [l, h, h, h, l],
        [l, h, h, h, h],
        [h, l, l, l, l],
        [h, l, l, l, h],
        [h, l, l, h, l],
        [h, l, l, h, h],
        [h, l, h, l, l],
        [h, l, h, l, h],
        [h, l, h, h, l],
        [h, l, h, h, h],
        [h, h, l, l, l],
        [h, h, l, l, h],
        [h, h, l, h, l],
        [h, h, l, h, h],
        [h, h, h, l, l],
        [h, h, h, l, h],
        [h, h, h, h, l],
        [h, h, h, h, h]
    ]
}

while True:
    deltaTime = clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    draw()

    for i in range(len(delAngles)):
        delAngles[i] += np.clip(mapp(random(), 0, 1, -spd, spd), -1, 1)
        angles[i] += delAngles[i] * maxSpd

    pygame.display.update()


from unittest import mock

import pytest
from h_matchers import Any

from lms.models import GradingInfo, HGroup
from lms.resources import LTILaunchResource, OAuth2RedirectResource
from lms.resources._js_config import JSConfig
from lms.services import ConsumerKeyError, HAPIError

pytestmark = pytest.mark.usefixtures(
    "ai_getter",
    "grading_info_service",
    "grant_token_service",
    "h_api",
    "vitalsource_service",
)

class TestEnableContentItemSelectionMode:
    @pytest.mark.usefixtures("blackboard_files_enabled")
    def test_it(self, context, js_config):
        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        assert js_config.asdict()["mode"] == "content-item-selection"
        assert js_config.asdict()["filePicker"] == {
            "formAction": mock.sentinel.form_action,
            "formFields": mock.sentinel.form_fields,
            "google": {
                "clientId": "fake_client_id",
                "developerKey": "fake_developer_key",
                "origin": context.custom_canvas_api_domain,
            },
            "blackboard": {
                "enabled": True,
                "listFiles": {
                    "authUrl": "http://example.com/api/blackboard/oauth/authorize",
                    "path": "/api/blackboard/courses/test_course_id/files",
                },
            },
            "canvas": {
                "enabled": True,
                "ltiLaunchUrl": "http://example.com/lti_launches",
                "listFiles": {
                    "authUrl": "http://example.com/api/canvas/oauth/authorize",
                    "path": "/api/canvas/courses/test_course_id/files",
                },
            },
            "vitalSource": {
                "enabled": False,
            },
        }

    def test_google_picker_origin_falls_back_to_lms_url_if_theres_no_custom_canvas_api_domain(
        self, ai_getter, context, js_config
    ):
        context.custom_canvas_api_domain = None

        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        ai_getter.lms_url.assert_called_once_with()
        assert (
            js_config.asdict()["filePicker"]["google"]["origin"]
            == ai_getter.lms_url.return_value
        )

    def test_it_doesnt_enable_the_blackboard_file_picker_if_the_feature_flag_is_off(
        self, js_config
    ):
        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        assert not js_config.asdict()["filePicker"]["blackboard"]["enabled"]

    def test_it_doesnt_enable_the_canvas_file_picker_if_the_lms_isnt_Canvas(
        self, context, js_config
    ):
        context.is_canvas = False

        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        self.assert_canvas_file_picker_not_enabled(js_config)

    def test_it_doesnt_enable_the_canvas_file_picker_if_the_consumer_key_isnt_found_in_the_db(
        self, ai_getter, js_config
    ):
        ai_getter.developer_key.side_effect = ConsumerKeyError()

        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        self.assert_canvas_file_picker_not_enabled(js_config)

    def test_it_doesnt_enable_the_canvas_file_picker_if_we_dont_have_a_developer_key(
        self, ai_getter, js_config
    ):
        ai_getter.developer_key.return_value = None

        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        self.assert_canvas_file_picker_not_enabled(js_config)

    def test_it_doesnt_enable_the_canvas_file_picker_if_theres_no_custom_canvas_course_id(
        self, pyramid_request, js_config
    ):
        del pyramid_request.params["custom_canvas_course_id"]

        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        self.assert_canvas_file_picker_not_enabled(js_config)

    def test_it_enables_vitalsource_picker_if_feature_enabled(
        self, pyramid_request, js_config
    ):
        pyramid_request.feature = lambda feature: feature == "vitalsource"

        js_config.enable_content_item_selection_mode(
            mock.sentinel.form_action, mock.sentinel.form_fields
        )

        assert js_config.asdict()["filePicker"]["vitalSource"]["enabled"]

    def assert_canvas_file_picker_not_enabled(self, js_config):
        assert not js_config.asdict()["filePicker"]["canvas"]["enabled"]
        assert "courseId" not in js_config.asdict()

    @pytest.fixture
    def blackboard_files_enabled(self, pyramid_request):
        pyramid_request.feature = lambda feature: feature == "blackboard_files"

class TestAddCanvasFileID:
    """Unit tests for JSConfig.add_canvas_file_id()."""

    def test_it_adds_the_viaUrl_api_config(self, js_config):
        js_config.add_canvas_file_id(
            "example_canvas_course_id", "example_canvas_file_id"
        )

        assert js_config.asdict()["api"]["viaUrl"] == {
            "authUrl": "http://example.com/api/canvas/oauth/authorize",
            "path": "/api/canvas/courses/example_canvas_course_id/files/example_canvas_file_id/via_url",
        }

    def test_it_sets_the_canvas_file_id(self, js_config, submission_params):
        js_config.add_canvas_file_id(
            "example_canvas_course_id", "example_canvas_file_id"
        )

        assert submission_params()["canvas_file_id"] == "example_canvas_file_id"

class TestAddDocumentURL:
    """Unit tests for JSConfig.add_document_url()."""

    def test_it_adds_the_via_url(self, js_config, pyramid_request, via_url):
        js_config.add_document_url("example_document_url")

        via_url.assert_called_once_with(pyramid_request, "example_document_url")
        assert js_config.asdict()["viaUrl"] == via_url.return_value

    def test_it_adds_the_viaUrl_api_config_for_Blackboard_documents(self, js_config):
        js_config.add_document_url("blackboard://content-resource/xyz123")

        assert js_config.asdict()["api"]["viaUrl"] == {
            "authUrl": "http://example.com/api/blackboard/oauth/authorize",
            "path": "/api/blackboard/courses/test_course_id/files/xyz123/via_url",
        }

    def test_it_sets_the_document_url(self, js_config, submission_params):
        js_config.add_document_url("example_document_url")

        assert submission_params()["document_url"] == "example_document_url"

class TestAddVitalsourceLaunchConfig:
    """Unit tests for JSConfig.add_vitalsource_launch_config()."""

    def test_it_sets_vitalsource_config(
        self, js_config, pyramid_request, vitalsource_service
    ):
        js_config.add_vitalsource_launch_config("book-id", "/abc")

        vitalsource_service.get_launch_params.assert_called_with(
            "book-id", "/abc", pyramid_request.lti_user
        )
        assert js_config.asdict()["vitalSource"] == {
            "launchUrl": mock.sentinel.launch_url,
            "launchParams": mock.sentinel.launch_params,
        }

    def test_it_sets_submission_params(self, js_config, submission_params):
        js_config.add_vitalsource_launch_config("book-id", "/abc")

        assert submission_params() == Any.dict.containing(
            {
                "vitalsource_book_id": "book-id",
                "vitalsource_cfi": "/abc",
            }
        )

    @pytest.fixture
    def vitalsource_service(self, vitalsource_service):
        vitalsource_service.get_launch_params.return_value = (
            mock.sentinel.launch_url,
            mock.sentinel.launch_params,
        )
        return vitalsource_service

class TestAddCanvasFileIDAddDocumentURLCommon:
    """Tests common to both add_canvas_file_id() and add_document_url()."""

    def test_it_sets_the_canvas_submission_params(
        self, pyramid_request, method_caller, submission_params
    ):
        method_caller()

        assert (
            submission_params()["h_username"]
            == pyramid_request.lti_user.h_user.username
        )
        assert (
            submission_params()["lis_outcome_service_url"]
            == "example_lis_outcome_service_url"
        )
        assert (
            submission_params()["lis_result_sourcedid"]
            == "example_lis_result_sourcedid"
        )
        assert submission_params()["learner_canvas_user_id"] == "test_user_id"

    def test_it_doesnt_set_the_speedGrader_settings_if_the_LMS_isnt_Canvas(
        self, context, method_caller, js_config
    ):
        context.is_canvas = False

        method_caller()

        assert "speedGrader" not in js_config.asdict()["canvas"]

    def test_it_doesnt_set_the_speedGrader_settings_if_theres_no_lis_result_sourcedid(
        self, method_caller, js_config, pyramid_request
    ):
        del pyramid_request.params["lis_result_sourcedid"]

        method_caller()

        assert "speedGrader" not in js_config.asdict()["canvas"]

    def test_it_doesnt_set_the_speedGrader_settings_if_theres_no_lis_outcome_service_url(
        self, method_caller, js_config, pyramid_request
    ):
        del pyramid_request.params["lis_outcome_service_url"]

        method_caller()

        assert "speedGrader" not in js_config.asdict()["canvas"]

    @pytest.fixture(
        params=[
            {
                "method": "add_canvas_file_id",
                "args": ["example_canvas_course_id", "example_canvas_file_id"],
            },
            {"method": "add_document_url", "args": ["example_document_url"]},
        ]
    )
    def method_caller(self, js_config, request):
        """Return a function that calls the method-under-test with default args."""

        def method_caller():
            return getattr(js_config, request.param["method"])(*request.param["args"])

        return method_caller

class TestMaybeEnableGrading:
    def test_it_adds_the_grading_settings(
        self, js_config, grading_info_service, pyramid_request
    ):
        js_config.maybe_enable_grading()

        grading_info_service.get_by_assignment.assert_called_once_with(
            context_id="test_course_id",
            oauth_consumer_key=pyramid_request.lti_user.oauth_consumer_key,
            resource_link_id="TEST_RESOURCE_LINK_ID",
        )
        assert js_config.asdict()["grading"] == {
            "enabled": True,
            "assignmentName": "test_assignment_name",
            "courseName": "test_course_name",
            "students": [
                {
                    "LISOutcomeServiceUrl": f"test_lis_outcomes_service_url_{i}",
                    "LISResultSourcedId": f"test_lis_result_sourcedid_{i}",
                    "displayName": f"test_h_display_name_{i}",
                    "userid": f"acct:test_h_username_{i}@TEST_AUTHORITY",
                }
                for i in range(3)
            ],
        }

    @pytest.mark.usefixtures("user_is_learner")
    def test_it_does_nothing_if_the_user_isnt_an_instructor(self, js_config):
        js_config.maybe_enable_grading()

        assert not js_config.asdict().get("grading")

    def test_it_does_nothing_if_theres_no_lis_outcome_service_url(
        self, js_config, pyramid_request
    ):
        del pyramid_request.params["lis_outcome_service_url"]

        js_config.maybe_enable_grading()

        assert not js_config.asdict().get("grading")

    def test_it_does_nothing_in_Canvas(self, context, js_config):
        context.is_canvas = True

        js_config.maybe_enable_grading()

        assert not js_config.asdict().get("grading")

    @pytest.fixture
    def grading_info_service(self, grading_info_service):
        grading_info_service.get_by_assignment.return_value = [
            mock.create_autospec(
                GradingInfo,
                instance=True,
                spec_set=True,
                lis_result_sourcedid=f"test_lis_result_sourcedid_{i}",
                lis_outcome_service_url=f"test_lis_outcomes_service_url_{i}",
                h_username=f"test_h_username_{i}",
                h_display_name=f"test_h_display_name_{i}",
            )
            for i in range(3)
        ]
        return grading_info_service

    @pytest.fixture
    def context(self, context):
        context.is_canvas = False
        return context

    @pytest.fixture
    def pyramid_request(self, pyramid_request):
        pyramid_request.lti_user = pyramid_request.lti_user._replace(roles="Instructor")
        pyramid_request.params["context_title"] = "test_course_name"
        pyramid_request.params["resource_link_title"] = "test_assignment_name"
        return pyramid_request

class TestMaybeSetFocusedUser:
    def test_it_does_nothing_if_theres_no_focused_user_param(
        self, js_config, pyramid_request
    ):
        del pyramid_request.params["focused_user"]

        js_config.maybe_set_focused_user()

        assert "focus" not in js_config.asdict()["hypothesisClient"]

    def test_it_sets_the_focused_user_if_theres_a_focused_user_param(
        self, h_api, js_config
    ):
        js_config.maybe_set_focused_user()

        # It gets the display name from the h API.
        h_api.get_user.assert_called_once_with("example_h_username")
        # It sets the focused user.
        assert js_config.asdict()["hypothesisClient"]["focus"] == {
            "user": {
                "username": "example_h_username",
                "displayName": h_api.get_user.return_value.display_name,
            },
        }

    def test_display_name_falls_back_to_a_default_value(self, h_api, js_config):
        h_api.get_user.side_effect = HAPIError()

        js_config.maybe_set_focused_user()

        assert (
            js_config.asdict()["hypothesisClient"]["focus"]["user"]["displayName"]
            == "(Couldn't fetch student name)"
        )

    @pytest.fixture
    def pyramid_request(self, pyramid_request):
        pyramid_request.params["focused_user"] = "example_h_username"
        return pyramid_request

class TestJSConfigAuthToken:
    """Unit tests for the "authToken" sub-dict of JSConfig."""

    def test_it(
        self, authToken, bearer_token_schema, BearerTokenSchema, pyramid_request
    ):
        BearerTokenSchema.assert_called_once_with(pyramid_request)
        bearer_token_schema.authorization_param.assert_called_once_with(
            pyramid_request.lti_user
        )
        assert authToken == bearer_token_schema.authorization_param.return_value

    @pytest.fixture
    def authToken(self, config):
        return config["api"]["authToken"]

class TestJSConfigAPISync:
    """Unit tests for the api.sync sub-dict of JSConfig."""

    @pytest.mark.usefixtures("section_groups_on")
    def test_it(self, sync, pyramid_request, GroupInfo):
        assert sync == {
            "authUrl": "http://example.com/api/canvas/oauth/authorize",
            "path": "/api/canvas/sync",
            "data": {
                "course": {
                    "context_id": "test_context_id",
                    "custom_canvas_course_id": "test_custom_canvas_course_id",
                },
                "lms": {
                    "tool_consumer_instance_guid": "test_tool_consumer_instance_guid"
                },
                "group_info": {
                    key: value
                    for key, value in pyramid_request.params.items()
                    if key in GroupInfo.columns.return_value
                },
            },
        }

    @pytest.mark.usefixtures("section_groups_on", "learner_canvas_user_id")
    def test_it_adds_learner_canvas_user_id_for_SpeedGrader_launches(self, sync):
        assert sync["data"]["learner"] == {
            "canvas_user_id": "test_learner_canvas_user_id",
        }

    def test_its_None_if_section_groups_isnt_enabled(self, sync):
        assert sync is None

    @pytest.fixture
    def sync(self, config):
        return config["api"]["sync"]

    @pytest.fixture
    def learner_canvas_user_id(self, pyramid_request):
        pyramid_request.params["learner_canvas_user_id"] = "test_learner_canvas_user_id"

    @pytest.fixture
    def pyramid_request(self, pyramid_request):
        pyramid_request.params.clear()
        pyramid_request.params.update(
            {
                "context_id": "test_context_id",
                "custom_canvas_course_id": "test_custom_canvas_course_id",
                "tool_consumer_instance_guid": "test_tool_consumer_instance_guid",
                "foo": "bar",  # This item should be missing from group_info.
            }
        )
        return pyramid_request

class TestJSConfigDebug:
    """Unit tests for the "debug" sub-dict of JSConfig."""

    @pytest.mark.usefixtures("user_is_learner")
    def test_it_contains_debugging_info_about_the_users_role(self, config):
        assert "role:learner" in config["tags"]

    @pytest.fixture
    def config(self, config):
        return config["debug"]

class TestJSConfigHypothesisClient:
    """Unit tests for the "hypothesisClient" sub-dict of JSConfig."""

    def test_it_contains_one_service_config(self, config):
        assert len(config["services"]) == 1

    def test_it_includes_the_api_url(self, config):
        assert config["services"][0]["apiUrl"] == "https://example.com/api/"

    def test_it_includes_the_authority(self, config):
        assert config["services"][0]["authority"] == "TEST_AUTHORITY"

    def test_it_disables_share_links(self, config):
        assert not config["services"][0]["enableShareLinks"]

    def test_it_includes_grant_token(
        self, config, pyramid_request, grant_token_service
    ):
        grant_token_service.generate_token.assert_called_with(
            pyramid_request.lti_user.h_user
        )
        grant_token = config["services"][0]["grantToken"]
        assert grant_token == grant_token_service.generate_token.return_value

    def test_it_includes_the_group(self, config, context):
        groups = config["services"][0]["groups"]

        assert groups == [context.h_group.groupid.return_value]

    @pytest.mark.usefixtures("section_groups_on")
    def test_it_configures_the_client_to_fetch_the_groups_over_RPC(self, config):
        assert config["services"][0]["groups"] == "$rpc:requestGroups"

    @pytest.mark.usefixtures("provisioning_disabled")
    def test_it_is_empty_if_provisioning_feature_is_disabled(self, config):
        assert config == {}

    def test_it_is_mutable(self, config):
        config.update({"a_key": "a_value"})

        assert config["a_key"] == "a_value"

    @pytest.fixture
    def config(self, config):
        return config["hypothesisClient"]

class TestJSConfigRPCServer:
    """Unit tests for the "rpcServer" sub-dict of JSConfig."""

    def test_it(self, config):
        assert config == {"allowedOrigins": ["http://localhost:5000"]}

    @pytest.fixture
    def config(self, config):
        return config["rpcServer"]

class TestEnableCanvasOauth2RedirectErrorMode:
    def test_scope_error(self, js_config):
        js_config.enable_canvas_oauth2_redirect_error_mode(
            auth_url=None,
            error_details="Technical error",
            is_scope_invalid=True,
            requested_scopes=["scope_a", "scope_b"],
        )

        config = js_config.asdict()

        assert config["mode"] == "canvas-oauth2-redirect-error"
        assert config["canvasOAuth2RedirectError"] == {
            "authUrl": None,
            "invalidScope": True,
            "errorDetails": "Technical error",
            "scopes": ["scope_a", "scope_b"],
        }

    def test_other_error(self, js_config):
        auth_url = "https://lms.hypothes.is/auth/url"
        js_config.enable_canvas_oauth2_redirect_error_mode(
            auth_url=auth_url, error_details="Some error"
        )

        config = js_config.asdict()

        assert config["mode"] == "canvas-oauth2-redirect-error"
        assert config["canvasOAuth2RedirectError"] == {
            "authUrl": auth_url,
            "invalidScope": False,
            "errorDetails": "Some error",
            "scopes": [],
        }

    @pytest.fixture
    def js_config(self, context, pyramid_request):
        return JSConfig(context, pyramid_request)

    @pytest.fixture
    def pyramid_request(self, pyramid_request):
        pyramid_request.lti_user = None
        return pyramid_request

    @pytest.fixture
    def context(self):
        return mock.create_autospec(
            OAuth2RedirectResource, spec_set=True, instance=True
        )

@pytest.fixture(autouse=True)
def BearerTokenSchema(patch):
    return patch("lms.resources._js_config.BearerTokenSchema")

@pytest.fixture
def bearer_token_schema(BearerTokenSchema):
    return BearerTokenSchema.return_value

@pytest.fixture
def js_config(context, pyramid_request):
    config = JSConfig(context, pyramid_request)
    config.enable_lti_launch_mode()
    return config

@pytest.fixture
def config(js_config):
    return js_config.asdict()

@pytest.fixture
def submission_params(config):
    return lambda: config["canvas"]["speedGrader"]["submissionParams"]

@pytest.fixture
def context():
    return mock.create_autospec(
        LTILaunchResource,
        spec_set=True,
        instance=True,
        h_group=mock.create_autospec(HGroup, instance=True, spec_set=True),
        is_canvas=True,
        canvas_sections_enabled=False,
    )

@pytest.fixture
def section_groups_on(context):
    context.canvas_sections_enabled = True

@pytest.fixture
def pyramid_request(pyramid_request):
    pyramid_request.params.update(
        {
            "lis_result_sourcedid": "example_lis_result_sourcedid",
            "lis_outcome_service_url": "example_lis_outcome_service_url",
            "context_id": "test_course_id",
            "custom_canvas_course_id": "test_course_id",
            "custom_canvas_user_id": "test_user_id",
        }
    )
    return pyramid_request

@pytest.fixture
def provisioning_disabled(ai_getter):
    ai_getter.provisioning_enabled.return_value = False

@pytest.fixture(autouse=True)
def via_url(patch):
    return patch("lms.resources._js_config.via_url")

@pytest.fixture(autouse=True)
def GroupInfo(patch):
    group_info_class = patch("lms.resources._js_config.GroupInfo")
    group_info_class.columns.return_value = ["context_id", "custom_canvas_course_id"]
    return group_info_class


from server.models.post import Post
from .base import BaseTestCase
import time
from server.models.user import User

class TestsPost(BaseTestCase):

    def test_endpoint_auth(self):

        endpoints = [
            ("groups/1/posts", "get"),
            ("groups/1/posts/create", "post")
        ]

        self.endpoint_auth_tester(endpoints)

    def test_posts(self):
        # create user
        email = "a@b.com"
        token = self.get_token(email=email)
        # create groups
        r, s, h = self.create_group("g1", tags=None, token=token)
        g1_id = r["id"]
        r, s, h = self.create_group("g2", tags=None, token=token)
        g2_id = r["id"]

        # invalid request
        r, s, h = self.create_post(group_id=g1_id, title=1, description="desc", token=token)
        self.assertEqual(s, 400)
        self.assertTrue("message" in r)

        # no title
        r, s, h = self.create_post(group_id=g1_id, title=None, description="desc", token=token)
        self.assertEqual(s, 400)
        self.assertTrue("message" in r)

        # no description
        r, s, h = self.create_post(group_id=g1_id, title="title", description=None, token=token)
        self.assertEqual(s, 400)
        self.assertTrue("message" in r)

        # non existing group
        r, s, h = self.create_post(group_id=100, title="title", description="desc", token=token)
        self.assertEqual(s, 404)

        # create post
        r, s, h = self.create_post(group_id=g1_id, title="title", description="desc", token=token)
        self.assertEqual(s, 201)
        self.assertEqual(r["id"], 1)
        self.assertEqual(r["title"], "title")
        self.assertEqual(r["description"], "desc")
        self.assertEqual(r["creator-id"], 1)
        self.assertEqual(r["group-id"], g1_id)
        self.assertAlmostEqual(r["created-at"], time.time(), delta=1)

        # create more posts
        self.create_post(group_id=g1_id, title="title", description="desc", token=token)
        self.create_post(group_id=g1_id, title="title", description="desc", token=token)
        self.create_post(group_id=g1_id, title="title", description="desc", token=token)
        self.create_post(group_id=g2_id, title="title", description="desc", token=token)
        self.create_post(group_id=g2_id, title="title", description="desc", token=token)

        user = User.query.filter_by(email=email).first()
        self.assertEqual(len(user.posts_created.all()), 6)
        posts = Post.query.all()
        for post in posts:
            self.assertEqual(post.creator.id, user.id)

        # get posts
        r, s, h = self.get(url=f"/groups/{g1_id}/posts", token=token)
        self.assertEqual(s, 200)
        self.assertEqual(r["group-id"], g1_id)
        self.assertEqual(len(r["posts"]), 4)
        # posts are sorted by create time
        posts = r["posts"]
        for i in range(len(posts)-1):
            self.assertTrue(posts[i]["created-at"] >= posts[i+1]["created-at"])

        # get posts
        r, s, h = self.get(url=f"/groups/{g2_id}/posts", token=token)
        self.assertEqual(s, 200)
        self.assertEqual(r["group-id"], g2_id)
        self.assertEqual(len(r["posts"]), 2)


import sys, getopt, os, pickle
import numpy as np
import tensorflow as tf
import librosa

sys.path.insert(0,'..')
from global_vars import subdirectory_list, n_fft, n_mels, t, hop_length, sr, genres
from shared_func import print_and_exit

help_msg = 'data_preprocessing.py -d <dir>, where dir is the directory containing labeled sub-dirs in which the .wav files are located'

# The following functions can be used to convert a value to a type compatible
# with tf.Example. https://www.tensorflow.org/tutorials/load_data/tfrecord#tfexample

def _bytes_feature(value):
  """Returns a bytes_list from a string / byte."""
  if isinstance(value, type(tf.constant(0))):
    value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _float_feature(value):
  """Returns a float_list from a float / double."""
  return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _int64_feature(value):
  """Returns an int64_list from a bool / enum / int / uint."""
  return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

def add_padding(array):
	padded = np.zeros((sr * 10))
	padded[0:array.shape[0]] = array

	return padded

#https://www.tensorflow.org/tutorials/load_data/tfrecord#creating_a_tfexample_message
def spectogram_to_example(spectogram, genre):
	feature = {
		'label': _int64_feature(genre),
		'spectogram': _bytes_feature(spectogram),
	}
	return tf.train.Example(features = tf.train.Features(feature = feature))

def create_spectogram(dir_to_browse, writer, genre):
	files = os.listdir(dir_to_browse)

	for file in files:
		y, _ = librosa.load(dir_to_browse + '/' + file, sr = sr)
		if(y.shape[0] < (10 * sr)):
			y = add_padding(y)
		spectogram = librosa.feature.melspectrogram(y = y, sr=sr, n_fft=n_fft, hop_length=hop_length, n_mels=n_mels)
		spectogram_pwr = librosa.power_to_db(spectogram, ref = np.max)

		spectogram_1d = np.reshape(spectogram_pwr, (n_mels * t)).tobytes()
		example = spectogram_to_example(spectogram_1d, genre)
		writer.write(example.SerializeToString())

#what if we already have the pickle but have updated the directory with the files -- this wont work correctly
# better to first create the pickle and then compare with old one if such exists
def maybe_create_spectograms(main_dir):
	genre_map = dict((label, idx) for idx, label in enumerate(genres))

	for subdir in subdirectory_list:
		curr_tf_record_path = main_dir + '/' + subdir + '.tfrecord'
		curr_subdir_path = main_dir + '/' + subdir
		if os.path.isfile(curr_tf_record_path):
			print(curr_tf_record_path, "already exists... skipping")
			continue

		print("Writing to ", curr_tf_record_path, "... ", end = "", flush = True)
		writer = tf.io.TFRecordWriter(path = curr_tf_record_path)
		for genre in genres:
			dir_to_browse = curr_subdir_path + '/' + genre
			create_spectogram(dir_to_browse, writer, genre_map[genre])
		print("done")

def main(argv):
	main_dir = ""

	try:
		opts, _ = getopt.getopt(argv,"h:d:",["main_dir="])
	except:
		print_and_exit(help_msg, 2)

	for opt, arg in opts:
		if opt == '-h':
			print_and_exit(help_msg, 0)
		elif opt == '-d':
			main_dir = arg

	if main_dir == "" :
		print_and_exit(help_msg, 2)

	maybe_create_spectograms(main_dir)

if __name__ == "__main__":
	main(sys.argv[1:])


'''
Prepare fields for Lawrence plots
- 3D fields for mass weighted OH
- 3D fields for reaction flux OH+CH4

Put data into boxes that correspond to those in Lawrence et al., 2001
'''
#**********************************************************
import netCDF4 as ncdf
import numpy as np
import tracer_var_codes as vcode

def lawr(jobid,nyrs):
    '''
OH mass weighted
output: 3D field, time average
    '''
    file    = ncdf.Dataset('/scratch/ih280/netscratch/um/'+jobid+'/'+jobid+'_oh.nc')
    oh      = file.variables['OH'][-12*nyrs:]
    oh      = np.mean(oh,axis=0)
    file.close()
    file    = ncdf.Dataset('/scratch/ih280/netscratch/um/'+jobid+'/'+jobid+'_P-theta.nc')
    P       = file.variables['p'][-12*nyrs:]
    P       = np.mean(P,axis=0)
    file.close()
    file    = ncdf.Dataset('/scratch/ih280/netscratch/um/'+jobid+'/'+jobid+'_airmass.nc')
    airmass = file.variables['airmass_atm'][-12*nyrs:]
    airmass = np.mean(airmass,axis=0)
    return (oh,P,airmass)

def boxes(pres, data_zm, mass_zm, zero, lat, hb, lb):
    '''
Distribute data into boxes
creates a mean box value for data, airmass and a zero variable
    '''
    # pbox: list of 12 lists for the 12 atm boxes
    # nb of vert boxes * nb of horiz boxes
    # The first step will result in a nested array which then has to be flattened.
    pbox1    = []
    pbox2    = []
    pbox3    = []
    # boxes: list of 12 lists for the 12 atm boxes
    # nb of vert boxes * nb of horiz boxes
    # Will contain flattened data from pbox1
    databox  = pbox1[:]
    massbox  = pbox2[:]
    zerobox  = pbox3[:]
    for i in range(len(hb)*(len(lb)-1)):
      pbox1.append([])
      pbox2.append([])
      pbox3.append([])
      databox.append([])
      massbox.append([])
      zerobox.append([])
    # Devide atmosphere into vertical boxes, spanning all latitudes
    # z contains indicies as a function of latitude for all pressure levels:
    # | z[2] | hb[1] > P >= hb[2]
    # | z[1] | hb[0] > P >= hb[1]
    # | z[0] |         P >= hb[0]
    z        = [[],[],[]]
    for i in range(len(lat)):
      z[0].append (np.where(  pres[:,i]>=hb[0] )                     [0])
      z[1].append (np.where(( pres[:,i]>=hb[1] ) & (pres[:,i]<hb[0]))[0])
      z[2].append (np.where(( pres[:,i]>=hb[2] ) & (pres[:,i]<hb[1]))[0])
    # Put data into the boxes.
    # This will result in a nested array, that then has to be flattened.
    # Use indices of z for the height boundaries.
    # Create latitude boundaries in loop.
    for i in range(len(lb)-1):              # number of lat boxes
      latlow  = np.where (lat >= lb[i]   )[0][ 0]
      lathigh = np.where (lat <  lb[i+1] )[0][-1]
      for l in range(latlow,lathigh+1):   # lat slice
        for h in range(len(hb)):        # number of vertical boxes
            pbox1[i*3+h].append (list( data_zm [z[h][l], l] ))
            pbox2[i*3+h].append (list( mass_zm [z[h][l], l] ))
            pbox3[i*3+h].append (list( zero    [z[h][l], l] ))
    # Flatten lists in pbox1
    for i in range(len(hb)*(len(lb)-1)):
      a=[]
      b=[]
      c=[]
      for k in pbox1[i]:
        for l in k:
            a.append(l)
      for k in pbox2[i]:
        for l in k:
            b.append(l)
      for k in pbox3[i]:
        for l in k:
            c.append(l)
      databox [i] = np.array( a[:] ) # OH
      massbox [i] = np.array( b[:] ) # Mass
      zerobox [i] = np.array( c[:] ) # Zeros
    del a, b, c, pbox1, pbox2, pbox3
    return (databox, massbox, zerobox)


"""Tests for pytype_runner.py."""

import os
import unittest

from pytype import config as pytype_config
from pytype import file_utils
from pytype import module_utils
from pytype.tools.analyze_project import parse_args
from pytype.tools.analyze_project import pytype_runner

class TestBase(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.parser = parse_args.make_parser()

class TestGetRunCmd(TestBase):
  """Test PytypeRunner.get_pytype_args()."""

  def setUp(self):
    self.runner = pytype_runner.PytypeRunner(
        [], [], self.parser.config_from_defaults())

  def get_basic_options(self, report_errors=False):
    module = module_utils.Module('foo', 'bar.py', 'bar')
    args = self.runner.get_pytype_args(module, report_errors)
    return pytype_config.Options(args)

  def test_pythonpath(self):
    self.assertEqual(self.get_basic_options().pythonpath, [self.runner.pyi_dir])

  def test_python_version(self):
    self.assertEqual(
        self.get_basic_options().python_version,
        tuple(int(i) for i in self.runner.python_version.split('.')))

  def test_output(self):
    self.assertEqual(self.get_basic_options().output,
                     os.path.join(self.runner.pyi_dir, 'bar.pyi'))

  def test_quick(self):
    self.assertTrue(self.get_basic_options().quick)

  def test_module_name(self):
    self.assertEqual(self.get_basic_options().module_name, 'bar')

  def test_error_reporting(self):
    # Disable error reporting
    options = self.get_basic_options(report_errors=False)
    self.assertFalse(options.report_errors)
    self.assertFalse(options.analyze_annotated)
    # Enable error reporting
    options = self.get_basic_options(report_errors=True)
    self.assertTrue(options.report_errors)
    self.assertTrue(options.analyze_annotated)

class TestYieldSortedModules(TestBase):
  """Tests for PytypeRunner.yield_sorted_modules()."""

  def normalize(self, d):
    return file_utils.expand_path(d).rstrip(os.sep) + os.sep

  def assert_sorted_modules_equal(self, mod_gen, expected_list):
    for path, target, name, expected_report_errors in expected_list:
      try:
        module, actual_report_errors = next(mod_gen)
      except StopIteration:
        raise AssertionError('Not enough modules')
      self.assertEqual(module, module_utils.Module(path, target, name))
      self.assertEqual(actual_report_errors, expected_report_errors)
    try:
      next(mod_gen)
    except StopIteration:
      pass
    else:
      # Too many modules
      raise AssertionError('Too many modules')

  def test_source(self):
    conf = self.parser.config_from_defaults()
    d = self.normalize('foo/')
    conf.pythonpath = [d]
    f = os.path.join(d, 'bar.py')
    runner = pytype_runner.PytypeRunner([f], [[f]], conf)
    self.assert_sorted_modules_equal(runner.yield_sorted_modules(),
                                     [(d, 'bar.py', 'bar', True)])

  def test_source_and_dep(self):
    conf = self.parser.config_from_defaults()
    d = self.normalize('foo/')
    conf.pythonpath = [d]
    source = os.path.join(d, 'bar.py')
    dep = os.path.join(d, 'baz.py')
    runner = pytype_runner.PytypeRunner([source], [[dep], [source]], conf)
    self.assert_sorted_modules_equal(
        runner.yield_sorted_modules(),
        [(d, 'baz.py', 'baz', False), (d, 'bar.py', 'bar', True)])

  def test_cycle(self):
    conf = self.parser.config_from_defaults()
    d = self.normalize('foo/')
    conf.pythonpath = [d]
    source = os.path.join(d, 'bar.py')
    dep = os.path.join(d, 'baz.py')
    runner = pytype_runner.PytypeRunner([source], [[dep, source]], conf)
    self.assert_sorted_modules_equal(
        runner.yield_sorted_modules(),
        [(d, 'baz.py', 'baz', False), (d, 'bar.py', 'bar', False),
         (d, 'baz.py', 'baz', False), (d, 'bar.py', 'bar', True)])

  def test_non_py_dep(self):
    conf = self.parser.config_from_defaults()
    d = self.normalize('foo/')
    conf.pythonpath = [d]
    dep = os.path.join(d, 'bar.so')
    runner = pytype_runner.PytypeRunner([], [[dep]], conf)
    self.assert_sorted_modules_equal(runner.yield_sorted_modules(), [])

  def test_non_pythonpath_dep(self):
    conf = self.parser.config_from_defaults()
    d = self.normalize('foo/')
    conf.pythonpath = [d]
    dep = file_utils.expand_path('bar/baz.py')
    runner = pytype_runner.PytypeRunner([], [[dep]], conf)
    self.assert_sorted_modules_equal(runner.yield_sorted_modules(), [])

if __name__ == '__main__':
  unittest.main()


#导入模块

import tkinter
#建立一个对话框
import tkinter.simpledialog as dl
#建立一个信息展示框
import tkinter.messagebox as mb
import random

#创建控件
top = tkinter.Tk()

#---------------
l = tkinter.Label(top,text="This is Label")

l.pack()
#文本对话框
mb.showinfo("MessageBox-Title","Hello MessageBox")

number = random.randrange(1,100)

while True:
    #输入对话框
    input_number = dl.askinteger("SimpleDialog-Title","Input Number")

    if input_number == number:
        output_dialog = "Right"
        mb.showinfo("Right",output_dialog)
        break
    elif input_number < number:
        output_dialog = "<Number"
        mb.showinfo("<",output_dialog)
    else:
        output_dialog = "Error"
        mb.showinfo("Error",output_dialog)

#listbox列表框控件
#--------------
# a = ['2222','3333']
# b = ['4444','5555']
#
# listb = tkinter.Listbox(top)
# listb2 = tkinter.Listbox(top)
#
# for item in a:
#     listb.insert(0,item)
#
# for item in b:
#     listb2.insert(0,item)
#
# listb.pack() #将控件放置在主窗口中
# listb2.pack()
#---------------------

top.mainloop()#进入消息循环

#master


from django.contrib.postgres.indexes import BrinIndex
from django.db import models
from django.utils.translation import gettext_lazy as _

from applications.accounts.models import User
from shared.models.transaction import AbstractTransaction

__all__ = 'Transaction',

class Transaction(AbstractTransaction):
    purpose_model = User

    purpose = models.ForeignKey(
        purpose_model,
        on_delete=models.PROTECT,
        related_name='transactions',
        verbose_name=_("Purpose")
    )

    class Meta:
        ordering = ('-created_at',)
        verbose_name = _('transaction')
        verbose_name_plural = _('transactions')
        indexes = (
            BrinIndex(fields=('created_at',)),
        )


# -*- coding: utf-8 -*-
import os
import sys

from setuptools import setup, find_packages

here = os.path.dirname(__file__)
version = __import__('faq').get_version()

def get_long_desc():
    return open(os.path.join(here, 'README.rst')).read()

if sys.argv[-1] == 'publish':
    os.system('python setup.py bdist_wheel upload -r natgeo')
    print("You probably want to also tag the version now:")
    print("  python setup.py tag")
    sys.exit()
elif sys.argv[-1] == 'tag':
    cmd = "git tag -a %s -m 'version %s';git push --tags" % (version, version)
    os.system(cmd)
    sys.exit()

setup(
    name='django-faq',
    version=version.replace(' ', '-'),
    description='Frequently Asked Question (FAQ) management for Django apps.',
    url='https://github.com/natgeosociety/django-faq/',
    author='Ben Spaulding',
    author_email='ben@benspaulding.us',
    license='BSD',
    long_description=get_long_desc(),
    packages=find_packages(exclude=['example*']),
    package_data={
        'faq': [
            'fixtures/*',
            'locale/*/LC_MESSAGES/*',
            'templates/faq/*',
            'templates/search/indexes/faq/*',
        ],
    },
    install_requires=['future'],
    classifiers=[
        'Development Status :: 4 - Beta',
        'Environment :: Web Environment',
        'Framework :: Django',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: BSD License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Topic :: Internet :: WWW/HTTP :: Site Management',
    ],
)


#!/usr/bin/env python3.4
import sys
import math

multiplication = {
    '1': {
        '1': (1, '1'),
        'i': (1, 'i'),
        'j': (1, 'j'),
        'k': (1, 'k')
    },
    'i': {
        '1': (1, 'i'),
        'i': (-1, '1'),
        'j': (1, 'k'),
        'k': (-1, 'j')
    },
    'j': {
        '1': (1, 'j'),
        'i': (-1, 'k'),
        'j': (-1, '1'),
        'k': (1, 'i')
    },
    'k': {
        '1': (1, 'k'),
        'i': (1, 'j'),
        'j': (-1, 'i'),
        'k': (-1, '1')
    }
}

def mult(tu, l):
    sign, sym = multiplication[tu[1]][l]
    return tu[0] * sign, sym

if __name__ == '__main__':
    for testCase in range(int(sys.stdin.readline())):
        letterCount, repeat = map(int, sys.stdin.readline().split())
        loop = sys.stdin.readline()
        cur = (1, '1')
        cursor = 0
        while cursor < 4 * letterCount:
            cur = mult(cur, loop[cursor % letterCount])
            cursor += 1
            if cur[0] == 1 and cur[1] == 'i':
                break
        if 4 * letterCount == cursor:
            print('Case #%d: NO' % (testCase + 1))
        else:
            cur = (1, '1')
            while cursor < 8 * letterCount:
                cur = mult(cur, loop[cursor % letterCount])
                cursor += 1
                if cur[0] == 1 and cur[1] == 'j':
                    break
            if 8 * letterCount == cursor:
                print('Case #%d: NO' % (testCase + 1))
            else:
                cur = (1, '1')
                while cursor < 12 * letterCount:
                    cur = mult(cur, loop[cursor % letterCount])
                    cursor += 1
                    if cur[0] == 1 and cur[1] == 'k':
                        break
                if 12 * letterCount == cursor:
                    print('Case #%d: NO' % (testCase + 1))
                elif repeat <= (cursor - 1) // letterCount:
                    print('Case #%d: NO' % (testCase + 1))
                else:
                    cur = (1, '1')
                    remaining = (repeat - 1 - (cursor - 1) // letterCount) % 4
                    while cursor % letterCount != 0:
                        cur = mult(cur, loop[cursor % letterCount])
                        cursor += 1
                    for i in range(remaining * letterCount):
                        cur = mult(cur, loop[cursor % letterCount])
                        cursor += 1
                    if cur[0] == 1 and cur[1] == '1':
                        print('Case #%d: YES' % (testCase + 1))
                    else:
                        print('Case #%d: NO' % (testCase + 1))


from pathlib import Path
from torch.utils.data import Dataset, ConcatDataset, DataLoader
from torchvision import transforms as trans
from torchvision.datasets import ImageFolder
from PIL import Image, ImageFile

ImageFile.LOAD_TRUNCATED_IMAGES = True
import numpy as np
import cv2
import bcolz
import pickle

from tqdm import tqdm
import random

def de_preprocess(tensor):
    return tensor * 0.5 + 0.5

def get_train_dataset(imgs_folder, train_transforms=None):
    if not train_transforms:
        train_transforms = trans.Compose([
            trans.RandomHorizontalFlip(),
            trans.ToTensor(),
            trans.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
        ])
    ds = ImageFolder(imgs_folder, train_transforms)
    class_num = ds[-1][1] + 1
    return ds, class_num

def get_custom_train_dataset(imgs_folder, train_transforms=None):
    class CustomDataset(ImageFolder):
        """__init__ and __len__ functions are the same as in TorchvisionDataset"""

        def __init__(self, root, transform=None):
            super(CustomDataset, self).__init__(root, transform=transform)

        def __getitem__(self, index):
            """
            Args:
                index (int): Index

            Returns:
                tuple: (sample, target) where target is class_index of the target class.
            """

            while True:
                try:
                    path, target = self.samples[index]
                    sample = np.array(self.loader(path))
                    if self.transform is not None:
                        sample = self.transform(image=sample)['image']
                    return sample, target
                except Exception as e:
                    import traceback
                    traceback.print_exc()
                    # traceback.print_exc()
                    print(str(e), path)
                    index = random.randint(0, len(self) - 1)

    ds = CustomDataset(imgs_folder, train_transforms)
    class_num = ds[-1][1] + 1
    return ds, class_num

def get_dacon_landmark_train_dataset(imgs_folder, train_transforms=None, label_file=None):
    import torch
    import json
    import os
    import glob

    class CustomDataset(torch.utils.data.Dataset):
        """__init__ and __len__ functions are the same as in TorchvisionDataset"""

        def __init__(self, root, transform=None, label_file=None):
            self.transform = transform
            labels = json.load(open(label_file))
            label_map = {}
            for label in labels['categories']:
                label_map[label['landmark_name']] = label['landmark_id']

            samples = []
            for dir in glob.glob(os.path.join(root, '*')):
                label_name = os.path.basename(dir)
                label_idx = label_map[label_name]
                for path in glob.glob(os.path.join(dir, "*")):
                    samples.append([path, label_idx])
            self.samples = samples

        def __getitem__(self, index):
            """
            Args:
                index (int): Index

            Returns:
                tuple: (sample, target) where target is class_index of the target class.
            """

            while True:
                try:
                    path, target = self.samples[index]
                    sample = np.array(Image.open(path).convert("RGB"))
                    if self.transform is not None:
                        sample = self.transform(image=sample)['image']
                    return sample, target
                except Exception as e:
                    # traceback.print_exc()
                    print(str(e), path)
                    index = random.randint(0, len(self) - 1)

        def __len__(self):
            return len(self.samples)

    ds = CustomDataset(imgs_folder, train_transforms, label_file)
    class_num = ds[-1][1] + 1
    return ds, class_num

def get_train_loader(conf, train_transforms=None):
    if conf.data_mode == 'common':
        ds, class_num = get_custom_train_dataset(conf.train_img_dir, train_transforms)
    elif conf.data_mode == 'dacon_landmark':
        ds, class_num = get_custom_train_dataset(conf.train_img_dir, train_transforms, conf.label_file)
    else:
        if conf.data_mode in ['ms1m', 'concat']:
            ms1m_ds, ms1m_class_num = get_train_dataset(conf.ms1m_folder / 'imgs')
            print('ms1m loader generated')
        if conf.data_mode in ['vgg', 'concat']:
            vgg_ds, vgg_class_num = get_train_dataset(conf.vgg_folder / 'imgs')
            print('vgg loader generated')
        if conf.data_mode == 'vgg':
            ds = vgg_ds
            class_num = vgg_class_num
        elif conf.data_mode == 'ms1m':
            ds = ms1m_ds
            class_num = ms1m_class_num
        elif conf.data_mode == 'concat':
            for i, (url, label) in enumerate(vgg_ds.imgs):
                vgg_ds.imgs[i] = (url, label + ms1m_class_num)
            ds = ConcatDataset([ms1m_ds, vgg_ds])
            class_num = vgg_class_num + ms1m_class_num
        elif conf.data_mode == 'emore':
            ds, class_num = get_train_dataset(conf.emore_folder / 'imgs')
    loader = DataLoader(ds, batch_size=conf.batch_size, shuffle=True, pin_memory=conf.pin_memory,
                        num_workers=conf.num_workers)
    return loader, class_num

def load_bin(path, rootdir, transform, image_size=[112, 112]):
    import mxnet as mx
    if not rootdir.exists():
        rootdir.mkdir()
    bins, issame_list = pickle.load(open(path, 'rb'), encoding='bytes')
    data = bcolz.fill([len(bins), 3, image_size[0], image_size[1]], dtype=np.float32, rootdir=rootdir, mode='w')
    for i in range(len(bins)):
        _bin = bins[i]
        img = mx.image.imdecode(_bin).asnumpy()
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
        img = Image.fromarray(img.astype(np.uint8))
        data[i, ...] = transform(img)
        i += 1
        if i % 1000 == 0:
            print('loading bin', i)
    print(data.shape)
    np.save(str(rootdir) + '_list', np.array(issame_list))
    return data, issame_list

def get_val_pair(path, name):
    carray = bcolz.carray(rootdir=path / name, mode='r')
    issame = np.load(path / '{}_list.npy'.format(name))
    return carray, issame

def get_common_val_data(data_path, max_positive_cnt, batch_size, pin_memory, num_workers, val_transforms=None,
                        use_pos=True, use_neg=True, val_smapling_type=None, use_keras_model=False):
    class ValDataset(Dataset):
        """__init__ and __len__ functions are the same as in TorchvisionDataset"""

        def __init__(self, files, transform=None):
            self.files = files
            self.transform = transform

        def __getitem__(self, index):
            """
            Args:
                index (int): Index

            Returns:
                tuple: (sample, target) where target is class_index of the target class.
            """
            file = self.files[index]
            im = Image.open(file).convert("RGB")
            sample = np.array(im)
            if self.transform is not None:
                sample = self.transform(image=sample)['image']

            if use_keras_model:
                from tensorflow.keras.preprocessing.image import img_to_array
                img = im
                w, h = img.size
                maxsz = max(w, h)
                scale = maxsz / 400

                img = img.resize((
                    int(w / scale), int(h / scale)
                ))

                return sample, img_to_array(img)
            else:
                return sample

        def __len__(self):
            return len(self.files)

    import glob
    import os

    if not use_pos and not use_neg:
        raise Exception("use_pos and use_neg all false")

    label_dirs = glob.glob(os.path.join(data_path, "*"))
    total_positive_cnt = 0
    label_files_list = []
    for label_dir in label_dirs:
        file_cnt = len(glob.glob(os.path.join(label_dir, "*")))
        total_positive_cnt += file_cnt * (file_cnt - 1) / 2
        if total_positive_cnt < 1:
            continue
        label_files_list.append(glob.glob(os.path.join(label_dir, "*")))
    print("total_positive_cnt", total_positive_cnt)
    if not max_positive_cnt or max_positive_cnt > total_positive_cnt:
        max_positive_cnt = total_positive_cnt

    if max_positive_cnt < 1:
        raise Exception("max_positive_cnt is 0")

    positive_files = []
    issame = []

    if val_smapling_type:
        unq_dirs = list({"_".join(d.split("_")[:-1]): True for d in label_dirs}.keys())
        if use_pos:
            each_cnt = max_positive_cnt / len(label_dirs)
            for label_idx, label_files in enumerate(label_files_list):
                cur_cnt = 0
                try:
                    for i in range(0, len(label_files) - 1):
                        for j in range(i + 1, len(label_files)):
                            positive_files.append(label_files[i])
                            positive_files.append(label_files[j])
                            cur_cnt += 1
                            if cur_cnt >= each_cnt:
                                raise
                except:
                    print("val positive label cnt", cur_cnt, os.path.basename(label_dirs[label_idx]))
                    pass
            max_positive_cnt = len(positive_files) // 2
            issame += [True] * int(len(positive_files) / 2)
            print("val positive cnt", len(positive_files))
        if val_smapling_type == "left_right_eye_half_same_dog":
            max_positive_cnt = max_positive_cnt // 2

        negative_files = []
        if use_neg:
            total_negative_cnt = 0
            idx_map = {}
            dir_map = {}
            while max_positive_cnt > total_negative_cnt:
                target_label_idx = random.randint(0, len(unq_dirs) - 1)
                left_dir = unq_dirs[target_label_idx] + "_left"
                right_dir = unq_dirs[target_label_idx] + "_right"
                if os.path.basename(left_dir) not in dir_map:
                    dir_map[os.path.basename(left_dir)] = glob.glob(os.path.join(left_dir, "*"))
                if os.path.basename(right_dir) not in dir_map:
                    dir_map[os.path.basename(right_dir)] = glob.glob(os.path.join(right_dir, "*"))
                if len(dir_map[os.path.basename(left_dir)]) < 1:
                    print("empty", left_dir)
                    continue
                if len(dir_map[os.path.basename(right_dir)]) < 1:
                    print("empty", right_dir)
                    continue
                left_item_idx = random.randint(0, len(dir_map[os.path.basename(left_dir)]) - 1)
                right_item_idx = random.randint(0, len(dir_map[os.path.basename(right_dir)]) - 1)
                if "{}_{}_{}".format(target_label_idx, left_item_idx, right_item_idx) in idx_map:
                    continue
                idx_map["{}_{}_{}".format(target_label_idx, left_item_idx, right_item_idx)] = True
                negative_files.append(dir_map[os.path.basename(left_dir)][left_item_idx])
                negative_files.append(dir_map[os.path.basename(right_dir)][right_item_idx])
                print("================")
                print(dir_map[os.path.basename(left_dir)][left_item_idx])
                print(dir_map[os.path.basename(right_dir)][right_item_idx])
                total_negative_cnt += 1

            if val_smapling_type == "left_right_eye":
                issame += [False] * int(len(negative_files) / 2)
                print("val negative cnt", len(negative_files))

        if val_smapling_type == "left_right_eye_half_same_dog":
            idx_map = {}
            total_negative_cnt = 0
            while max_positive_cnt > total_negative_cnt:
                target_label_idx = random.randint(0, len(label_files_list) - 1)
                if len(label_files_list[target_label_idx]) < 1:
                    continue
                target_item_idx = random.randint(0, len(label_files_list[target_label_idx]) - 1)
                neg_label_idx = random.randint(0, len(label_files_list) - 1)
                while target_label_idx == neg_label_idx:
                    neg_label_idx = random.randint(0, len(label_files_list) - 1)

                if len(label_files_list[neg_label_idx]) < 1:
                    continue
                neg_item_idx = random.randint(0, len(label_files_list[neg_label_idx]) - 1)

                if "{}_{}_{}_{}".format(target_label_idx, target_item_idx, neg_label_idx, neg_item_idx) in idx_map:
                    continue
                idx_map["{}_{}_{}_{}".format(target_label_idx, target_item_idx, neg_label_idx, neg_item_idx)] = True
                negative_files.append(label_files_list[target_label_idx][target_item_idx])
                negative_files.append(label_files_list[neg_label_idx][neg_item_idx])
                print("================")
                print(label_files_list[target_label_idx][target_item_idx])
                print(label_files_list[neg_label_idx][neg_item_idx])
                total_negative_cnt += 1
            issame += [False] * int(len(negative_files) / 2)
            print("val negative cnt", len(negative_files))
    else:
        if use_pos:
            each_cnt = max_positive_cnt / len(label_dirs)
            for label_idx, label_files in enumerate(label_files_list):
                cur_cnt = 0
                try:
                    for i in range(0, len(label_files) - 1):
                        for j in range(i + 1, len(label_files)):
                            positive_files.append(label_files[i])
                            positive_files.append(label_files[j])
                            cur_cnt += 1
                            if cur_cnt >= each_cnt:
                                raise
                except:
                    print("val positive label cnt", cur_cnt, os.path.basename(label_dirs[label_idx]))
                    pass
            max_positive_cnt = len(positive_files) // 2
            issame += [True] * int(len(positive_files) / 2)
            print("val positive cnt", len(positive_files))
        negative_files = []
        if use_neg:
            total_negative_cnt = 0
            idx_map = {}
            while max_positive_cnt > total_negative_cnt:
                target_label_idx = random.randint(0, len(label_files_list) - 1)
                if len(label_files_list[target_label_idx]) < 1:
                    continue
                target_item_idx = random.randint(0, len(label_files_list[target_label_idx]) - 1)
                neg_label_idx = random.randint(0, len(label_files_list) - 1)
                while target_label_idx == neg_label_idx:
                    neg_label_idx = random.randint(0, len(label_files_list) - 1)

                if len(label_files_list[neg_label_idx]) < 1:
                    continue
                neg_item_idx = random.randint(0, len(label_files_list[neg_label_idx]) - 1)

                if "{}_{}_{}_{}".format(target_label_idx, target_item_idx, neg_label_idx, neg_item_idx) in idx_map:
                    continue
                idx_map["{}_{}_{}_{}".format(target_label_idx, target_item_idx, neg_label_idx, neg_item_idx)] = True
                negative_files.append(label_files_list[target_label_idx][target_item_idx])
                negative_files.append(label_files_list[neg_label_idx][neg_item_idx])
                total_negative_cnt += 1
            issame += [False] * int(len(negative_files) / 2)
            print("val negative cnt", len(negative_files))

    loader = DataLoader(ValDataset(positive_files + negative_files, val_transforms), batch_size=batch_size,
                        shuffle=False, pin_memory=pin_memory,
                        num_workers=num_workers)
    return loader, issame

def get_val_data(data_path):
    agedb_30, agedb_30_issame = get_val_pair(data_path, 'agedb_30')
    cfp_fp, cfp_fp_issame = get_val_pair(data_path, 'cfp_fp')
    lfw, lfw_issame = get_val_pair(data_path, 'lfw')
    return agedb_30, cfp_fp, lfw, agedb_30_issame, cfp_fp_issame, lfw_issame

def load_mx_rec(rec_path):
    import mxnet as mx
    save_path = rec_path / 'imgs'
    if not save_path.exists():
        save_path.mkdir()
    imgrec = mx.recordio.MXIndexedRecordIO(str(rec_path / 'train.idx'), str(rec_path / 'train.rec'), 'r')
    img_info = imgrec.read_idx(0)
    header, _ = mx.recordio.unpack(img_info)
    max_idx = int(header.label[0])
    for idx in tqdm(range(1, max_idx)):
        img_info = imgrec.read_idx(idx)
        header, img = mx.recordio.unpack_img(img_info)
        label = int(header.label)
        img = Image.fromarray(img)
        label_path = save_path / str(label)
        if not label_path.exists():
            label_path.mkdir()
        img.save(label_path / '{}.jpg'.format(idx), quality=95)

# class train_dataset(Dataset):
#     def __init__(self, imgs_bcolz, label_bcolz, h_flip=True):
#         self.imgs = bcolz.carray(rootdir = imgs_bcolz)
#         self.labels = bcolz.carray(rootdir = label_bcolz)
#         self.h_flip = h_flip
#         self.length = len(self.imgs) - 1
#         if h_flip:
#             self.transform = trans.Compose([
#                 trans.ToPILImage(),
#                 trans.RandomHorizontalFlip(),
#                 trans.ToTensor(),
#                 trans.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
#             ])
#         self.class_num = self.labels[-1] + 1

#     def __len__(self):
#         return self.length

#     def __getitem__(self, index):
#         img = torch.tensor(self.imgs[index+1], dtype=torch.float)
#         label = torch.tensor(self.labels[index+1], dtype=torch.long)
#         if self.h_flip:
#             img = de_preprocess(img)
#             img = self.transform(img)
#         return img, label


import tensorflow as tf
import numpy as np
from tensorflow.python.ops.rnn_cell import LSTMCell, LSTMStateTuple, MultiRNNCell
import os
import random
os.environ["CUDA_VISIBLE_DEVICES"] = '0' #共4個gpu

"""Usage
Declare a Seq2Seq instance : model = Seq2Seq(vac_size)
Compile model : model.compile()
Train model : model.fit(xs, ys, batch_size, epoch)
"""
class Model():
    def __init__(self, batch_size , max_len, args , dictionary_x, dictionary_y, dtype = tf.float32):
        # model parameter
        self.dtype = dtype
        self.max_len = max_len
        self.dictionary_x = dictionary_x
        self.dictionary_y = dictionary_y
        self.val_size_x = len(dictionary_x)
        self.val_size_y = len(dictionary_y)
        self.encoder_units = self.val_size_x*2
        self.encoder_lay_Num = 3
        self.args = args
        self.batch_size = batch_size

        # feed tensor
        self.xs_PH = tf.placeholder(dtype = self.dtype, shape = [self.batch_size, self.max_len])
        self.ys_PH = tf.placeholder(dtype = self.dtype, shape = [self.batch_size, self.max_len])
        self.inputs_length_PH = tf.placeholder(dtype = tf.int32, shape = [self.batch_size])
        self.inputs_length_test_PH = tf.placeholder(dtype = tf.int32, shape = [1])

        # define session
        config = tf.ConfigProto()
        config.gpu_options.allow_growth = True
        self.sess = tf.Session(config = config)

        #compile the model
        self.compile()

    def Encoder(self, xs):
        encoder_input = tf.one_hot(tf.cast(xs, tf.int32), self.val_size)

        encoder_input = tf.layers.dense(inputs=encoder_input,
            units=self.encoder_units, activation=tf.nn.relu)

        if self.args.train:
            inputs_length = self.inputs_length_PH
        elif self.args.test:
            inputs_length = self.inputs_length_test_PH

        multirnn_cell = MultiRNNCell([LSTMCell(self.encoder_units)
            for _ in range(self.encoder_lay_Num)],  state_is_tuple=True)

        (fw_outputs, bw_outputs), (fw_final_state, bw_final_state) = (
            tf.nn.bidirectional_dynamic_rnn(cell_fw=multirnn_cell,
                                            cell_bw=multirnn_cell, inputs=encoder_input,
                                            sequence_length=inputs_length, dtype=self.dtype))

        sentence_code = tf.concat((fw_outputs, bw_outputs), axis = 2)

        sentence_code_ = []
        for i in range(self.batch_size):
            sentence_code_.append(sentence_code[i,inputs_length[i]-1,:])

        sentence_code = tf.stack(sentence_code_)

        encoder_output = tf.layers.dense(inputs=sentence_code, units=self.encoder_units, activation=tf.nn.relu)
        encoder_output = tf.layers.dense(inputs=encoder_output, units=self.encoder_units, activation=tf.nn.relu)
        encoder_output = tf.layers.dense(inputs=encoder_output, units=self.classification_num, activation=tf.nn.relu)
        encoder_output = tf.layers.dense(inputs=encoder_output, units=self.classification_num, activation=tf.nn.relu)

        return encoder_output

    def compile(self):

        encoder_output = self.Encoder(self.xs_PH)

        # compute model loss
        cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
            logits=encoder_output,
            labels=self.ys_PH)

        self.loss = tf.reduce_mean(cross_entropy)

        # predict tensor
        self.prediction = tf.argmax(encoder_output, 1)

        # define train_op and initialize variable
        self.train_op = tf.train.AdamOptimizer().minimize(self.loss)
        self.sess.run(tf.global_variables_initializer())
        self.saver = tf.train.Saver()

    def fit(self, xs, ys, batch_size, epoch):

        data_len = len(xs)
        batch_offset = 0
        ep_loss = 0
        batch_run = 0

        while batch_offset < (data_len-batch_size):
            _, batch_loss = self.sess.run([self.train_op, self.loss],
                                          feed_dict = {self.xs_PH : xs[batch_offset:batch_offset + batch_size],
                                                       self.ys_PH : ys[batch_offset:batch_offset + batch_size],
                                                       self.inputs_length_PH : self.get_inputs_length(batch_size , xs[batch_offset:batch_offset + batch_size])})

            batch_offset += batch_size
            batch_run += 1

            #print('loss: {0:3f} | finish: {1:3f}%'.format(batch_loss, (batch_offset/data_len)*100))

            ep_loss += batch_loss

        print('epoch: {0} | loss: {1:3f}'.format(epoch, ep_loss/batch_run))

        return (ep_loss/batch_run)

    def predict(self, x):
        index = self.sess.run([self.prediction] ,  feed_dict = {
            self.xs_PH : self.create_index(x),
            self.inputs_length_test_PH : self.get_inputs_length(1 , self.create_index(x))})

        return index[0][0]

    def get_inputs_length(self , batch_size , x):
        inputs_length = np.zeros((batch_size))
        for i in range(batch_size):
            inputs_length[i] = self.max_len
            for ii in range(self.max_len):
                if int(x[i][ii]) == 2:
                    inputs_length[i] = int(ii)
                    break
        return inputs_length

    def create_index(self , x):
        test_x = np.zeros((1,self.max_len))

        for i in range(self.max_len):
            if i < len(x):
                if x[i] in self.dictionary:
                    test_x[0][i] = self.dictionary.index(x[i])
                else:
                    test_x[0][i] = 3
            elif i == len(x):
                test_x[0][i] = 2
            else:
                test_x[0][i] = 0

        #clean the unknown word
        test_x_ = np.zeros((1,self.max_len))
        index = 0
        for i in range(self.max_len):
            if test_x[0][i] == 3:
                pass
            else:
                test_x_[0][index] = test_x[0][i]
                index += 1
        test_x = test_x_

        return test_x

    def save(self):
        save_path = os.getcwd() + '/model_file/domain_classification/model.ckpt'

        self.saver.save(self.sess, save_path)

        return

    def restore(self):

        model_file = os.getcwd() + '/model_file/domain_classification/model.ckpt'

        if os.path.isdir(os.path.dirname(model_file)):
            self.saver = tf.train.Saver()
            self.saver.restore(self.sess, model_file)

        return