""" Tests covering the pipeline schema code.
"""

import json
import os
import shutil
import tempfile
import unittest
from unittest import mock

import pytest
import requests
import yaml

import nf_core.create
import nf_core.schema

from .utils import with_temporary_file, with_temporary_folder

class TestSchema(unittest.TestCase):
    """Class for schema tests"""

    def setUp(self):
        """Create a new PipelineSchema object"""
        self.schema_obj = nf_core.schema.PipelineSchema()
        self.root_repo_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

        # Create a test pipeline in temp directory
        self.tmp_dir = tempfile.mkdtemp()
        self.template_dir = os.path.join(self.tmp_dir, "wf")
        create_obj = nf_core.create.PipelineCreate(
            "testpipeline", "", "", outdir=self.template_dir, no_git=True, plain=True
        )
        create_obj.init_pipeline()

        self.template_schema = os.path.join(self.template_dir, "nextflow_schema.json")

    def tearDown(self):
        if os.path.exists(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)

    def test_load_lint_schema(self):
        """Check linting with the pipeline template directory"""
        self.schema_obj.get_schema_path(self.template_dir)
        self.schema_obj.load_lint_schema()

    def test_load_lint_schema_nofile(self):
        """Check that linting raises properly if a non-existant file is given"""
        with pytest.raises(AssertionError):
            self.schema_obj.get_schema_path("fake_file")

    def test_load_lint_schema_notjson(self):
        """Check that linting raises properly if a non-JSON file is given"""
        self.schema_obj.get_schema_path(os.path.join(self.template_dir, "nextflow.config"))
        with pytest.raises(AssertionError):
            self.schema_obj.load_lint_schema()

    @with_temporary_file
    def test_load_lint_schema_noparams(self, tmp_file):
        """
        Check that linting raises properly if a JSON file is given without any params
        """
        # write schema to a temporary file
        with open(tmp_file.name, "w") as fh:
            json.dump({"type": "fubar"}, fh)
        self.schema_obj.get_schema_path(tmp_file.name)
        with pytest.raises(AssertionError):
            self.schema_obj.load_lint_schema()

    def test_get_schema_path_dir(self):
        """Get schema file from directory"""
        self.schema_obj.get_schema_path(self.template_dir)

    def test_get_schema_path_path(self):
        """Get schema file from a path"""
        self.schema_obj.get_schema_path(self.template_schema)

    def test_get_schema_path_path_notexist(self):
        """Get schema file from a path"""
        with pytest.raises(AssertionError):
            self.schema_obj.get_schema_path("fubar", local_only=True)

    def test_get_schema_path_name(self):
        """Get schema file from the name of a remote pipeline"""
        self.schema_obj.get_schema_path("atacseq")

    def test_get_schema_path_name_notexist(self):
        """
        Get schema file from the name of a remote pipeline
        that doesn't have a schema file
        """
        with pytest.raises(AssertionError):
            self.schema_obj.get_schema_path("exoseq")

    def test_load_schema(self):
        """Try to load a schema from a file"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()

    def test_schema_docs(self):
        """Try to generate Markdown docs for a schema from a file"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        docs = self.schema_obj.print_documentation()
        assert self.schema_obj.schema["title"] in docs
        assert self.schema_obj.schema["description"] in docs
        for definition in self.schema_obj.schema.get("definitions", {}).values():
            assert definition["title"] in docs
            assert definition["description"] in docs

    @with_temporary_file
    def test_save_schema(self, tmp_file):
        """Try to save a schema"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()

        # Make a temporary file to write schema to
        self.schema_obj.schema_filename = tmp_file.name
        self.schema_obj.save_schema()

    @with_temporary_file
    def test_load_input_params_json(self, tmp_file):
        """Try to load a JSON file with params for a pipeline run"""
        # write schema to a temporary file
        with open(tmp_file.name, "w") as fh:
            json.dump({"input": "fubar"}, fh)
        self.schema_obj.load_input_params(tmp_file.name)

    @with_temporary_file
    def test_load_input_params_yaml(self, tmp_file):
        """Try to load a YAML file with params for a pipeline run"""
        # write schema to a temporary file
        with open(tmp_file.name, "w") as fh:
            yaml.dump({"input": "fubar"}, fh)
        self.schema_obj.load_input_params(tmp_file.name)

    def test_load_input_params_invalid(self):
        """Check failure when a non-existent file params file is loaded"""
        with pytest.raises(AssertionError):
            self.schema_obj.load_input_params("fubar")

    def test_validate_params_pass(self):
        """Try validating a set of parameters against a schema"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        self.schema_obj.input_params = {"input": "fubar.csv", "outdir": "results/"}
        assert self.schema_obj.validate_params()

    def test_validate_params_fail(self):
        """Check that False is returned if params don't validate against a schema"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        self.schema_obj.input_params = {"fubar": "input"}
        assert not self.schema_obj.validate_params()

    def test_validate_schema_pass(self):
        """Check that the schema validation passes"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        self.schema_obj.validate_schema(self.schema_obj.schema)

    def test_validate_schema_fail_noparams(self):
        """Check that the schema validation fails when no params described"""
        self.schema_obj.schema = {"type": "invalidthing"}
        with pytest.raises(AssertionError):
            self.schema_obj.validate_schema(self.schema_obj.schema)

    def test_validate_schema_fail_duplicate_ids(self):
        """
        Check that the schema validation fails when we have duplicate IDs in definition subschema
        """
        self.schema_obj.schema = {
            "definitions": {"groupOne": {"properties": {"foo": {}}}, "groupTwo": {"properties": {"foo": {}}}},
            "allOf": [{"$ref": "#/definitions/groupOne"}, {"$ref": "#/definitions/groupTwo"}],
        }
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.validate_schema(self.schema_obj.schema)
        assert exc_info.value.args[0] == "Duplicate parameter found in schema `definitions`: `foo`"

    def test_validate_schema_fail_missing_def(self):
        """
        Check that the schema validation fails when we a definition in allOf is not in definitions
        """
        self.schema_obj.schema = {
            "definitions": {"groupOne": {"properties": {"foo": {}}}, "groupTwo": {"properties": {"bar": {}}}},
            "allOf": [{"$ref": "#/definitions/groupOne"}],
        }
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.validate_schema(self.schema_obj.schema)
        assert exc_info.value.args[0] == "Definition subschema `groupTwo` not included in schema `allOf`"

    def test_validate_schema_fail_unexpected_allof(self):
        """
        Check that the schema validation fails when we an unrecognised definition is in allOf
        """
        self.schema_obj.schema = {
            "definitions": {"groupOne": {"properties": {"foo": {}}}, "groupTwo": {"properties": {"bar": {}}}},
            "allOf": [
                {"$ref": "#/definitions/groupOne"},
                {"$ref": "#/definitions/groupTwo"},
                {"$ref": "#/definitions/groupThree"},
            ],
        }
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.validate_schema(self.schema_obj.schema)
        assert exc_info.value.args[0] == "Subschema `groupThree` found in `allOf` but not `definitions`"

    def test_make_skeleton_schema(self):
        """Test making a new schema skeleton"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.pipeline_manifest["name"] = "nf-core/test"
        self.schema_obj.pipeline_manifest["description"] = "Test pipeline"
        self.schema_obj.make_skeleton_schema()
        self.schema_obj.validate_schema(self.schema_obj.schema)

    def test_get_wf_params(self):
        """Test getting the workflow parameters from a pipeline"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.get_wf_params()

    def test_prompt_remove_schema_notfound_config_returntrue(self):
        """Remove unrecognised params from the schema"""
        self.schema_obj.pipeline_params = {"foo": "bar"}
        self.schema_obj.no_prompts = True
        assert self.schema_obj.prompt_remove_schema_notfound_config("baz")

    def test_prompt_remove_schema_notfound_config_returnfalse(self):
        """Do not remove unrecognised params from the schema"""
        self.schema_obj.pipeline_params = {"foo": "bar"}
        self.schema_obj.no_prompts = True
        assert not self.schema_obj.prompt_remove_schema_notfound_config("foo")

    def test_remove_schema_notfound_configs(self):
        """Remove unrecognised params from the schema"""
        self.schema_obj.schema = {
            "properties": {"foo": {"type": "string"}, "bar": {"type": "string"}},
            "required": ["foo"],
        }
        self.schema_obj.pipeline_params = {"bar": True}
        self.schema_obj.no_prompts = True
        params_removed = self.schema_obj.remove_schema_notfound_configs()
        assert len(self.schema_obj.schema["properties"]) == 1
        assert "required" not in self.schema_obj.schema
        assert len(params_removed) == 1
        assert "foo" in params_removed

    def test_remove_schema_notfound_configs_childschema(self):
        """
        Remove unrecognised params from the schema,
        even when they're in a group
        """
        self.schema_obj.schema = {
            "definitions": {
                "subSchemaId": {
                    "properties": {"foo": {"type": "string"}, "bar": {"type": "string"}},
                    "required": ["foo"],
                }
            }
        }
        self.schema_obj.pipeline_params = {"bar": True}
        self.schema_obj.no_prompts = True
        params_removed = self.schema_obj.remove_schema_notfound_configs()
        assert len(self.schema_obj.schema["definitions"]["subSchemaId"]["properties"]) == 1
        assert "required" not in self.schema_obj.schema["definitions"]["subSchemaId"]
        assert len(params_removed) == 1
        assert "foo" in params_removed

    def test_add_schema_found_configs(self):
        """Try adding a new parameter to the schema from the config"""
        self.schema_obj.pipeline_params = {"foo": "bar"}
        self.schema_obj.schema = {"properties": {}}
        self.schema_obj.no_prompts = True
        params_added = self.schema_obj.add_schema_found_configs()
        assert len(self.schema_obj.schema["properties"]) == 1
        assert len(params_added) == 1
        assert "foo" in params_added

    def test_build_schema_param_str(self):
        """Build a new schema param from a config value (string)"""
        param = self.schema_obj.build_schema_param("foo")
        assert param == {"type": "string", "default": "foo"}

    def test_build_schema_param_bool(self):
        """Build a new schema param from a config value (bool)"""
        param = self.schema_obj.build_schema_param("True")
        assert param == {"type": "boolean", "default": True}

    def test_build_schema_param_int(self):
        """Build a new schema param from a config value (int)"""
        param = self.schema_obj.build_schema_param("12")
        assert param == {"type": "integer", "default": 12}

    def test_build_schema_param_float(self):
        """Build a new schema param from a config value (float)"""
        param = self.schema_obj.build_schema_param("12.34")
        assert param == {"type": "number", "default": 12.34}

    def test_build_schema(self):
        """
        Build a new schema param from a pipeline
        Run code to ensure it doesn't crash. Individual functions tested separately.
        """
        param = self.schema_obj.build_schema(self.template_dir, True, False, None)

    @with_temporary_folder
    def test_build_schema_from_scratch(self, tmp_dir):
        """
        Build a new schema param from a pipeline with no existing file
        Run code to ensure it doesn't crash. Individual functions tested separately.

        Pretty much a copy of test_launch.py test_make_pipeline_schema
        """
        test_pipeline_dir = os.path.join(tmp_dir, "wf")
        shutil.copytree(self.template_dir, test_pipeline_dir)
        os.remove(os.path.join(test_pipeline_dir, "nextflow_schema.json"))

        param = self.schema_obj.build_schema(test_pipeline_dir, True, False, None)

    @mock.patch("requests.post")
    def test_launch_web_builder_timeout(self, mock_post):
        """Mock launching the web builder, but timeout on the request"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.Timeout()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    @mock.patch("requests.post")
    def test_launch_web_builder_connection_error(self, mock_post):
        """Mock launching the web builder, but get a connection error"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.ConnectionError()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    @mock.patch("requests.post")
    def test_get_web_builder_response_timeout(self, mock_post):
        """Mock checking for a web builder response, but timeout on the request"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.Timeout()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    @mock.patch("requests.post")
    def test_get_web_builder_response_connection_error(self, mock_post):
        """Mock checking for a web builder response, but get a connection error"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.ConnectionError()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    def mocked_requests_post(**kwargs):
        """Helper function to emulate POST requests responses from the web"""

        class MockResponse:
            def __init__(self, data, status_code):
                self.status_code = status_code
                self.content = json.dumps(data)

        if kwargs["url"] == "invalid_url":
            return MockResponse({}, 404)

        if kwargs["url"] == "valid_url_error":
            response_data = {"status": "error", "api_url": "foo", "web_url": "bar"}
            return MockResponse(response_data, 200)

        if kwargs["url"] == "valid_url_success":
            response_data = {"status": "recieved", "api_url": "https://nf-co.re", "web_url": "https://nf-co.re"}
            return MockResponse(response_data, 200)

    @mock.patch("requests.post", side_effect=mocked_requests_post)
    def test_launch_web_builder_404(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_url = "invalid_url"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.launch_web_builder()
        assert exc_info.value.args[0] == "Could not access remote API results: invalid_url (HTML 404 Error)"

    @mock.patch("requests.post", side_effect=mocked_requests_post)
    def test_launch_web_builder_invalid_status(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_url = "valid_url_error"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.launch_web_builder()
        assert exc_info.value.args[0].startswith("Pipeline schema builder response not recognised")

    @mock.patch("requests.post", side_effect=mocked_requests_post)
    @mock.patch("requests.get")
    @mock.patch("webbrowser.open")
    def test_launch_web_builder_success(self, mock_post, mock_get, mock_webbrowser):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_url = "valid_url_success"
        # Assertion error comes from the get_web_builder_response() function
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.launch_web_builder()
        assert exc_info.value.args[0].startswith("Could not access remote API results: https://nf-co.re")

    def mocked_requests_get(*args, **kwargs):
        """Helper function to emulate GET requests responses from the web"""

        class MockResponse:
            def __init__(self, data, status_code):
                self.status_code = status_code
                self.content = json.dumps(data)

        if args[0] == "invalid_url":
            return MockResponse({}, 404)

        if args[0] == "valid_url_error":
            response_data = {"status": "error", "message": "testing URL failure"}
            return MockResponse(response_data, 200)

        if args[0] == "valid_url_waiting":
            response_data = {"status": "waiting_for_user", "message": "testing URL waiting"}
            return MockResponse(response_data, 200)

        if args[0] == "valid_url_saved":
            response_data = {"status": "web_builder_edited", "message": "testing saved", "schema": {"foo": "bar"}}
            return MockResponse(response_data, 200)

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_404(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "invalid_url"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.get_web_builder_response()
        assert exc_info.value.args[0] == "Could not access remote API results: invalid_url (HTML 404 Error)"

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_error(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "valid_url_error"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.get_web_builder_response()
        assert exc_info.value.args[0] == "Got error from schema builder: 'testing URL failure'"

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_waiting(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "valid_url_waiting"
        assert self.schema_obj.get_web_builder_response() is False

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_saved(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "valid_url_saved"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.get_web_builder_response()
        assert exc_info.value.args[0].startswith("Response from schema builder did not pass validation")
        assert self.schema_obj.schema == {"foo": "bar"}


"""pro1 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from dal import autocomplete
from django.contrib import admin
from django.views.generic import TemplateView
from gst import views
from django.urls import reverse

#from gst.views import GST_idAutocomplete

urlpatterns = [
    url(r'^$',views.home),
    # url(
    #     r'^gst-autocomplete/$',
    #     GST_idAutocomplete.as_view(),
    #     name='gst-autocomplete',
    # ),

    url(r'^about/$',views.about),

    url(r'^business/$',views.business),
    url(r'^business/create/$',views.create_business),
    url(r'^business/update/$',views.update_business),
    url(r'^business/update/confirm/(?P<id>[0-9]+)$',views.update_confirm),
    url(r'^business/delete/$',views.delete_business),
    url(r'^business/delete/confirm/(?P<id>[0-9]+)$',views.delete_confirm_bus),
    url(r'^business/display/$',views.display),

    url(r'^product/$',views.product),
    url(r'^product/create/$',views.create_product),
    url(r'^product/update/$',views.update_product),
    url(r'^product/update/confirm/(?P<id>[0-9]+)$',views.product_update_confirm),
    url(r'^product/delete/$',views.delete_product),
    url(r'^product/delete/confirm/(?P<id>[0-9]+)$',views.delete_confirm),
    url(r'^product/display/$',views.productdisplay),

    url(r'^b2b/$',views.b2b),
    url(r'^b2b/add_txn/$',views.add_b2b_txn),
    url(r'^b2b/display_txn/$',views.display_b2b),
    url(r'^b2b/update_txn/$',views.update_b2b),
    url(r'^b2b/update/confirm/(?P<id>[0-9]+)$',views.b2b_update_confirm),
    url(r'^b2b/delete_txn/$',views.delete_b2b),
    url(r'^b2b/delete/confirm/(?P<id>[0-9]+)$',views.b2b_delete_confirm),

    url(r'^b2c/$',views.b2c),
    url(r'^b2c/add_txn/$',views.add_b2c_txn),
    url(r'^b2c/display_txn/$',views.display_b2c),
    url(r'^b2c/update_txn/$',views.update_b2c),
    url(r'^b2c/update/confirm/(?P<id>[0-9]+)$',views.b2c_update_confirm),
    url(r'^b2c/delete_txn/$',views.delete_b2c),
    url(r'^b2c/delete/confirm/(?P<id>[0-9]+)$',views.b2c_delete_confirm),

    url(r'^view_by_bussiness/$',views.view_by_bussiness),
    url(r'^view_by_bussiness/(?P<id>[0-9]+)$',views.view_con),

    url(r'^admin/', admin.site.urls),

]


import numpy as np
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score

import torch
import pickle
from scipy import interp

def inv_fpr_at_tpr_equals_half(tpr, fpr):
    base_tpr = np.linspace(0.05, 1, 476)
    fpr = fpr + 1e-20
    inv_fpr = interp(base_tpr, tpr, 1. / fpr)
    return np.mean(inv_fpr[225])

class Monitor:
    def __init__(self, name):
        self.value = None
        self.name = name
        self.scalar = True

    def __call__(self, **kwargs):
        self.value = self.call(**kwargs)
        return self.value

    def call(self, **kwargs):
        pass

class ROCAUC(Monitor):
    def __init__(self):
        super().__init__('roc_auc')

    def call(self, yy=None, yy_pred=None, w_valid=None, **kwargs):
        print(len(yy))
        print(len(yy_pred))
        return roc_auc_score(yy, yy_pred, sample_weight=w_valid)

class ROCCurve(Monitor):
    def __init__(self):
        super().__init__('roc_curve')
        self.scalar = False
        self.fpr, self.tpr = None, None

    def call(self, yy=None, yy_pred=None, w_valid=None, **kwargs):
        self.fpr, self.tpr, _ = roc_curve(yy, yy_pred, sample_weight=w_valid)
        return (self.fpr, self.tpr)

class InvFPR(Monitor):
    def __init__(self):
        super().__init__('inv_fpr')

    def call(self, yy=None, yy_pred=None, w_valid=None, **kwargs):
        fpr, tpr, _ = roc_curve(yy, yy_pred, sample_weight=w_valid)
        return inv_fpr_at_tpr_equals_half(tpr, fpr)

class Best(Monitor):
    def __init__(self, monitor, track='max'):
        super().__init__('best_' + monitor.name)
        self.monitor = monitor
        self.track = track
        if self.track == 'max':
            self.best_value = -np.inf
        elif self.track == 'min':
            self.best_value = np.inf
        else:
            raise ValueError("track must be max or min")
        self.changed = False

    def call(self, yy=None, yy_pred=None, w_valid=None, **kwargs):
        value = self.monitor.value
        print('============================')
        print(value)
        print('============================')
        if self.track == 'max':
            if value > self.best_value:
                self.changed = True
                self.best_value = value
            else:
                self.changed = False
        elif self.track == 'min':
            if value < self.best_value:
                self.changed = True
                self.best_value = value
            else:
                self.changed = False
        return self.best_value

class Regurgitate(Monitor):
    def __init__(self, value_name):
        self.value_name = value_name
        super().__init__(value_name)

    def call(self, **kwargs):
        self.value = kwargs[self.value_name]
        return self.value

class Saver(Monitor):
    def __init__(self, save_monitor, model_file, settings_file):
        self.saved = False
        self.save_monitor = save_monitor
        self.model_file = model_file
        self.settings_file = settings_file
        super().__init__('save')

    def call(self, model=None, settings=None, **kwargs):
        if self.save_monitor.changed:
            self.save(model, settings)
            self.value = True
        else:
            self.value = False
        return self.value

    def save(self, model, settings):
        with open(self.model_file, 'wb') as f:
            torch.save(model.cpu().state_dict(), f)
            if torch.cuda.is_available():
                model.cuda()
        with open(self.settings_file, "wb") as f:
            pickle.dump(settings, f)


import argparse
import time
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.optim as optim
from pytorch_models import networks

# パーサーの設定
parser = argparse.ArgumentParser()
parser.add_argument("net", type=str, help="ネットワークモデルの名前")
parser.add_argument("-e", "--epochs", type=int, default=1, help="学習エポック数")
parser.add_argument("-b", "--batch_size", type=int, default=16, help="学習時のバッチサイズ")
parser.add_argument("-a", "--best_accuracy", type=float, default=0., help="同じモデルの過去の最高精度")
parser.add_argument("--calc_statistics", type=bool, default=False, help="データセットのmean, stdを計算するかどうか")
args = parser.parse_args()

# オーグメント設定
def get_statistics():
    tmp_set = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transforms.ToTensor())
    data = torch.cat([d[0] for d in torch.utils.data.DataLoader(tmp_set)])
    return data.mean(dim=[0, 2, 3]), data.std(dim=[0, 2, 3])

if args.calc_statistics:
    mean, std = get_statistics()  # 各チャネルの平均，各チャネルの標準偏差
    print(f"このデータセットは mean: {mean.to('cpu').detach().numpy()}, std: {std.to('cpu').detach().numpy()} だっぴ！")
else:
    mean = [0.49139765, 0.48215759, 0.44653141]
    std = [0.24703199, 0.24348481, 0.26158789]

transform_train = transforms.Compose([
    transforms.RandomCrop(32, padding=4),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),  # Tensor
    transforms.Normalize(mean, std),
])
transform_test = transforms.Compose([
    transforms.ToTensor(),  # Tensor
    transforms.Normalize(mean, std),
])

# 学習データをダウンロード
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=args.batch_size, shuffle=True, num_workers=2)

# テストデータをダウンロード
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=args.batch_size, shuffle=False, num_workers=2)

# デバイスの設定
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"{device} で学習するっぴ！")

# モデルの選択
net = networks.get_net(args.net)
print(net)

# 損失関数
criterion = nn.CrossEntropyLoss()
# 最適化関数
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

# 学習
print("学習を始めるっぴ！")
epochs = args.epochs
best_acc = args.best_accuracy
bast_epoch = 0
start = time.time()
for epoch in range(1, epochs + 1):
    print("epoch: %d/%d" % (epoch, epochs))
    for phase in ['train', 'test']:
        if phase == 'train':  # 学習
            running_loss = 0.0
            for i, data in enumerate(trainloader, 0):
                # データの取得
                inputs, labels = data[0].to(device), data[1].to(device)
                # 勾配を初期化
                optimizer.zero_grad()
                # 順伝播，逆伝播，パラメータ更新
                outputs = net(inputs)
                loss = criterion(outputs, labels)
                loss.backward()
                optimizer.step()

                # loss の出力
                running_loss += loss.item()
                if i % 2000 == 1999:  # iが0からのカウントなので2000イテレーションごと
                    print("iter: %d, loss: %f, time: %ds" % (i + 1, running_loss / 2000, int(time.time() - start)))
                    running_loss = 0.0
        else:  # 評価
            correct = 0
            total = 0
            with torch.no_grad():
                for data in testloader:
                    # データの取得
                    images, labels = data[0].to(device), data[1].to(device)
                    # 順伝播，クラス判定
                    outputs = net(images)
                    _, predicted = torch.max(outputs.data, 1)
                    # 精度算出
                    total += labels.size(0)
                    correct += (predicted == labels).sum().item()
                    acc = correct / total
            print(f"Accuracy: {acc}")
            if acc > best_acc:
                # モデルの保存
                best_acc = acc
                bast_epoch = epoch
                weight_path = f"./cifar10_weight/{args.net}_bs{args.batch_size}.pth"
                torch.save(net.state_dict(), weight_path)

print("学習が終わったっぴ！")
print(f"一番精度が高い epoch は {bast_epoch} だっぴ！")


from django.conf.urls import url
from django.core.urlresolvers import reverse_lazy
from django.db.models import Q
from django.db.models.deletion import Collector
from django.utils.text import slugify
from django.views.generic import ListView, CreateView, UpdateView, DetailView, DeleteView

class DynamicListView(ListView):
    template_name = 'django_dynamic_views/dynamic_list_view.html'
    ajax_template_name = None
    field_names = None
    order_fields = None
    verbose_names = None
    convert_field_values = None
    search_fields = None
    filter_fields = None
    annotate_fields = None
    prefetch_related = []
    distinct = True

    def get_ajax_template_name(self):
        """
        Hook for returning the ajax template.

        Returns self.ajax_template_name if it exists, else the normal template.

        :return:
        """
        if self.ajax_template_name:
            return self.ajax_template_name

        return super(DynamicListView, self).get_template_names()

    def get_template_names(self):
        """
        When a request is made with AJAX, it returns the ajax_template_name
        Else the normal listview behaviour

        :return:
        """
        if self.request.is_ajax():
            return self.get_ajax_template_name()
        return super(DynamicListView, self).get_template_names()

    def get_field_names(self):
        """
        Return the field names defined in field_names attribute.
        If field_names does not exists, automatically get all the field names in the model

        :return: list of fieldnames
        """
        if self.field_names:
            return self.field_names
        return []

    def get_convert_field_values(self):
        """
        Dict with methods to be called on the view to convert a certain value

        :return: method name
        """
        if self.convert_field_values:
            return self.convert_field_values
        else:
            return {}

    def get_order_fields(self):
        """
        Return the field names defined in order_fields attribute.

        All the field that a user can order on. If not specified it returns all
         the fields that are defined in get_field_names that are present in
         the model.

        :return: list of field names
        """
        if self.order_fields:
            return self.order_fields
        return []

    def get_field_verbose_names(self):
        """
        Returns a dict with the verbose name of a field.
        E.g.:
        { 'name': _("Name"), 'max_value': _("Maximum value") }

        :return: dict with field -> verbose name mapping
        """
        if self.verbose_names:
            return self.verbose_names
        else:
            field_verbose_names = {}
            for name in self.get_field_names():
                field_verbose_names[name] = name

            return field_verbose_names

    def get_search_fields(self):
        """
        Hook to returns all the fields where can be searched in. The fields shall
        be suffixed with __icontains in the query

        :return: All the field where can be searched in
        """
        if self.search_fields:
            return self.search_fields
        else:
            return False

    @property
    def get_paginate_url(self):
        """
        The url it should paginate on. By default an empty string

        :return: string url
        """
        return ''

    def get_paginate_by(self, queryset):
        """
        Returns the numbers of pages per page in the list.
        First tries the GET parameter, then the value defined
        in the class attribute

        :return:
        """

        return self.request.GET.get('paginate_by', self.paginate_by)

    @property
    def search_phrase(self):
        """
        Propery method to determine the search phrase.

        :return: string search phrase
        """
        if self.request.GET.get('search_phrase') or self.request.GET.get('search_phrase') == '':
            return self.request.GET.get('search_phrase')

        return ''

    def add_queryset_search(self, queryset):
        """
        Modifies the query set with the search parameter.
        Creates an OR filter argument for every self.search_fields with the searchphrase.

        :param queryset: current queryset
        :return: modified queryset
        """
        if self.search_phrase:
            queries = [Q(**{'{}__{}'.format(search_field, 'icontains'): self.search_phrase}) for search_field in
                       self.get_search_fields()]

            # Set up the query
            query = Q()

            # Or the Q object with the ones remaining in the list
            for item in queries:
                query |= item

            queryset = queryset.filter(query)

        return queryset

    @property
    def order_by(self):
        """
        Propery method to determine the order by.
        First check if it is used in the url, then retrieve the user setting and else it is an empty string

        :return: string order by
        """
        order_by = self.request.GET.get('order_by', None)
        if order_by in self.get_field_names():
            if order_by in self.get_order_fields():
                if self.request.GET.get('sort') == 'DESC':
                    return '-%s' % order_by
                else:
                    return order_by

        return ''

    def add_queryset_ordering(self, query_set):
        """
        Sets the ordering on a query.

        :param query_set:
        :return: modified queryset
        """
        if self.order_by:
            return query_set.order_by(self.order_by)
        else:
            return query_set

    def get_filter_fields(self):
        """
        Hook to determine the filter fields.  The format it expects
        is requires a tuple dict. The first argument is the key used in the database
        and to be used for grouping, the other is the name the user sees in the UI

        *Example*

        ::

            (
                ('category__pk', 'category__name'),
                ('author__pk', 'author__name'),
            )

        """
        return self.filter_fields or []

    def get_filter_values(self):
        """
        Queries the database for the values that shall be used in the filtering dropdowns

        :returns list with tuples with the first argument the filter key and the second the value used for
        displaying in the UI
        """
        filter_values = []

        for filter_key, filter_name in self.get_filter_fields():
            values = [(o[filter_key], o[filter_name]) for o in
                      self.get_queryset().values(filter_key, filter_name).order_by(filter_key)]

            values.sort(key=lambda tup: tup[1])  # Sort on the filter_name

            sel_key = self.filter_kwargs.get(filter_key, '')
            selected_verbose = ''
            if sel_key:
                selected_verbose = dict(values).get(sel_key)
                if not selected_verbose:
                    try:
                        selected_verbose = dict(values).get(int(sel_key))
                    except Exception as e:
                        pass

            filter_values.append(
                (filter_key, self.verbose_names.get(filter_name), values, selected_verbose)
            )

        return filter_values

    @property
    def filter_kwargs(self):
        """
        Helper method to create the keyword arguments used in the queryset to actual filter the list
        """
        filter_kwargs = {}

        for filter_key, filter_name in self.get_filter_fields():
            filter_value = self.request.GET.get('filter-{}'.format(filter_key))
            if filter_value and filter_value != '---':
                filter_kwargs[filter_key] = str(filter_value)

        return filter_kwargs

    def add_queryset_filtering(self, queryset):
        """
        Modifies the queryset with the filtering of the queryset

        :param queryset:
        :returns modified queryset
        """

        if self.filter_kwargs:
            queryset = queryset.filter(**self.filter_kwargs)

        return queryset

    def add_queryset_annotating(self, queryset):
        if self.annotate_fields:
            queryset = queryset.annotate(**self.annotate_fields)

        return queryset

    def get_queryset(self):
        """
        Modifies the query set with all the magic this class contains
        We will add searching, ordering and filtering, as well add distinct and
        prefetch related to the queryset
        """
        queryset = super(DynamicListView, self).get_queryset()
        queryset = self.add_queryset_search(queryset)
        queryset = self.add_queryset_filtering(queryset)
        queryset = self.add_queryset_annotating(queryset)
        queryset = self.add_queryset_ordering(queryset)

        if self.distinct:
            queryset = queryset.distinct()

        if self.prefetch_related:
            queryset = queryset.prefetch_related(*self.prefetch_related)

        return queryset

    @staticmethod
    def nice_page_range(page_range, current_page):
        """
        Returns a page range with only the needed pages in it.

        :param page_range:
        :param current_page:
        :return:
        """
        display_around = 2
        if len(page_range) > display_around:
            # determine new start in range
            start = current_page - display_around
            if start < 1:
                start = 1
            # determine new end in range
            end = current_page + display_around + 1
            if end > len(page_range):
                end = len(page_range) + 1
            page_range = range(start, end)
        return page_range

    def get_context_data(self, **kwargs):
        context = super(DynamicListView, self).get_context_data(**kwargs)
        context['field_names'] = self.get_field_names()
        context['field_verbose_names'] = self.get_field_verbose_names()
        context['order_fields'] = self.get_order_fields()
        context['convert_field_values'] = self.get_convert_field_values()
        context['filter_fields'] = self.get_filter_fields()
        context['filter_values'] = self.get_filter_values()
        context['filter_kwargs'] = self.filter_kwargs
        context['num_fields'] = len(self.get_field_names())
        context['paginate_url'] = self.get_paginate_url
        context['search'] = True if self.get_search_fields() else False
        context['search_phrase'] = self.search_phrase
        if context['paginator']:
            context['nice_page_range'] = self.nice_page_range(context['paginator'].page_range,
                                                              context['page_obj'].number)

        if self.order_by:
            context['order_by'] = self.order_by[1:] if self.order_by[0] == '-' else self.order_by
            context['sort'] = 'ASC' if self.order_by[0] == '-' else 'DESC'

        return context

class AdminDynamicListView(DynamicListView):
    template_name = 'django_dynamic_views/admin_dynamic_list_view.html'
    title = None

    links = ['create', 'read', 'update', 'delete']
    create_text = None
    create_link = None
    read_link = None
    update_link = None
    delete_link = None

    @property
    def link_names(self):
        return {link: 'get_{}_link'.format(link) for link in self.links}

    def object_links(self):
        return [link for link in self.links if link not in ('create', 'list', )]

    def get_update_link(self):
        if self.update_link:
            return self.update_link
        else:
            return False

    def get_read_link(self):
        if self.read_link:
            return self.read_link
        else:
            return False

    def get_create_link(self):
        if self.create_link:
            return self.create_link
        else:
            return False

    def get_delete_link(self):
        if self.delete_link:
            return self.delete_link
        else:
            return False

    def get_title(self):
        if self.title:
            return self.title
        else:
            return ''

    def get_create_text(self):
        if self.create_text:
            return self.create_text
        else:
            return 'New'

    def get_context_data(self, **kwargs):
        context = super(AdminDynamicListView, self).get_context_data(**kwargs)
        context['links'] = self.links
        context['object_links'] = self.object_links
        context['link_names'] = self.link_names
        context['create_link'] = self.get_create_link()
        context['read_link'] = self.get_read_link()
        context['update_link'] = self.get_update_link()
        context['delete_link'] = self.get_delete_link()
        context['title'] = self.get_title()
        context['create_text'] = self.get_create_text()
        return context

class DynamicReadView(DetailView):
    template_name = 'django_dynamic_views/dynamic_read_view.html'
    field_names = None
    verbose_names = None

    def get_field_names(self):
        """
        Return the field names defined in field_names attribute.

        :return: list of fieldnames
        """
        if self.field_names:
            return self.field_names
        return []

    def get_field_verbose_names(self):
        """
        Returns a dict with the verbose name of a field.
        E.g.:
        { 'name': _("Name"), 'max_value': _("Maximum value") }

        :return: dict with field -> verbose name mapping
        """
        if self.verbose_names:
            return self.verbose_names
        else:
            field_verbose_names = {}
            for name in self.get_field_names():
                field_verbose_names[name] = name

            return field_verbose_names

    def get_context_data(self, **kwargs):
        context = super(DynamicReadView, self).get_context_data(**kwargs)
        context['field_names'] = self.get_field_names()
        context['field_verbose_names'] = self.get_field_verbose_names()
        return context

class DynamicDeleteView(DeleteView):
    template_name = 'django_dynamic_views/dynamic_delete_form.html'

    def get_context_data(self, **kwargs):
        context = super(DynamicDeleteView, self).get_context_data(**kwargs)

        collector = Collector(using='default') # or specific database
        collector.collect([self.object])
        to_delete = collector.instances_with_model()
        context['to_delete_list'] = []

        for x, y in to_delete:
            context['to_delete_list'].append((x.__name__, y,))

        return context

class DynamicUpdateView(UpdateView):
    template_name = 'django_dynamic_views/dynamic_form.html'
    field_names = None

    @property
    def fields(self):
        return self.field_names

class DynamicCreateView(CreateView):
    template_name = 'django_dynamic_views/dynamic_form.html'
    field_names = None

    @property
    def fields(self):
        return self.field_names

class DynamicCRUDView(object):
    model = None
    links = ['list', 'update', 'read', 'delete', 'create']

    field_names = ['pk']
    verbose_names = None

    update_kwargs = 'pk'
    update_kwargs_regexp = '(?P<pk>[-\w]+)'
    read_kwargs = 'pk'
    read_kwargs_regexp = '(?P<pk>[-\w]+)'
    delete_kwargs = 'pk'
    delete_kwargs_regexp = '(?P<pk>[-\w]+)'

    def get_view_kwargs(self):
        return {'model': self.model}

    def get_list_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        kwargs['links'] = self.links
        kwargs['verbose_names'] = self.verbose_names
        kwargs['paginate_by'] = getattr(self, 'paginate_by', None)

        for link in self.links:
            if link != 'list':
                kwargs['{}_link'.format(link)] = self.link_name(link)

        return kwargs

    def get_read_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        return kwargs

    def get_update_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        kwargs['success_url'] = reverse_lazy(self.link_name('list'))
        return kwargs

    def get_create_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        kwargs['success_url'] = reverse_lazy(self.link_name('list'))
        return kwargs

    def get_delete_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['success_url'] = reverse_lazy(self.link_name('list'))
        return kwargs

    @property
    def list_class(self):
        return AdminDynamicListView.as_view(**self.get_list_view_kwargs())

    @property
    def update_class(self):
        return DynamicUpdateView.as_view(**self.get_update_view_kwargs())

    @property
    def read_class(self):
        return DynamicReadView.as_view(**self.get_read_view_kwargs())

    @property
    def delete_class(self):
        return DynamicDeleteView.as_view(**self.get_delete_view_kwargs())

    @property
    def create_class(self):
        return DynamicCreateView.as_view(**self.get_create_view_kwargs())

    @property
    def model_name(self):
        return slugify(self.model.__name__)

    def link_name(self, link_name):
        return '{}_{}'.format(self.model_name, link_name)

    def urls(self):
        urls = []
        for link in self.links:
            if hasattr(self, '{}_link'.format(link)):
                link_name = getattr(self, '{}_link'.format(link))
            else:
                link_name = link

            url_check = r'{}/{}/'.format(self.model_name, link_name)

            if hasattr(self, '{}_kwargs'.format(link)):
                link_kwargs = getattr(self, '{}_kwargs_regexp'.format(link))
                url_check += '{}/'.format(link_kwargs)

            # Add start and end of line to regex pattern
            url_check = '^%s$' % url_check

            action_cls = getattr(self, '{}_class'.format(link))
            urls.append(url(url_check, action_cls, name=self.link_name(link)))

        return urls


import os
import io
import json
import requests
import aiohttp
import discord
from typing import Union

class Database():
    def __init__(self) -> None:
        self.url = os.getenv('GAS_PROJECT_URL')+'?'

    #DBへのPOST処理
    async def post_db(self, name:str, data:dict, **kwargs) -> requests.Response:
        base = {'name':name}
        payload = base|kwargs
        res = requests.post(url=self.url, params=payload, data=json.dumps(data))
        return res

    #DBへのGET処理
    async def get_db(self, name:str, **kwargs) -> Union[dict,list]:
        base = {'name':name}
        async with aiohttp.ClientSession() as session:
            async with session.get(url=self.url, params=base|kwargs) as resp:
                resj = await resp.json()
                return resj

class DiscordDatabase():
    def __init__(self) -> None:
        pass

    #DiscordDatabaseサーバーへの画像POST処理(一括)
    async def post_image(self, channel:discord.TextChannel, image:discord.Attachment, filename:str, content:str=None) -> str:
        imgby = await image.read() #bytes型で添付ファイルを取得
        imgbyio = io.BytesIO(imgby) #BytesIO型に変換
        file = discord.File(fp=imgbyio, filename=filename) #discord.Fileで添付ファイルを新規作成
        msg = await channel.send(content=content,file=file) #添付ファイル送信
        url = msg.attachments[0].url
        return url

    #DiscordDatabaseサーバーへの画像POST処理(受取のみ)
    async def post_iimage(self, channel:discord.TextChannel, image:io.BytesIO, filename:str, content:str=None) -> str:
        file = discord.File(fp=image, filename=filename) #discord.Fileで添付ファイルを新規作成
        msg = await channel.send(content=content,file=file) #添付ファイル送信
        url = msg.attachments[0].url
        return url


"""Invert emf_class_2_need_def dictionary."""
import logging
from typing import Any, Dict, Optional

from pyecore.ecore import EClass

logger = logging.getLogger(__name__)

def get_emf_class_from_need(need: Dict[str, Any], emf_class_2_need_def, mm_root) -> Optional[str]:
    """
    Try to derive the ECore class from a need type.

    3 strategies are used:

    1. Check whether whether one of the emf_class_2_need_def need_static settings for 'type' matches
    2. Check whether the need type matches any lower case key in emf_class_2_need_def
    3. Check whether the need type matches any lower case ECore EClass name of the meta model

    If none is successful, the function returns None.
    """
    # first look in need_static
    for emf_type, definitions in emf_class_2_need_def.items():
        if "type" in definitions["need_static"]:
            if definitions["need_static"]["type"] == need["type"]:
                return emf_type
    # now match the dictionary key
    all_emf_types = list(emf_class_2_need_def.keys())
    for emf_type in all_emf_types:
        if emf_type.lower() == need["type"]:
            return emf_type
    # now go through all EClass items in the meta model
    for item in mm_root.eClassifiers.items:
        if item.name.lower() == need["type"] and isinstance(item, EClass):
            return item.name
    logger.error(f"Cannot derive the ECore class for need id '{need['id']}' (type '{need['type']}')")
    return None


#!/usr/bin/env python

# Setup.py egregiously copied from another project I maintain
import sys
import distutils.core

from pip.download import PipSession
from pip.req import parse_requirements

__version__ = "0.1"

try:
    import setuptools
except ImportError:
    pass

def requires(path):
    return [str(r.req) for r in parse_requirements(path, session=PipSession())
            if r]

distutils.core.setup(
    name="babymailgun",
    version=__version__,
    packages=["babymailgun"],
    package_data={
        "babymailgun": [],
        },
    author="Matt Dietz",
    author_email="matthew.dietz@gmail.com",
    url="https://github.com/cerberus98/babymailgun",
    download_url="https://github.com/cerberus98/babymailgun",
    license="https://github.com/cerberus98/babymailgun/blob/master/LICENSE",
    description="",
    install_requires=requires("requirements.txt"),
    entry_points={
        "console_scripts": [
            "mailgun_cli = babymailgun.shell:main",
        ]}
    )


import pygame as pg
from .. import tools, prepare
from ..components.tournament import Tournament
from ..components.tournaments import TOURNAMENTS
from ..components.labels import GroupLabel as GLabel, Blinker

class Intro(tools._State):
    def __init__(self):
        super(Intro, self).__init__()
        screen = pg.display.get_surface().get_rect()
        font = prepare.FONTS["weblysleekuil"]
        snow_font = prepare.FONTS["SnowtopCaps"]
        self.labels = []
        title = GLabel(self.labels, snow_font, 96, "One Room Shack", "lightblue",
                                   {"midtop": (screen.centerx, screen.top + 20)})
        top = title.rect.bottom + 30
        left = 560
        lines = ["The cooler's well-stocked and there's wood in the stove so",
                    "grab a beer and pull up a bucket - it's ice fishing season!",
                    "YOU'll be competing in ice-fishing derbies to win as",
                    "much cash as you can before the season ends."]
        for line in lines:
            label = GLabel(self.labels, font, 32, line, "dodgerblue",
                                         {"topleft": (left, top)})
            top = label.rect.bottom + 3
        top += 20
        fishing = GLabel(self.labels, font, 48, "Catching Fish", "dodgerblue",
                                       {"midtop": (screen.centerx, top)})
        top = fishing.rect.bottom + 10
        fish_lines = ["Keep the end of your fishing line close to a fish's mouth until",
                           "the fish takes the bait. Drinking beer that a fish likes will make",
                           "them more likely to bite, but also makes controlling your fishing",
                           "rod more difficult."]
        for fish_line in fish_lines:
            fline = GLabel(self.labels, font, 32, fish_line, "dodgerblue",
                                        {"topleft": (left, top)})
            top = fline.rect.bottom + 3
        top += 20
        fc_title = GLabel(self.labels, font, 48, "Fishing Controls", "dodgerblue",
                                        {"midtop": (screen.centerx, top)})
        top = fc_title.rect.bottom + 10
        controls = [("UP / DOWN", "Let out / take in fishing line"),
                         ("LEFT / RIGHT", "Retract / extend fishing rod"),
                         ("SPACE", "Switch between drinking and fishing"),
                         ("ENTER", "Open Menu"),
                         ("ESCAPE", "Quit")]
        left1 = 860
        left2 = 960
        for control_pair in controls:
            key = GLabel(self.labels, font, 32, control_pair[0], "dodgerblue",
                                       {"topright": (left1, top)})
            use = GLabel(self.labels, font, 32, control_pair[1], "dodgerblue",
                                       {"topleft": (left2, top)})
            top = use.rect.bottom + 10

        self.blinker = Blinker(snow_font, 32, "Press Enter to continue", "dodgerblue",
                                       {"midbottom": (screen.centerx, screen.bottom - 20)}, 650)

    def startup(self, persistent):
        self.persist = persistent

    def get_event(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.done = True
                self.persist["tournament"] = Tournament(pg.Rect(0, 0, 10, 10), **TOURNAMENTS[0])
                self.next = "TOURNAMENT_INFO"

    def update(self, surface, keys, dt):
        self.draw(surface, dt)

    def draw(self, surface, dt):
        surface.fill(pg.Color("gray90"))
        for label in self.labels:
            label.draw(surface)
        self.blinker.draw(surface, dt)


from aiohttp import test_utils
import json
import pytest
from . import AioHttpInterface
from .. import aiohttp
from ..commonhttp import errors
from ..tests import fake_server
from ... import di, Story

story = None

def teardown_function(function):
    story and story.clear()

@pytest.fixture
def webhook_handler():
    return test_utils.make_mocked_coro(return_value={
        'status': 200,
        'content_type': 'application/json',
        'text': json.dumps({'message': 'Ok!'}),
    })

@pytest.mark.asyncio
async def test_post(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            assert await http.post(fake_server.URI.format('/v2.6/me/messages/'), json={'message': 'hello world!'})
            assert len(server.history) == 1
            req = server.history[-1]['request']
            assert req.content_type == 'application/json'
            assert await req.json() == {'message': 'hello world!'}

@pytest.mark.asyncio
async def test_listen_webhook(webhook_handler):
    http = AioHttpInterface(port=9876)
    http.webhook(uri='/webhook', handler=webhook_handler, token='qwerty')
    try:
        await http.start()
        res = await http.post_raw('http://localhost:9876/webhook', json={'message': 'Is there anybody in there?'})
        webhook_handler.assert_called_once_with({'message': 'Is there anybody in there?'})
        assert res['status'] == 200
        assert res['text'] == json.dumps({'message': 'Ok!'})
    finally:
        await http.stop()

@pytest.mark.asyncio
async def test_pass_validation_for_correct_request():
    http = AioHttpInterface(port=9876)
    http.webhook(uri='/webhook', handler=None, token='token-value')
    try:
        await http.start()
        res = await http.get_raw('http://localhost:9876/webhook', params={
            'hub.challenge': 'some-challenge',
            'hub.mode': 'subscribe',
            'hub.verify_token': 'token-value',
        })
        assert res['text'] == 'some-challenge'
    finally:
        await http.stop()

@pytest.mark.asyncio
async def test_reject_validation_for_incorrect_request():
    http = AioHttpInterface(port=9876)
    http.webhook(uri='/webhook', handler=None, token='token-value')
    try:
        await http.start()
        await http.get('http://localhost:9876/webhook', params={
            'something': 'incorrect',
        })
    except errors.HttpRequestError as err:
        assert err.code == 422
        assert err.message == 'Error, wrong validation token'
    finally:
        await http.stop()

@pytest.mark.asyncio
async def test_should_not_create_server_if_there_wasnt_any_webhooks():
    http = AioHttpInterface(port=9876)
    try:
        await http.start()
        assert not http.server
    finally:
        await http.stop()

@pytest.mark.skip(reason='too long')
@pytest.mark.asynciod
async def test_get_400_from_wrong_domain():
    http = AioHttpInterface()
    try:
        await http.get('http://wrong-url')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_get_400_from_wrong_path():
    http = AioHttpInterface()
    try:
        await http.get('http://localhost:9876/webhook')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_post_to_wrong_path_get_400(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            try:
                await http.post(fake_server.URI.format('/v2.6/me/messages/mistake'), json={'message': 'hello world!'})
            except errors.HttpRequestError as err:
                assert err.code == 404

@pytest.mark.skip(reason='too long')
@pytest.mark.asyncio
async def test_post_400_from_wrong_domain():
    http = AioHttpInterface()
    try:
        await http.post('http://wrong-url')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_post_400_from_wrong_path():
    http = AioHttpInterface()
    try:
        await http.post('http://localhost:9876/webhook')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_delete_200(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            await http.delete(fake_server.URI.format('/v2.6/me/messenger_profile'))

@pytest.mark.asyncio
async def test_delete_400(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            try:
                await http.delete(fake_server.URI.format('/v2.6/me/wrong'))
            except errors.HttpRequestError as err:
                assert err.code == 404

@pytest.mark.asyncio
async def test_pass_middleware(mocker, webhook_handler):
    handler_stub = mocker.stub()

    def MockMiddleware():
        async def middleware_factory(app, handler):
            async def mock_middleware_handler(request):
                handler_stub(request)
                return await handler(request)

            return mock_middleware_handler

        return middleware_factory

    try:
        http = AioHttpInterface(middlewares=[MockMiddleware()], port=8080)
        http.webhook(uri='/webhook', handler=webhook_handler, token='qwerty')
        await http.start()
        await http.post('http://localhost:8080/webhook', json={})
        assert handler_stub.called
    finally:
        await http.stop()

def test_get_as_deps():
    global story
    story = Story()
    story.use(aiohttp.AioHttpInterface())

    with di.child_scope('http'):
        @di.desc()
        class OneClass:
            @di.inject()
            def deps(self, http):
                self.http = http

        assert isinstance(di.injector.get('one_class').http, aiohttp.AioHttpInterface)

@pytest.mark.asyncio
async def test_shop_should_remove_app():
    http = aiohttp.AioHttpInterface()
    assert not http.has_app()
    http.get_app()
    assert http.has_app()
    await http.stop()
    assert not http.has_app()

@pytest.mark.asyncio
async def test_should_raise_exception_on_webhook_if_aiohttp_already_is_started(webhook_handler):
    http = aiohttp.AioHttpInterface()
    http.get_app()
    await http.start()
    with pytest.raises(aiohttp.WebhookException):
        http.webhook(uri='/webhook', handler=webhook_handler, token='qwerty')


from django.contrib import admin

from .models import GeoServerDomain, GeoserverWorkspace, OGCLayer, WebGISProject, Categories

class GeoServerDomainAdmin(admin.ModelAdmin):
    list_display = ["domain", "container_domain"]
    list_filter = ["publishing_date"]
    search_fields = ["domain"]
    fieldsets = [
        (None, {"fields": ["domain", "container_domain"]}),
    ]

    class Meta:
        model = GeoServerDomain

class GeoserverWorkspaceDomainAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["workspace"]}),
    ]

    class Meta:
        model = GeoserverWorkspace

class CategoriesAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug_category": ("category_name",)}
    fieldsets = [
                (None, {"fields": ["category_name", "slug_category"]}),
            ]

    class Meta:
        model = Categories

class OGCLayerAdmin(admin.ModelAdmin):
    list_display = ["title", "ogc_layer_name", "publishing_date", "ogc_bbox", "ogc_centroid", "complete_url_wms", "complete_url_wfs_wcs", "header_image"]
    list_filter = ["publishing_date"]
    search_fields = ["title"]
    prepopulated_fields = {"slug_post": ("title",)}
    fieldsets = [
                ("Meta description", {"fields": ["title", "slug_post", "description", "contents", "categories", "draft"]}),
                ("Geoserver", {"fields": ["geoserver_domain", "geoserver_workspace"]}),
                ("OGC Parameters", {"fields": [
                    "ogc_layer_name", "ogc_layer_style", "ogc_legend", "is_vector", "is_raster",
                ]}),
                ("OpenLayers Parameters",
                 {"fields": ["set_max_zoom", "set_min_zoom", "set_zindex", "set_opacity"]}
                 ),
            ]

    class Meta:
        model = OGCLayer

class WebGISProjectAdmin(admin.ModelAdmin):
    list_display = ["title", "description", "publishing_date", "updating_date", "highlighted", "draft", "meta_image"]
    list_filter = ["publishing_date"]
    search_fields = ["title"]
    prepopulated_fields = {"slug_post": ("title",)}
    fieldsets = [
                ("Meta description", {"fields": ["title", "slug_post", "header_image", "description"]}),
                ("Contents", {"fields": ["contents", "categories"]}),
                ("Options", {"fields": ["draft", "highlighted", "publishing_date"]}),
                ("OpenLayers Parameters",
                 {
                     "classes": ("collapse",),
                     "fields":
                      ["map_scaleline", "map_center_longitude", "map_center_latitude", "set_max_zoom", "set_min_zoom",
                       "set_zoom_level"
                       ]
                  }
                 ),
                ("OGC Layer",  {"fields": ["main_layer", "layers"]}),
            ]

    class Meta:
        model = WebGISProject

admin.site.register(GeoServerDomain, GeoServerDomainAdmin)
admin.site.register(GeoserverWorkspace, GeoserverWorkspaceDomainAdmin)
admin.site.register(Categories, CategoriesAdmin)
admin.site.register(OGCLayer, OGCLayerAdmin)
admin.site.register(WebGISProject, WebGISProjectAdmin)


from PyPDF2 import PdfMerger
import os

#Create an instance of PdfFileMerger() class
merger = PdfMerger()

#Define the path to the folder with the PDF files
path_to_files = r'C:/Users/kaabi/Downloads/Rent Slips Vitry/'

folder_name = os.path.split(path_to_files.rstrip('/'))[-1]

#Get the file names in the directory
for file_name in os.listdir(path_to_files):

    if file_name.endswith(".pdf"):
        merger.append(path_to_files + file_name)

#Write out the merged PDF file
merger.write(path_to_files + "/" + folder_name + ".pdf")
merger.close()

# -*- coding: utf-8 -*-
# """
# Created on Wed Sep  6 14:35:21 2023

# @author: kaabi
# """

# from PyPDF2 import PdfMerger
# import os

# #Create an instance of PdfFileMerger() class
# merger = PdfMerger()

# #Define the path to the folder with the PDF files
# path_to_files = r'C:/Users/ChimieENS/Downloads/Documents_RP/'

# #Get the file names in the directory
# for root, dirs, file_names in os.walk(path_to_files):
#     #Iterate over the list of the file names
#     for file_name in file_names:
#         #Append PDF files
#         merger.append(path_to_files + file_name)

# #Write out the merged PDF file
# merger.write("C:/Users/ChimieENS/Downloads/Documents_RP/merged_all_pages.pdf")
# merger.close()


from django.contrib import admin
from django.http import HttpResponse
from django.urls import path, include

def blank(request):
    return HttpResponse("For API Used Only")

urlpatterns = [
    path('', blank),
    path('admin/', admin.site.urls),
    path('api/v1/', include('upwork.urls'))
]


import os
from glob import glob

import matplotlib.pyplot as plt

from satlomasproc.unet.train import build_data_generator

def plot_data_generator(num_samples=3, fig_size=(20, 10), *, train_config):
    images_dir = os.path.join(train_config.images_path, 'images')
    mask_dir = os.path.join(train_config.images_path, 'masks')

    images = glob(os.path.join(images_dir, '*.tif'))

    data_generator = build_data_generator(images,
                                          config=train_config,
                                          mask_dir=mask_dir)

    def plot_samples(plt, generator, num):
        j = 0
        for image_batch, mask_batch in data_generator:
            for image, mask in zip(image_batch, mask_batch):
                _, ax = plt.subplots(nrows=1,
                                     ncols=train_config.n_classes + 1,
                                     figsize=fig_size)
                ax[0].imshow(image[:,:,:train_config.n_channels])
                for i in range(train_config.n_classes):
                    ax[i + 1].imshow(mask[:, :, i])
                j += 1
                if j >= num:
                    return

    plot_samples(plt, data_generator, num_samples)
    plt.show()


#######################################################################################

import feature_extraction.audio_to_feats as atf
import numpy as np
from numpy import *
import pickle
# import keras.models
import config
import keras
from dataset_tools import audio_converter as ac
from dataset_tools import dataset_management as dm
import os
import feature_extraction.map_json_to_feats as jtf

max_sequence_length = config.audioLengthMaxSeconds * 100  # 100 frames per second, or 10 ms per frame
deltaTimeNormalizer = 200  # number that timeFromPrev and timeToNext are divided by to make them more suitable for learning. Arbitrary choice: very roughly average distance between 2 onsets
finishers = config.permitFinishers

def batchGetSongFeatsFromAudios(songFeatPaths):  # needs to also analyze audio instead of just loading feats data, which hasn't been computed for a new audio
    songFeats = []
    tempWavDir = "data/temp/temp.wav"
    for item in songFeatPaths:

        ext = os.path.splitext(item)[-1].lower()
        assert(ext == ".mp3" or ext == ".ogg")

        # this includes standardization
        if ext == ".mp3":
            ac.mp3ToWav(item, tempWavDir)
        if ext == ".ogg":
            ac.oggToWav(item, tempWavDir)
        audioFeat = atf.makeFeats(tempWavDir)
        os.remove(tempWavDir)

        bandMeans = np.loadtxt("data/misc/bandMeans.txt")
        bandStdevs = np.loadtxt("data/misc/bandStdevs.txt")

        audioFeat = dm.normalize(audioFeat, bandMeans, bandStdevs)

        songFeats.append([item[:-4], audioFeat])
    return songFeats

def batchPrepareFeatsForModel(mapInfo, songFeats, SRs):  # mapInfo has tuples of id, onsets, notes for each map. songFeats has 15x40 per onset. Need to make unrollings.

    onsetCount = 0
    for map in mapInfo:
        onsetCount += len(map[1])

    pMapFeats = np.empty((onsetCount, 6+finishers), dtype=float32)  # Everything here should be filled TODO check
    pSongFeats = np.full((onsetCount, 1+2*config.colorAudioBookendLength, 40), config.pad)

    onsetIndex = 0

    # mapPad = np.array([-1,-1,-1,-1,-1,-1,-1,-1])
    # audioPad = np.full((1+2*config.colorAudioBookendLength, 40), config.pad)
    for i, map in enumerate(mapInfo):
        song = songFeats[i]
        sr = SRs[i]

        onsets = np.array(map[1]).astype(int)

        rolledMapData = []
        # don: 0
        # kat: 2/8/10
        # fdon: 4
        # fkat: 6/12/14
        for j, color in enumerate(map[2]):

            isFirstOnset = -1
            if j == 0:
                isFirstOnset = 1

            if j == 0:
                timeFromPrev = -1
                timeToNext = onsets[j+1] - onsets[j]
            elif j == len(onsets) - 1:
                timeFromPrev = onsets[j] - onsets[j-1]
                timeToNext = -1
            else:
                timeFromPrev = onsets[j] - onsets[j-1]
                timeToNext = onsets[j+1] - onsets[j]
            if finishers:
                rolledMapData.append(np.array([-1, -1, -1, -1, timeFromPrev / deltaTimeNormalizer, timeToNext / deltaTimeNormalizer, isFirstOnset, sr]))  # since we are predicting, all colors start 0
            else:
                rolledMapData.append(np.array([-1, -1, timeFromPrev / deltaTimeNormalizer, timeToNext / deltaTimeNormalizer, isFirstOnset, sr]))  # since we are predicting, all colors start 0

        # # Now make unrollings from rolledMapData...
        # for j, item in enumerate(rolledMapData):
        #     mapUnrollingsSet = np.empty((unrollings, 8), dtype=float32)
        #     songUnrollingsSet = np.empty((unrollings, 1+2*config.colorAudioBookendLength, 40), dtype=float32)
        #     for k in range(unrollings):  # 0 to 79
        #         indexToGet = j - unrollings + k  # first is 0 - 80 + 0, through 0 - 80 + 79
        #         if indexToGet < 0:
        #             mapUnrollingsSet[k] = mapPad
        #             songUnrollingsSet[k] = audioPad
        #         else:
        #             assert(indexToGet < len(rolledMapData))
        #             mapUnrollingsSet[k] = rolledMapData[indexToGet]
        #             songUnrollingsSet[k] = song[1][indexToGet]

        #     pMapFeats[onsetIndex] = mapUnrollingsSet
        #     pSongFeats[onsetIndex] = songUnrollingsSet
        #     onsetIndex += 1

    # assert(onsetIndex == onsetCount)

    return rolledMapData, song[1]

def addContextAndTrim(x, onsets, bookendLength):
# x.reshape(())   (config.audioLengthMaxSeconds, 40)?
    padding = np.full((1,40), config.pad, dtype=float32)  # TODO after normalization, this should be like -3 instead of -500. track minimum to determine this
    context = bookendLength
    window = 2*context + 1 # prepend and append context
    # want to create input_shape=(max_sequence_length,15,40) from (max_sequence_length, 40)
    out = np.zeros((len(onsets),window,40))
    onsets = np.array(onsets).astype(int)
    # onsets = onsets.astype(int)
    # #
    truths = onsets // 10

    for i, truth in enumerate(truths): # want: for each onset in onsets (need its corresponding index in x). Could scan and continue for misses.
        bookended = np.zeros((window,40), dtype=float32)
        for j in range (context*-1, context+1):
            indexToGet = int(truth) + j  # if at start of audio this is negative in first half, if at end this is out of bounds positive in second half
            if indexToGet < 0 or indexToGet >= len(x):
                bookended[j + context] = padding
            else:
                bookended[j + context] = x[indexToGet]
        out[i] = bookended
    return out

from dataset_tools import map_to_json_converter
def batchGetMapInfo(batch_maps):
    mapFeats = []
    for item in batch_maps:
        json = map_to_json_converter.mapToJson(item)
        id, onsets, notes, _ = jtf.jsonToFeatsColor(json)  # also passes back SR but we ignore that SR here
        cap = min(len(onsets), config.colorOnsetMax)  # TODO limiting, can remove maybe for prediction
        onsets = onsets[:cap]
        notes = notes[:cap]
        mapFeats.append([id, onsets, notes])
    return mapFeats

mapPad = np.array([-1,-1,-1,-1,-1,-1,-1,-1])
if not finishers:
    mapPad = np.array([-1,-1,-1,-1,-1,-1])
audioPad = np.full((1+2*config.colorAudioBookendLength, 40), config.pad)

def predict(unrollings, model, xMaps, xAudios, temperature): # initially via https://towardsdatascience.com/time-series-forecasting-with-recurrent-neural-networks-74674e289816
    #prediction_list = xMaps #close_data[-unrollings:]
    # TODO construct unrollings here per-onset
    # predictedColors = np.empty((len(xMaps), 4))

    # for i, onsetUnrolling in enumerate(xMaps):
    #     xMap = onsetUnrolling
    #     xAudio = xAudios[i]

    #     out = model.predict() #TODO

    #     predictedColors[i] = out
    #     # I would then need to add this prediction to the next 64 unrollings

    includeAudioFeats = config.includeAudioFeatsInColorModel

    originalMap = xMaps
    originalAudio = xAudios
    leadingSequenceMap = np.full((unrollings, 6+finishers), mapPad)
    leadingSequenceAudio = np.full((unrollings, 1+2*config.colorAudioBookendLength, 40), audioPad)

    # print(leadingSequenceMap.dtype.name + leadingSequenceAudio.dtype.name)

    assert(leadingSequenceMap.dtype.name == "int32")
    assert(leadingSequenceAudio.dtype.name == "float64")

    colorPredictions = []

    totals = [0,0,0,0]  # totals of colors predicted
    totalsRaw = [0.0,0.0,0.0,0.0]  # totals of raw prediction probabilities
    if not finishers:
        totals = [0,0]  # totals of colors predicted
        totalsRaw = [0.0,0.0]  # totals of raw prediction probabilities

    for i in range(len(xMaps)):  # TODO append map and sound data at top of loop, then update color once predicted
        # print(f"i: {i} - Shape of leadingSequenceMap: ")
        # print(leadingSequenceMap.shape)

        leadingSequenceMap = np.append(leadingSequenceMap, reshape(originalMap[i], (1, 6+finishers)), axis=0)
        if includeAudioFeats:
            leadingSequenceAudio = np.append(leadingSequenceAudio, reshape(originalAudio[i], (1, 1+2*config.colorAudioBookendLength, 40)), axis=0)

        xMap = leadingSequenceMap[-(unrollings+1):]  # x gets last 64 onsets
        if includeAudioFeats:
            xAudio = leadingSequenceAudio[-(unrollings+1):]  # x gets last 64 onsets

        # xMap[-1]

        # print(f"i: {i} - Shape of xMap: ")
        # print(xMap.shape)

        xMap = reshape(xMap, (1, unrollings+1, 6+finishers))  # model expects input in batch form, shapes get wonky if no extra first dimension
        if includeAudioFeats:
            xAudio = reshape(xAudio, (1, unrollings+1, 1+2*config.colorAudioBookendLength, 40))

        # print("Shape of xMap: ")
        # print(xMap.shape)
        # print("Shape of xAudio: ")
        # print(xAudio.shape)

        # x = x.reshape((1, unrollings, 1))

        if includeAudioFeats:
            out = model.predict([xMap, xAudio], verbose=0)#[0][0]  # if verbose, prints for every call to model.predict
        else:
            out = model.predict([xMap], verbose=0)

        # update leading sequences with new onset based on the predicted color combined with original data
        colorPrediction = solidifyColorPrediction(out[0], temperature)  # extra dimension in output, again because things are in batch form
        colorPredictions.append(colorPrediction)
        totals = [a + b for a, b in zip(totals, colorPrediction)]
        totalsRaw = [a + b for a, b in zip(totalsRaw, out[0])]

        if finishers:
            newOnsetMap = np.append(colorPrediction, [originalMap[i][4], originalMap[i][5], originalMap[i][6], originalMap[i][7]])
        else:
            assert(len(colorPrediction) == 2)
            newOnsetMap = np.append(colorPrediction, [originalMap[i][2], originalMap[i][3], originalMap[i][4], originalMap[i][5]])
        # newOnsetAudio = originalAudio[i]

        newOnsetMap = reshape(newOnsetMap, (1, 6+finishers))
        leadingSequenceMap[-1] = newOnsetMap  # update onset with predicted color

        # newOnsetAudio = reshape(newOnsetAudio, (1, 1+2*config.colorAudioBookendLength, 40))

        # leadingSequenceMap = np.append(leadingSequenceMap, newOnsetMap, axis=0)
        # leadingSequenceAudio = np.append(leadingSequenceAudio, newOnsetAudio, axis=0)

        if i > 0 and i % 250 == 0:
            print(f"Predicted {i} colors so far...")

    assert(len(colorPredictions) == len(xMaps))
    return colorPredictions, totals, totalsRaw

def solidifyColorPrediction(out, temperature):
    don = [1,0,0,0]
    kat = [0,1,0,0]
    fdon = [0,0,1,0]
    fkat = [0,0,0,1]
    objects = [don,kat,fdon,fkat]

    if not finishers:
        don = [1,0]
        kat = [0,1]
        objects = [don, kat]

    assert(len(out) == 2+finishers)
    colorIndex = sample(out, temperature)
    color = objects[colorIndex]

    return color

def sample(preds, temperature):
    # temp is originally 1.0. Low = predictability, high = stochasticity
    # temp of 0 is equivalent to basic argmax. infinity is equivalent to uniform sampling.
    # tempo of 1 is sampling from original probabilities.
    # decreasing from 1, Probabilities become shifted toward larger ones and away from smaller ones
    # increasing from 1, probabilities become more enarly equal
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)

def makePredictionFromMapAndAudio(model, mapFiles, audioFiles, SRs, temperature): # returns prediction from model. in: model, mapFiles, audioFiles, starRatings

    print(f"Predicting with finishers {finishers}, includeAudio {config.includeAudioFeatsInColorModel}, temperature {temperature}")

    # get onsets first and related info, including color
    mapInfo = batchGetMapInfo(mapFiles)  # id, onsets, notes for each map. Does not include SR since we will take the user provided SR for prediction
    unrollings = config.colorUnrollings

    # Processing this batch to prepare it for the model
    bookendLength = config.colorAudioBookendLength  # number of frames to prepend and append on each side of central frame. For n, we have total 2n+1 frames.
    songFeats = batchGetSongFeatsFromAudios(audioFiles)

    for i, songFeat in enumerate(songFeats):  # TODO only do this for the feats matching with the onsets. Much faster
        songFeat[1] = addContextAndTrim(songFeat[1], mapInfo[i][1], bookendLength)

    # Untested but perhaps good to go
    xMaps, xAudios = batchPrepareFeatsForModel(mapInfo, songFeats, SRs)  # # everything should be same as color training, except all notes are colorless and we provided SR

    prediction = None
    colors = None

    xMaps = reshape(xMaps, (len(xMaps), 6+finishers)).astype(float32)  # want |onsets|, 80, 4+4, 1. 4+4 is the 4 colors and 4 other map feats.
    xAudios = reshape(xAudios, (len(xMaps), 1+2*config.colorAudioBookendLength, 40, 1)).astype(float32)  # want |onsets|, 80, 15, 40, 1: onsets, unrollings, 1+2bookends, freq bands, 1.

    print("Beginning prediction...")

    assert(len(audioFiles) == 1)  # All the onsets are mashed together in one list, would need to separate them by song to support several songs
    for i in range(len(audioFiles)):
        prediction, totals, totalsRaw = predict(unrollings, model, xMaps, xAudios, temperature)
    # prediction = model.predict(my_prediction_batch_generator, batch_size=generator_batch_size, verbose=1)

    if finishers:
        print(f"Predicted colors totals [don, kat, fdon, fkat]: {totals}")
        print(f"Raw prediction probability totals [don, kat, fdon, fkat]: {totalsRaw}")
    else:
        print(f"Predicted colors totals [don, kat]: {totals}")
        print(f"Raw prediction probability totals [don, kat]: {totalsRaw}")

    # print(prediction)
    print("Got to end of prediction")

    with open('models/prediction.pickle', 'wb') as handle:
        pickle.dump(prediction, handle, protocol=pickle.HIGHEST_PROTOCOL)

    return prediction

# def processPrediction(prediction):  # prediction here is the tensor of frequency bands created in makePredictionFromAudio.
#     prediction = prediction[0] # assuming only one prediction, this reshapes data. If many predictions, implement for each element in input.
#     print("Prediction sample:")
#     print(prediction)
#     return "placeholder"


# -*- coding: utf-8 -*-

from datetime import date
from dateutil.parser import parse
from imio.smartweb.core.config import EVENTS_URL
from imio.smartweb.core.contents.sections.views import CarouselOrTableSectionView
from imio.smartweb.core.contents.sections.views import HashableJsonSectionView
from imio.smartweb.core.utils import batch_results
from imio.smartweb.core.utils import get_json
from imio.smartweb.core.utils import hash_md5
from plone import api
from Products.CMFPlone.utils import normalizeString

class EventsView(CarouselOrTableSectionView, HashableJsonSectionView):
    """Events Section view"""

    @property
    def items(self):
        today = date.today().isoformat()
        max_items = self.context.nb_results_by_batch * self.context.max_nb_batches
        selected_item = f"selected_agendas={self.context.related_events}"
        specific_related_events = self.context.specific_related_events
        if specific_related_events:
            selected_item = "&".join(
                [f"UID={event_uid}" for event_uid in specific_related_events]
            )
        params = [
            selected_item,
            "metadata_fields=category_title",
            "metadata_fields=start",
            "metadata_fields=end",
            "metadata_fields=has_leadimage",
            "metadata_fields=modified",
            "metadata_fields=UID",
            f"event_dates.query={today}",
            "event_dates.range=min",
            f"b_size={max_items}",
        ]
        current_lang = api.portal.get_current_language()[:2]
        if current_lang != "fr":
            params.append("translated_in_{}=1".format(current_lang))
        if not specific_related_events:
            params += [
                "sort_on=event_dates",
            ]
        url = "{}/@events?{}".format(EVENTS_URL, "&".join(params))
        self.json_data = get_json(url)
        self.refresh_modification_date()
        if self.json_data is None or len(self.json_data.get("items", [])) == 0:  # NOQA
            return []
        linking_view_url = self.context.linking_rest_view.to_object.absolute_url()
        image_scale = self.image_scale
        orientation = self.context.orientation
        items = self.json_data.get("items")[:max_items]
        results = []
        for item in items:
            item_id = normalizeString(item["title"])
            item_url = item["@id"]
            item_uid = item["UID"]
            start = item["start"] and parse(item["start"]) or None
            end = item["end"] and parse(item["end"]) or None
            date_dict = {"start": start, "end": end}
            modified_hash = hash_md5(item["modified"])
            dict_item = {
                "uid": item_uid,
                "title": item["title"],
                "description": item["description"],
                "category": item["category_title"],
                "event_date": date_dict,
                "url": f"{linking_view_url}#/{item_id}?u={item_uid}",
                "has_image": item["has_leadimage"],
                "image": f"{item_url}/@@images/image/{orientation}_{image_scale}?cache_key={modified_hash}",
            }
            results.append(dict_item)
        if specific_related_events:
            results = sorted(
                results, key=lambda x: specific_related_events.index(x["uid"])
            )
        return batch_results(results, self.context.nb_results_by_batch)

    @property
    def see_all_url(self):
        return self.context.linking_rest_view.to_object.absolute_url()

    def is_multi_dates(self, start, end):
        return start and end and start.date() != end.date()


#  uv_project.py (c) 2016 Mattias Fredriksson
#
# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# ##### END GPL LICENSE BLOCK #####

import bpy, time, sys

from math import *
from mathutils import *
from .funcs_math import *
from .funcs_blender import *
from bpy.props import * #Property objects

class ProjectMesh(bpy.types.Operator):
    """ Projects selected to active / for redo apply transform"""
    bl_idname = "mesh.project_onto_selected_mesh"
    bl_label = "Project Mesh(es) onto Active"
    bl_info = "Projects a selected mesh(es) onto the active mesh"
    bl_options = {'REGISTER', 'UNDO'}

    proj_type_enum = [
        ("AXISALIGNED", "Axis Aligned", "The projected mesh(es) will be rotated so it's axis with the smallest angel toward the camera will face the it", 1),
        ("CAMERA", "Camera View", "The mesh will be projected as is, where each vertice distance from the projection surface will be determined by the furthest point from the camera (plane)", 2),
        ("ZISUP", "Z is Up", "The projected mesh(es) will be rotated so the Z axis will face the camera", 3),
        ]

    displayExecutionTime = False

    proj_type = EnumProperty(items=proj_type_enum,
            name = "Projection Alignment",
            description="Determines how the mesh will be aligned related to camera view before projection onto the surface. ",)
    depthOffset = FloatProperty(name="Depth Offset",
            description="Move the projection closer/away from target surface by a fixed amount (along camera forward axis)",
            default=0, min=-sys.float_info.max, max=sys.float_info.max, step=1)
    bias = FloatProperty(name="Intersection Bias",
            description="Error marginal for intersection tests, can solve intersection problems",
            default=0.00001, min=0.00001, max=1, step=1)

    def invoke(self, context, event) :
        """
        Invoke stage, gathering information of the projection objects:
        """
        start_time = time.time()
        #Fetch camera orientations:
        self.cameraRot = findViewRotation(context)
        self.cameraRotInv = self.cameraRot.transposed()
        self.camAxis = findViewAxis(context)
        self.cameraPos = findViewPos(context)
        self.ortho = viewTypeOrtho(context)
        self.lastOffset = self.depthOffset

        target_ob = context.active_object
        #Verify target
        if not target_ob:
            self.report({'ERROR'}, "No active mesh object found to use as projection target.")
            return {'CANCELLED'}
        elif target_ob.type != 'MESH':
            self.report({'ERROR'}, "Active object was not a mesh. Select an appropriate mesh object as projection target")
            return {'CANCELLED'}
        ob_sources = context.selected_objects
        #Verify selection
        self.ob_list = []
        for ob in ob_sources :
            if ob.type == 'MESH' and ob != target_ob :
                self.ob_list.append(SourceMesh(ob))
        if len(self.ob_list) == 0 :
            if len(ob_sources) > 0 :
                self.report({'ERROR'}, "Only mesh objects can be projected, need atleast one project source and an active object as projection target")
            else :
                self.report({'ERROR'}, "No selection to project found, make sure to select one project source and an active object as projection target")
            return {'CANCELLED'}
        #Generate projection info
        self.generate_BVH(target_ob, context.scene)
        self.target_ob = target_ob.name

        if ProjectMesh.displayExecutionTime :
            self.report({'INFO'}, "Finished, invoke stage execution time: %.2f seconds ---" % (time.time() - start_time))
        return self.execute(context)

    def execute(self, context):
        """
        Project each mesh onto active object
        """
        start_time = time.time()

        offset_change =  self.depthOffset != self.lastOffset

        self.lastOffset = self.depthOffset
        if not offset_change:
            self.report({'INFO'}, "Executing: Mesh Projection")
            #Project the meshes with the gathered information
            self.project(context.scene)
            #Finished
            if ProjectMesh.displayExecutionTime :
                self.report({'INFO'}, "Finished, project stage execution time: %.2f seconds ---" % (time.time() - start_time))
        #Set offset move it on camera forward axis:
        self.depthChange(context.scene)
        return {'FINISHED'}

    def depthChange(self, scene) :
        """ Moves the objects along camera z axis
        """
        mat = Matrix.Translation(self.camAxis[2] * -self.depthOffset)
        for ob in self.ob_list :
            if ob.bmesh_gen is not None:
                setNamedMesh(ob.bmesh_gen, ob.name, scene, Matrix.Translation(self.camAxis[2] * -self.depthOffset))

    def generate_BVH(self, target_ob, scene) :
        #Can't create from object, transformation not applied
        bmesh = createBmesh(target_ob, target_ob.matrix_world, True, scene, True)
        self.bvh = bvhtree.BVHTree.FromBMesh(bmesh, epsilon = self.bias)
        bmesh.free()

    def project(self, scene) :
        """ Project the mesh(es) onto the target
        """
        for ob in self.ob_list :
            #Create a bm mesh copy of the mesh!
            bmesh = ob.bmesh.copy()
            (vMin, vMax) = findMinMax(bmesh)
            mat = self.orientation(ob)
            #createMesh(bmesh, scene, mat) #Generate a aligned debug mesh
            #Find the furthest point of the mesh along camera forward
            depthDist = max(self.camAxis[2].dot(mat * vMin), self.camAxis[2].dot(mat * vMax))
            proj_list = [(None,None) for x in range(len(bmesh.verts))]
            non_proj_list = []
            #Project the vertices:
            count = 0
            count_closest = 0
            for vert in bmesh.verts :
                count += self.projectVert(mat, vert, depthDist, proj_list, non_proj_list)
            for vert in non_proj_list :
                count_closest += self.projectClosestConnect(mat, vert, depthDist, proj_list)
            #Finalize the projection by assigning the bmesh into the blender object
            #Validate one vert was projected first:
            bmesh.select_flush(False)

            if count > 0 :
                ob.bmesh_gen = bmesh
                setNamedMesh(bmesh, ob.name, scene, Matrix.Translation(self.camAxis[2] * -self.depthOffset))
                if count_closest > 0:
                    self.report({'WARNING'}, "Mesh: %s has %d vertices that failed to project and used neighbouring vertex result instead. Verify selected verts is projected OK" %(ob.name, count_closest))
                nonProjCount = len(bmesh.verts) - (count + count_closest)
                if nonProjCount != 0:
                    self.report({'WARNING'}, "Mesh: %s has %d vertices that did not project succesfully. Validate that the mesh is covered by the target" %(ob.name, nonProjCount))
            else :
                self.report({'WARNING'}, "Mesh: %s had no vertices projected onto the target. Validate that the mesh is covered by the target" %(ob.name))
    #Done

    def projectVert(self, transMat, vert, depthDist, proj_list, non_proj) :
        """ Calculate the projection of a single vert (also sets the vert.co)
        transMat:   Object transformation matrix
        vert:       Vert being updated
        """
        co =  transMat * vert.co
        #Find the distance offset to the max point of the mesh along camera axis
        dir = self.getCameraAxis(co)
        #Ray cast:
        (loc, nor, ind, dist) = self.bvh.ray_cast(co, dir, 100000)
        #If intersection occured project it
        if loc is not None:
            offset = -(depthDist - self.camAxis[2].dot(co))
            vert.co = loc + dir * offset
            proj_list[vert.index] = (loc, nor) #Store projection point and normal
            vert.select_set(False)
            return True
        #else:
        non_proj.append(vert)
        vert.select_set(True)
        return False

    def projectClosestConnect(self, transMat, vert, depthDist, proj_list) :
        co =  transMat * vert.co
        for edge in vert.link_edges :
            o_vert_ind = edge.other_vert(vert).index
            if proj_list[o_vert_ind][0] is not None :
                dir = self.getCameraAxis(co)
                rel = proj_list[o_vert_ind][1].dot(dir) #Relation between ray dir and plane normal.
                if abs(rel) <  self.bias:
                    continue
                #Plane d value:
                d = -proj_list[o_vert_ind][1].dot(proj_list[o_vert_ind][0])
                #Calculate distance
                dist = (-d - proj_list[o_vert_ind][1].dot(co)) / rel

                offset = -(depthDist - self.camAxis[2].dot(co))
                #project
                vert.co = co + dir * (dist + offset)
                return True
        return False

    def orientation(self, ob) :
        loc, meshRot, sca = ob.matrix_world.decompose()
        meshRot = meshRot.to_matrix()

        #Calc rotation
        if self.proj_type == 'AXISALIGNED' :
            rot = self.cameraRot * alignRotationMatrix(self.cameraRotInv * meshRot)
        elif self.proj_type == 'ZISUP' :
            rot = self.cameraRot * calculateXYPlaneRot(meshRot.transposed(), self.camAxis)
        else : #self.proj_type == 'CAMERA' :
            rot = meshRot
        #Assemble orientation matrix:
        mat = Matrix.Translation(loc) * (rot * scaleMatrix(sca, 3)).to_4x4()
        #mat[3].xyz = loc
        return mat

    def getCameraAxis(self, target) :
        """ Calculates the projection ray direction
        """
        if self.ortho :
            return self.camAxis[2]
        else :
            dir = target - self.cameraPos
            dir.normalize()
            return dir

class SourceMesh :
    def __init__(self, object):
        self.name = object.name
        self.matrix_world = object.matrix_world.copy()
        self.bmesh = createBmesh(object)
        self.bmesh_gen = None

    def __del__(self) :
        if self.bmesh_gen is not None :
            self.bmesh_gen.free()
        self.bmesh.free()
def calculateXYPlaneRot(meshAxis, camAxis) :
    """ Finds the rotation of the mesh on the camera X,Y plane
    """
    xAxis = meshAxis[0] - meshAxis[0].dot(camAxis[2]) * camAxis[2]
    xAxis.normalize()
    x = xAxis.dot(camAxis[0])
    y = xAxis.dot(camAxis[1])

    angle = atan2(y,x)
    return Matrix.Rotation(angle, 3, Vector((0,0,1))) #Use camAxis[2] if the rotation is applied in world space opposed to camera space

def alignRotationMatrix(rotMat) :
    """
    Aligns the axis with largest Z component to (0,0,1) and orthonormalizes the other two axes.
    """
    #Find axis with largest Z component and orthonormalize the other basis vectors to it:
    if abs(rotMat[2][2]) > max(abs(rotMat[1][2]), abs(rotMat[0][2])) :
        #Z axis is depth:
        rotMat[2] = Vector((0,0,sign(rotMat[2][2])))
        rotMat[2], rotMat[0], rotMat[1] = orthoNormalizeVec3(rotMat[2], rotMat[0], rotMat[1])
    elif abs(rotMat[1][2]) > abs(rotMat[0][2]) :
        #Y axis is depth:
        rotMat[1] = Vector((0,0,sign(rotMat[1][2])))
        rotMat[1], rotMat[0], rotMat[2] = orthoNormalizeVec3(rotMat[1], rotMat[0], rotMat[2])
    else :
        #X axis is depth:
        rotMat[0] = Vector((0,0,sign(rotMat[0][2])))
        rotMat[0], rotMat[1], rotMat[2] = orthoNormalizeVec3(rotMat[0], rotMat[1], rotMat[2])
    return rotMat