import logging; logger = logging.getLogger("morse." + __name__)

import re
import threading
from functools import partial

from morse.core import status, services
from morse.core.request_manager import RequestManager

try:
    import rospy
    import actionlib_msgs
except ImportError as ie:
    raise ImportError("Could not import some ROS modules."
                      " Check your ROS configuration is ok. Details:\n" + str(ie))

def ros_timer(callable_obj, frequency):
    # Shamelessly stolen from actionlib/action_server.py

    rate = rospy.Rate(frequency)

    rospy.logdebug("Starting timer")
    while not rospy.is_shutdown():
        try:
            rate.sleep()
            callable_obj()
        except rospy.exceptions.ROSInterruptException:
            rospy.logdebug("Sleep interrupted")

class RosAction(object):
    """ Implements a minimal action state machine.

    See http://www.ros.org/wiki/actionlib/DetailedDescription
    for the possible states.
    """
    def __init__(self, manager, component, action, rostype):

        self.manager = manager

        self._pending_goals = {}
        self.goal_lock = threading.Lock()

        self.component = component
        self._action = action

        # robot.001.sensor.001 = robot001.sensor001
        name = re.sub(r'\.([0-9]+)', r'\1', component)
        self.name = name.replace(".", "/") + "/" + action

        # Retrieves the types of the goal msg, feedback msg and result
        # msg (check roslib.message.Message for details)
        rosinstance = rostype()
        types = [type(getattr(rosinstance, t)) for t in rosinstance.__slots__]

        self.result_type = types[1]
        self.feedback_type = types[2]

        # read the frequency with which to publish status from the parameter server
        # (taken from actionlib/action_server.py)
        self.status_frequency = rospy.get_param(self.name + "/status_frequency", 5.0)
        queue_size = max(1, self.status_frequency)

        # Create the 5 topics required by an action server
        self.goal_topic = rospy.Subscriber(self.name + "/goal", types[0], self.on_goal)
        self.result_topic = rospy.Publisher(self.name + "/result", types[1], queue_size=queue_size)
        self.feedback_topic = rospy.Publisher(self.name + "/feedback", types[2], queue_size=queue_size)

        self.cancel_topic = rospy.Subscriber(self.name + "/cancel", actionlib_msgs.msg.GoalID, self.on_cancel)
        self.status_topic = rospy.Publisher(self.name + "/status", actionlib_msgs.msg.GoalStatusArray,
                                            queue_size=queue_size)

        status_list_timeout = rospy.get_param(self.name + "/status_list_timeout", 5.0)
        self.status_list_timeout = rospy.Duration(status_list_timeout)

        self.status_timer = threading.Thread(None, ros_timer, None, (self._publish_status,self.status_frequency) )
        self.status_timer.start()

    def setstatus(self, id, status):

        with self.goal_lock:
            goal_id = self._pending_goals[id]['goal_id']
            goal_status = actionlib_msgs.msg.GoalStatus(goal_id = goal_id,
                                                   status = status)
            self._pending_goals[id]['status'] = goal_status

    def getstatus(self, id):

        with self.goal_lock:
            return self._pending_goals[id]['status'].status

    def set_internal_id(self, id, morse_id):

        with self.goal_lock:
            self._pending_goals[id]['morse_id'] = morse_id

    def manage_internal_id(self, morse_id):
        """ Check if this ROS action manager manages the given
        internal request ID.

        This is used by RosRequestManager to dispatch the service
        'on completion' event.
        """
        return self.get_id_from_internal_id(morse_id) is not None

    def get_id_from_internal_id(self, morse_id):

        with self.goal_lock:
            for id, goal in self._pending_goals.items():
                if goal.setdefault('morse_id') == morse_id:
                    return id

    def on_goal(self, goal):
        logger.info("Got a new goal for ROS action " + self.name)

        # Workaround for encoding issues (-> goal_id.id comes as bytes,
        # and must be converted to string before being reserialized)
        id = actionlib_msgs.msg.GoalID(id = goal.goal_id.id,
                                       stamp = goal.goal_id.stamp)

        with self.goal_lock:
            self._pending_goals[id.id] = {'goal_id': id, 'status': None}

        self.setstatus(id.id, actionlib_msgs.msg.GoalStatus.PENDING)

        is_sync, morse_id = self.manager.on_incoming_request(self.component, self._action, [goal.goal])

        # is_sync should be only True for ROS services!
        if is_sync:
            # TODO: clean terminated goals 'after a few seconds' (as
            # said by actionlib doc)
            self.setstatus(id.id, actionlib_msgs.msg.GoalStatus.REJECTED)
            logger.error("Internal error: This ROS action is bound to a "
                         "synchronous MORSE service! ({})".format(component_name + '.' + service_name))

        self.set_internal_id(id.id, morse_id)
        self.setstatus(id.id, actionlib_msgs.msg.GoalStatus.ACTIVE)
        logger.debug("Started action. GoalID=" + id.id + " MORSE ID=" + str(morse_id))

    def on_cancel(self, goal_id):
        logger.info("Got a cancel request for ROS action " + self.name)

        current_status = None

        try:
            current_status = self.getstatus(goal_id.id)
        except KeyError:
            # Unknown GoalID...? skipping this cancel request.
            logger.info("I can not find any goal matching this cancel request. Skipping it.")
            return

        if current_status == actionlib_msgs.msg.GoalStatus.PENDING:
            self.setstatus(goal_id.id, actionlib_msgs.msg.GoalStatus.RECALLING)
        else: #current status = ACTIVE (or smth else...)
            self.setstatus(goal_id.id, actionlib_msgs.msg.GoalStatus.PREEMPTING)
            self.manager.abort_request(self._pending_goals[goal_id.id]['morse_id'])

    def on_result(self, morse_id, state, result):

        logger.info("Got a result for action " + self.name + ": " + str(state) + " " + str(result))
        id = self.get_id_from_internal_id(morse_id)

        if state == status.PREEMPTED:
            logger.info("The action " + self.name + " has been preempted. "
                         "Reporting it to ROS system.")
            self.setstatus(id, actionlib_msgs.msg.GoalStatus.PREEMPTED)
        if state == status.FAILED:
            logger.info("The action " + self.name + " has been aborted. "
                         "Reporting it to ROS system.")
            self.setstatus(id, actionlib_msgs.msg.GoalStatus.ABORTED)
        if state == status.SUCCESS:
            logger.debug("The action " + self.name + " has succeeded. Reporting"
                         " it to ROS system and publishing results.")
            self.setstatus(id, actionlib_msgs.msg.GoalStatus.SUCCEEDED)

        self.publish_result(id, result)

    def publish_result(self, goal_id, result):

        goal_status = None

        with self.goal_lock:
            goal_status = self._pending_goals[goal_id]['status']

        res = self.result_type(status=goal_status,
                               result=result)

        self.result_topic.publish(res)

    def _publish_status(self):
        """ This private method is called asynchronously to update the status of pending goals.
        """

        status_array = actionlib_msgs.msg.GoalStatusArray()

        with self.goal_lock:
            for goal in self._pending_goals.values():
                if goal['status']:
                    status_array.status_list.append(goal['status'])

        status_array.header.stamp = rospy.Time.now()
        self.status_topic.publish(status_array)

class RosRequestManager(RequestManager):

    def __init__(self):
        RequestManager.__init__(self)

        self._services = {}
        self._actions = []

    def __str__(self):
        return "ROS Request Manager"

    def initialization(self):

        # Init MORSE-node in ROS
        rospy.init_node('morse', disable_signals=True)
        logger.info("ROS node 'morse' successfully created.")

        return True

    def finalization(self):
        # do not shutdown ros since we cant restart it later on (see rospy).
        return True

    def register_ros_action(self, method, component_name, service_name):

        rostype = None
        try:
            rostype = method._ros_action_type # Is it a ROS action?
            logger.info(component_name + "." + service_name + " is a ROS action of type " + str(rostype))
        except AttributeError:
            logger.info(component_name + "." + service_name + " has no ROS-specific action type. Skipping it.")
            return False

        self._actions.append(RosAction(self, component_name, service_name, rostype))

        logger.info("Created new ROS action server for {}.{}".format(
                                                    component_name,
                                                    service_name))

        return True

    def register_ros_service(self, method, component_name, service_name):

        rostype = None
        try:
            rostype = method._ros_service_type # Is it a ROS service?
            logger.info(component_name + "." + service_name + " is a ROS service of type " + str(rostype))
        except AttributeError:
            logger.info(component_name + "." + service_name + " has no ROS-specific service type. Skipping it.")
            return False

        cb = self.add_ros_handler(component_name, service_name)

        # robot.001.sensor.001 = robot001.sensor001
        name = re.sub(r'\.([0-9]+)', r'\1', component_name)
        _service_name = name.replace(".", "/") + "/" + service_name

        try:
            s = rospy.Service(_service_name, rostype, cb)
            logger.info("Created new ROS service for %s.%s" % \
                         (component_name, service_name))
        except Exception as e:
            logger.warning("Could not initiate rospy.Service\n" + str(e))

        return True

    def post_registration(self, component_name, service_name, is_async):
        """ We create here ROS services (for *synchronous* services) and ROS
        actions (for *asynchronous* services).

        In order not to interfere with neither ROS own service wrapping mechanism or
        MORSE service invokation mechanisms, we create here, 'on the fly', handlers
        for each service exposed through ROS.

        ROS requires type for the services/actions. Those can be set with the
        :py:meth:`ros_action` and :py:meth:`ros_service` decorators.
        If none is set, the action/service is discarded.
        """

        rostype = None

        # TODO: I access here an internal member of the parent class to
        # retrieve the ROS type, if set. _services should probably be
        # 'officially' exposed
        method, is_async = self._services[(component_name, service_name)]

        if is_async:
            return self.register_ros_action(method, component_name, service_name)
        else:
            return self.register_ros_service(method, component_name, service_name)

    def add_ros_handler(self, component_name, service_name):
        """ Dynamically creates custom ROS->MORSE dispatchers
        for ROS *services* only.

        ROS actions are dealt with in the :py:class:`RosAction` class.
        """

        def innermethod(request):
            # TODO: when this will be actually called? If ROS service
            # management lives in its own thread, it can be basically
            # called at any time, which is dangerous.

            # The request type is generated from the .srv definition.
            # roslib.message.Message defines the method __getstate__()
            # the retrieve a 'flat' view of all parameters.
            args = request.__getstate__()

            logger.info("ROS->MORSE dispatcher for " + service_name + \
                         " got incoming request: " + str(args))
            is_sync, value = self.on_incoming_request(component_name, service_name, args)

            # is_sync should be always True for ROS services!
            if not is_sync:
                logger.error("Internal error: This ROS "
                             "service is bound to an asynchronous MORSE"
                             " service! ({})".format(component_name + '.' + service_name))
                raise rospy.service.ServiceException("MORSE Internal error! Check MORSE logs for details.")

            state, result = value

            if state == status.SUCCESS:
                # Here, we 'hope' that the return value of the MORSE
                # service is a valid dataset to construct the
                # ServiceResponse expected by ROS
                return result
            else:
                # failure!
                raise rospy.service.ServiceException(result)

        innermethod.__doc__ = "This method is invoked directly by MORSE when " +\
        "a new service request comes in. This handler simply redispatch it to " +\
        "MORSE own service invokation system.\n\n" +\
        "The method takes a ROS ServiceRequest as unique parameter, and must " +\
        "return a ROS ServiceResponse"

        innermethod.__name__ = "_" + service_name + "_ros_handler"

        logger.debug("Created new ROS->MORSE dispatcher for service {}.{}".format(
                                                    component_name,
                                                    service_name))
        return innermethod

    def on_service_completion(self, request_id, result):
        # First, figure out which 'ROSAction' manages this request id:
        manager = None

        for action in self._actions:
            if action.manage_internal_id(request_id):
                manager = action
                break

        if manager is None:
            logger.error("A ROS action call has been lost! Nobody manage request " + request_id)

        # Then, dispatch the 'on completion' event.
        status, value = result
        manager.on_result(request_id, status, value)

    def main(self):
        pass

def ros_action(fn = None, type = None, name = None):
    """ The @ros_action decorator.

    This decorator is very similar to the standard
    :py:meth:`morse.core.services.async_service` decorator. It sets a
    class method to be a asynchronous service, exposed as a ROS action of
    type `type`.

    This decorator can only be used on methods in classes inheriting from
    :py:class:`morse.core.object.Object`.

    :param callable fn: [automatically set by Python to point to the
      decorated function]
    :param class type: you MUST set this parameter to define the
      type of the ROS action.
    :param string name: by default, the name of the service is the name
      of the method. You can override it by setting the 'name' argument.
      Your ROS action will appear as /component_instance/<name>/...
    """
    if not type:
        logger.error("You must provide a valid ROS action type when using the " + \
        "@ros_action decorator, e.g. @ros_action(type=MyRosAction). Action ignored.")
        return

    if not hasattr(fn, "__call__"):
        return partial(ros_action, type = type, name = name)

    fn._ros_action_type = type
    return services.service(fn, component = None, name = name, asynchronous = True)

def ros_service(fn = None, type = None, component = None, name = None):
    """ The @ros_service decorator.

    This decorator is very similar to the standard
    :py:meth:`morse.core.services.service` decorator. It sets a free function or
    class method to be a (synchronous) service, exposed as a ROS service of
    type `type`.

    This decorator works both with free function and for methods in
    classes inheriting from
    :py:class:`morse.core.object.Object`. In the former case,
    you must specify a component (your service will belong to this
    namespace), in the later case, it is automatically set to the name
    of the corresponding MORSE component.

    :param callable fn: [automatically set by Python to point to the
      decorated function]
    :param class type: you MUST set this parameter to define the
      type of the ROS action.
    :param string component: you MUST set this parameter to define the
      name of the component which export the service ONLY for free
      functions. Cf explanation above.
    :param string name: by default, the name of the service is the name
      of the method. You can override it by setting the 'name' argument.
      Your ROS service will appear as /<name>
    """
    if not type:
        logger.error("You must provide a valid ROS action type when using the " + \
        "@ros_action decorator, e.g. @ros_action(type=MyRosAction). Service ignored.")
        return

    if not hasattr(fn, "__call__"):
        return partial(ros_service, type = type, component = component, name = name)

    fn._ros_service_type = type
    return services.service(fn, component = component, name = name, asynchronous = False)


from flask import Flask, request, jsonify
from flask_cors import CORS
from werkzeug import exceptions
from flask_mail import Mail, Message

app = Flask(__name__)
mail = Mail(app)
CORS(app)
Games = [{'id':1,'name':'farcry 6'}, {'id':2,'name': 'COD'}]

@app.route('/')
def entry():
    return 'Welcome to this API'

@app.route('/Games', methods=['GET', 'POST'])
def games_handler():
    if request.method == 'GET':
        return jsonify({'Game': Games}), 200
    elif request.method == 'POST':
        data = request.get_json()
        for game in Games:
            print(game['name'])
            if(game['name'] == data['name']):
                return jsonify('Game already exists'), 403
        Games.append(data)
        data['id'] = len(Games)
        resp = {'Game': Games}
        # msg = Message(f"Game {data['name']} has been added",
        #                 sender="zainuppal2@gmail.com",
        #                 recipients=["zainuppal1@gmail.com"])
        # mail.send(msg)
        return jsonify(resp), 201

@app.route('/Games/<int:game_id>')
def game_handler(game_id):
    game = next(game for game in Games if game['id'] == game_id)
    return jsonify({'Game':game}), 200

@app.errorhandler(exceptions.NotFound)
def handle_404(err):
    return jsonify({"message": f"Error {err}"}), 404

@app.errorhandler(exceptions.InternalServerError)
def handle_500(err):
    return jsonify({"message": f"{err}"}), 500

if __name__ == '__main__':
    app.run(debug=True)


#from datetime import date, timedelta, datetime
import datetime
from datetime import date, timedelta
import time

lastMonthYear = (datetime.datetime.now().replace(day=1) - datetime.timedelta(days=1)).year
lastMonth = (datetime.datetime.now().replace(day=1) - datetime.timedelta(days=1)).month
currentMonthYear = datetime.datetime.today().year
currentMonth = datetime.datetime.today().month
nextMonthYear = (datetime.datetime.now().replace(day=28) + datetime.timedelta(days=4)).year
nextMonth = (datetime.datetime.now().replace(day=28) + datetime.timedelta(days=4)).month
day = datetime.datetime.today().day
date1 = (time.strftime("%Y-%m-%d"))
print(date1)
print(type(date1))
date2 = datetime.date.today()
print(date2)
print(type(date2))

if int(day) > 25:
    d1 = date(currentMonthYear, currentMonth, 26)  # start date
    d2 = date(nextMonthYear, nextMonth, 25)  # end date
    delta = d2 - d1         # timedelta
    for i in range(delta.days + 1):
        print(d1 + timedelta(i))
        #ws.cell(row=i + 3, column=1, value=(d1 + timedelta(i)))
else:
    d1 = date(lastMonthYear, lastMonth, 26)  # start date
    d2 = date(currentMonthYear, currentMonth, 25)  # end date
    delta = d2 - d1         # timedelta
    for i in range(delta.days + 1):
        print(d1 + timedelta(i))
        #ws.cell(row=i + 3, column=1, value=(d1 + timedelta(i)))


"""
This script fetches the RDS instance classes and engine version in use in a specified region,
checks if they are available in a second region,
and prints out the classes versions and instance IDs that are not available in the second region.
"""
import sys
import boto3

def get_in_use_rds_classes_and_ids(region):
    rds = boto3.client("rds", region_name=region)
    paginator = rds.get_paginator("describe_db_instances")

    instance_classes_and_ids = {}
    instance_engines_and_versions = {}

    for page in paginator.paginate():
        for db_instance in page["DBInstances"]:
            class_ = db_instance["DBInstanceClass"]
            engine = db_instance["Engine"]
            engine_version = db_instance["EngineVersion"]
            if class_ in instance_classes_and_ids:
                instance_classes_and_ids[class_].append(
                    db_instance["DBInstanceIdentifier"]
                )
            else:
                instance_classes_and_ids[class_] = [db_instance["DBInstanceIdentifier"]]
                instance_engines_and_versions[class_] = (engine, engine_version)

    return instance_classes_and_ids, instance_engines_and_versions

def compare_rds_classes(region1, region2):
    (
        classes_and_ids_region1,
        engines_and_versions_region1,
    ) = get_in_use_rds_classes_and_ids(region1)

    not_in_region2 = {}

    for class_, (engine, version) in engines_and_versions_region1.items():
        classes_region2 = get_rds_classes(region2, engine)
        engine_versions_region2 = get_rds_engine_versions(region2, engine)

        class_available = class_ in classes_region2
        version_available = version in engine_versions_region2

        if not class_available or not version_available:
            not_in_region2[class_] = (
                classes_and_ids_region1[class_],
                version,
                class_available,
                version_available,
            )

    print(
        f"RDS Instance Classes and/or Engine Versions in use in {region1} not available in {region2}:"
    )
    for class_, (
        ids,
        version,
        class_available,
        version_available,
    ) in not_in_region2.items():
        if not class_available and not version_available:
            print(
                f"Class: {class_}, Engine Version: {version}, Instance IDs: {ids} - both class and version not available"
            )
        elif not class_available:
            print(
                f"Class: {class_}, Engine Version: {version}, Instance IDs: {ids} - class not available"
            )
        else:
            print(
                f"Class: {class_}, Engine Version: {version}, Instance IDs: {ids} - engine version not available"
            )

def get_rds_classes(region, engine):
    rds = boto3.client("rds", region_name=region)
    paginator = rds.get_paginator("describe_orderable_db_instance_options")

    instance_classes = set()

    for page in paginator.paginate(Engine=engine):
        for instance_class in page["OrderableDBInstanceOptions"]:
            instance_classes.add(instance_class["DBInstanceClass"])

    return instance_classes

def get_rds_engine_versions(region, engine):
    rds = boto3.client("rds", region_name=region)
    paginator = rds.get_paginator("describe_orderable_db_instance_options")

    engine_versions = set()

    for page in paginator.paginate(Engine=engine):
        for option in page["OrderableDBInstanceOptions"]:
            engine_versions.add(option["EngineVersion"])

    return engine_versions

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python check_rds_types.py <region1> <region2>")
        sys.exit(1)

    REGION1 = sys.argv[1]
    REGION2 = sys.argv[2]

    compare_rds_classes(REGION1, REGION2)


"""event tests"""
from urllib.parse import urlencode

from django.contrib.contenttypes.models import ContentType
from django.test import RequestFactory, TestCase
from django.views.debug import SafeExceptionReporterFilter
from guardian.shortcuts import get_anonymous_user

from authentik.core.models import Group
from authentik.events.models import Event
from authentik.flows.views.executor import QS_QUERY
from authentik.lib.generators import generate_id
from authentik.policies.dummy.models import DummyPolicy
from authentik.tenants.models import Tenant

class TestEvents(TestCase):
    """Test Event"""

    def setUp(self) -> None:
        self.factory = RequestFactory()

    def test_new_with_model(self):
        """Create a new Event passing a model as kwarg"""
        test_model = Group.objects.create(name="test")
        event = Event.new("unittest", test={"model": test_model})
        event.save()  # We save to ensure nothing is un-saveable
        model_content_type = ContentType.objects.get_for_model(test_model)
        self.assertEqual(
            event.context.get("test").get("model").get("app"),
            model_content_type.app_label,
        )

    def test_new_with_user(self):
        """Create a new Event passing a user as kwarg"""
        event = Event.new("unittest", test={"model": get_anonymous_user()})
        event.save()  # We save to ensure nothing is un-saveable
        self.assertEqual(
            event.context.get("test").get("model").get("username"),
            get_anonymous_user().username,
        )

    def test_new_with_uuid_model(self):
        """Create a new Event passing a model (with UUID PK) as kwarg"""
        temp_model = DummyPolicy.objects.create(name="test", result=True)
        event = Event.new("unittest", model=temp_model)
        event.save()  # We save to ensure nothing is un-saveable
        model_content_type = ContentType.objects.get_for_model(temp_model)
        self.assertEqual(event.context.get("model").get("app"), model_content_type.app_label)
        self.assertEqual(event.context.get("model").get("pk"), temp_model.pk.hex)

    def test_from_http_basic(self):
        """Test plain from_http"""
        event = Event.new("unittest").from_http(self.factory.get("/"))
        self.assertEqual(
            event.context, {"http_request": {"args": {}, "method": "GET", "path": "/"}}
        )

    def test_from_http_clean_querystring(self):
        """Test cleansing query string"""
        request = self.factory.get(f"/?token={generate_id()}")
        event = Event.new("unittest").from_http(request)
        self.assertEqual(
            event.context,
            {
                "http_request": {
                    "args": {"token": SafeExceptionReporterFilter.cleansed_substitute},
                    "method": "GET",
                    "path": "/",
                }
            },
        )

    def test_from_http_clean_querystring_flow(self):
        """Test cleansing query string (nested query string like flow executor)"""
        nested_qs = {"token": generate_id()}
        request = self.factory.get(f"/?{QS_QUERY}={urlencode(nested_qs)}")
        event = Event.new("unittest").from_http(request)
        self.assertEqual(
            event.context,
            {
                "http_request": {
                    "args": {"token": SafeExceptionReporterFilter.cleansed_substitute},
                    "method": "GET",
                    "path": "/",
                }
            },
        )

    def test_from_http_tenant(self):
        """Test from_http tenant"""
        # Test tenant
        request = self.factory.get("/")
        tenant = Tenant(domain="test-tenant")
        setattr(request, "tenant", tenant)
        event = Event.new("unittest").from_http(request)
        self.assertEqual(
            event.tenant,
            {
                "app": "authentik_tenants",
                "model_name": "tenant",
                "name": "Tenant test-tenant",
                "pk": tenant.pk.hex,
            },
        )


import pygame
from pygame.locals import (
 K_UP,
 K_DOWN,
 K_r,
 K_m,
 K_q
)

import config
from handlers import scoreHandlers, musicHandlers
from factories import soundsFactory

pygame.display.init()
pygame.font.init()
pygame.mixer.init()

clock = pygame.time.Clock()
screen = pygame.display.set_mode((0,0), flags=pygame.FULLSCREEN)
DISPLAY_INFO = pygame.display.Info()
font = pygame.font.Font(None, DISPLAY_INFO.current_h//4)
sounds = soundsFactory.createSounds(pygame.mixer, config.ASSETS['ASSET_DIRECTORY_NAME'], config.AUDIO_ASSETS)

screen.fill(pygame.color.THECOLORS['deepskyblue'])
score = config.SCORING['STARTING_SCORE']
pygame.display.set_caption("{} points Quizzr".format(score))
pygame.display.flip()

active = True
while active:
 for event in pygame.event.get():
  if event.type == pygame.QUIT: active = False
  if event.type == pygame.KEYUP:
   if event.key == K_UP: score = scoreHandlers.incramentScore(pygame, config.SCORING, sounds['INCRAMENT_SCORE_SOUND'], score)
   elif event.key == K_DOWN: score = scoreHandlers.decrementScore(pygame, config.SCORING, sounds['DECREMENT_SCORE_SOUND'], score)
   elif event.key == K_r: score = scoreHandlers.resetScore(pygame, config.SCORING, sounds['RESET_SCORE_SOUND'])
   elif event.key == K_m: musicHandlers.toggleMusic(pygame.mixer.music, config.ASSETS['ASSET_DIRECTORY_NAME'], config.AUDIO_ASSETS['MUSIC'], config.AUDIO_CONFIGURATION['VOLUME'])
   elif event.key == K_q: active = False
 text = font.render(str(score), True, pygame.color.THECOLORS['yellow'])
 screen.blit(text, (DISPLAY_INFO.current_w - text.get_width() // 2, DISPLAY_INFO.current_h - text.get_height() // 2))
 pygame.display.update(text.get_rect())
 clock.tick(40)

pygame.quit()


"""razor_sharp URL Configuration"""

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.conf.urls import handler404, handler500
from .views import handler404, handler500

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('allauth.urls')),
    path('profiles/', include('accounts.urls')),
    path('products/', include('products.urls')),
    path('checkout/', include('checkout.urls')),
    path('cart/', include('cart.urls')),
    path('blog/', include('blog.urls')),
    path('contact/', include('contact.urls')),
    path('summernote/', include('django_summernote.urls')),
    path('', include('home.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

handler404 = 'razor_sharp.views.handler404'
handler500 = 'razor_sharp.views.handler500'


from collections import OrderedDict
from contextlib import contextmanager
from enum import Enum
from html import unescape
from pathlib import Path
import re
import sys

# Third-party imports
from lxml import html
import pytest
from selenium.webdriver.common.keys import Keys
from yarl import URL

# Local imports
from selenium import webdriver
from selweb.driver import (BrowserDriver, FirefoxDriver, GenericDriver,
                           PhantomJSDriver)
from selweb import (Browser, WebObject, CompositeWebObject, WebPage)
from selweb.util import xpath_clsmatch

# ============================================================================
# Custom driver/browser
# ============================================================================

@BrowserDriver.register
class ChromeDriver(GenericDriver):
    __slots__ = ()

    def __init__(self, *, driver=None):
        options = dict()
        if driver:
            options.update(executable_path=str(driver))
        super().__init__(webdriver.Chrome, **options)

class PhantomJS:

    @staticmethod
    def driver(bindir):
        exe_name = 'phantomjs.exe' if sys.platform == 'win32' else 'phantomjs'
        bin = bindir / exe_name
        driver = PhantomJSDriver(driver=bin)
        return driver

class Chrome:

    @staticmethod
    def driver(bindir):
        exe_name = 'chromedriver.exe' if sys.platform == 'win32' else 'chromedriver'
        bin = bindir / exe_name
        driver = ChromeDriver(driver=bin)
        return driver

class Firefox:

    @staticmethod
    def driver(bindir, *, binary=None):
        exe_name = 'geckodriver.exe' if sys.platform == 'win32' else 'geckodriver'
        bin = bindir / exe_name
        driver = FirefoxDriver(driver=bin, binary=binary)
        return driver

class Driver(Enum):
    chrome = Chrome
    firefox = Firefox
    phantomjs = PhantomJS

@contextmanager
def browser(bindir, driver):
    """Return browser using chrome driver"""
    if not isinstance(driver, Driver):
        errmsg = ('driver arg expected {} object, got {} object instead'.
                  format(Driver.__name__, type(driver).__name__))
        raise TypeError(errmsg)
    with Browser(driver.value.driver(bindir)) as browser:
        yield browser

# ============================================================================
# Google front page
# ============================================================================

class GoogleLogo(WebObject):

    def __init__(self, parent):
        xpath = "//*[@id='hplogo']"
        super().__init__('logo', xpath, parent)

class SearchBar(WebObject):

    def __init__(self, parent):
        xpath = "//input[@name='q']"
        super().__init__('searchbar', xpath, parent)

    def submit_search(self, text):
        """docstring for enter_text"""
        browser = self.browser
        searchbar = browser.element(self.absxpath)

        # The following context block is commented due to a bug in geckdriver
        # with browser.actionchain() as a:
        #     #  Click the search bar, enter search term, and submit
        #     a.move_to_element(searchbar).click().send_keys(text)
        #     a.send_keys(Keys.RETURN)

        # Click the search bar, enter search term, and submit
        searchbar.click()
        searchbar.send_keys(text)
        searchbar.send_keys(Keys.RETURN)

        #  Return the results page
        browser.waitfor.title(f'{text} - Google Search', timeout=5)
        new_url = browser.location
        ret = GoogleResultPage(new_url, browser)
        ret.reload()
        return ret

class GoogleFrontPage(WebPage):

    def __init__(self, browser):
        url = URL('https://www.google.ca')
        super().__init__('google_front', url, browser,
                         reloadcontext=self.reload_context)

    @contextmanager
    def reload_context(self):
        yield

        # Add sub objects
        self.add(GoogleLogo(self))
        self.add(SearchBar(self))

        for c in self.children():
            c.reload()

# ============================================================================
# GoogleSearchResults
# ============================================================================

class SearchItemTitle(WebObject):

    def __init__(self, parent):
        clsname = xpath_clsmatch('r')
        xpath = f'//h3[{clsname}]'
        super().__init__('title', xpath, parent)

        self._bs = None

    @property
    def url(self):
        a = html.fromstring(self.source)[0]
        url = unescape(a.get('href'))

        # Remove the query frag
        frag = '/url?q='
        if url.startswith(frag):
            url = url.replace(frag, '', 1)

        # Remove google added url vars
        regex = '[&]sa[=][a-zA-Z][&]ved[=]'
        match = re.search(regex, url)
        if match:
            url = url[:match.start()]

        # Return an absolute url
        url = URL(url)
        if not url.is_absolute():
            url = self.page.url.join(url)

        # Remove any trailing foreslashes
        parts = url.parts
        if parts[-1] == '':
            new_path = '/'.join(('', ) + url.parts[1:-1])
            url = url.with_path(new_path)
        return url

    @property
    def title(self):
        """Return title text"""
        src = self.source
        parser = html.document_fromstring(src)
        return parser.text_content()

    @property
    def absxpath(self):
        # Possible that a search item can contain child search items (eg top
        # result item), we don't care about those, just the first one
        xpath = self.parent.absxpath
        xpath = ''.join([xpath, self.xpath])
        return f"({xpath})[1]"

class SearchItemLabel(WebObject):

    def __init__(self, parent):
        clsname = xpath_clsmatch('s')
        xpath = f"//div[{clsname}]//cite"
        super().__init__('label', xpath, parent)

    @property
    def label(self):
        """Return label"""
        src = self.source
        parser = html.document_fromstring(src)
        return parser.text_content().strip()

    @property
    def absxpath(self):
        xpath = self.parent.absxpath
        xpath = ''.join([xpath, self.xpath])
        return f"({xpath})[1]"

class SearchItemSummary(WebObject):

    def __init__(self, parent):
        cls_s = xpath_clsmatch('s')
        cls_st = xpath_clsmatch('st')
        xpath = f"//div[{cls_s}]//span[{cls_st}]"
        super().__init__('summary', xpath, parent)

    @property
    def text(self):
        """Return summary text"""
        src = self.source
        parser = html.document_fromstring(src)
        return parser.text_content().strip()

    @property
    def absxpath(self):
        xpath = self.parent.absxpath
        xpath = ''.join([xpath, self.xpath])
        return f"({xpath})[1]"

class SearchItem(CompositeWebObject):

    # the name will be the index number
    def __init__(self, parent, *, index=0):
        if not isinstance(index, int):
            errmsg = ('index arg expected {} object, got {} object instead'.
                      format(int.__name__, type(index).__name__))
            raise TypeError(errmsg)
        elif index < 0:
            errmsg = ('index arg expected to be >= 0, got {} instead'.
                      format(index))
            raise ValueError(errmsg)

        label = SearchItemLabel(self)
        cls_r = xpath_clsmatch('r')
        xpath = f"//h3[{cls_r}]/parent::node()[.{label.xpath}]"
        super().__init__(index, xpath, parent, reloadcontext=self.reload_context)

    @contextmanager
    def reload_context(self):
        yield

        # Run after core reload is done
        title = SearchItemTitle(self)
        label = SearchItemLabel(self)
        summary = SearchItemSummary(self)
        for item in [title, label, summary]:
            self.add(item)
            item.reload()

    @property
    def absxpath_noindex(self):
        """Return the non-indexed xpath"""
        return super().absxpath

    @property
    def absxpath(self):
        xpath = super().absxpath
        return f"({xpath})[{self.name+1}]"

class ResultList(CompositeWebObject):

    def __init__(self, parent):
        xpath = "//div[@id='res']"
        super().__init__('results', xpath, parent,
                         reloadcontext=self.reload_context)

    @contextmanager
    def reload_context(self):
        yield
        # Run after core reload

        # Get lxml.html parser for this object to find sub items
        item = SearchItem(self)
        item_xpath = ''.join([self.xpath, item.xpath])
        src = self.source
        parser = html.fromstring(src)
        results = parser.xpath(item_xpath)

        for i, el in enumerate(results):
            if i > 0:
                item = SearchItem(self, index=i)
            self.add(item)
            try:
                item.reload()
            except Exception as err:
                print('ERROR', item.absxpath, err)
                break

class GoogleResultPage(WebPage):

    def __init__(self, url, browser):
        super().__init__('google_results', url, browser,
                         reloadcontext=self.reload_context)

    @contextmanager
    def reload_context(self):
        yield

        # Run after core reload is done
        results = ResultList(self)
        self.add(results)
        results.reload()

# ============================================================================
#
# ============================================================================


#!/usr/local/bin/python3
import math
from collections import defaultdict
from collections import Counter

reverse_chars = {
    '(': ')',
    '[': ']',
    '{': '}',
    '<': '>',
}
illegal_char_points_table = {
    ')': 3,
    ']': 57,
    '}': 1197,
    '>': 25137,
}
missing_char_points_table = {
    ')': 1,
    ']': 2,
    '}': 3,
    '>': 4,
}

def check_line(line):
    stack = []

    for char in line:
        is_opening_char = char in ['(', '[', '{', '<']
        if is_opening_char:
            stack.append(char)
        else:
            expected = reverse_chars[stack.pop()]
            if expected != char:
                return (char, stack)

    return (None, stack)

with open('input') as f:
    lines = f.read().splitlines()

    illegal_occurences = defaultdict(lambda: 0)
    incomplete_lines_points = []

    for line in lines:
        incomplete_points = 0
        illegal_char, stack = check_line(line)

        if illegal_char != None:
            illegal_occurences[illegal_char] += 1

        if illegal_char == None and len(stack) > 0:
            for c in reversed(stack):
                required_char = reverse_chars[c]
                incomplete_points = (incomplete_points * 5) + missing_char_points_table[required_char]

        if incomplete_points > 0:
            incomplete_lines_points.append(incomplete_points)

    illegal_points = 0
    for char, occurence_count in Counter(illegal_occurences).items():
        illegal_points += illegal_char_points_table[char] * occurence_count
    print(f"illegal_points {illegal_points}")

    middle_idx = int(math.floor(len(incomplete_lines_points) / 2))
    incomplete_points = sorted(incomplete_lines_points)[middle_idx]
    print(f"incomplete_points {incomplete_points}")


import numpy as np
import pandas as pd
from math import radians, cos, sin, asin, sqrt

from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp

def haversine(a, b):
    r = 6371
    lon1, lat1, lon2, lat2 = map(radians, [ a[1], a[0], b[1], b[0]])
    dist_lon = lon2 - lon1
    dist_lat = lat2 - lat1
    hav = sin(dist_lat/2)**2 + cos(lat1) * cos(lat2) * sin(dist_lon/2)**2
    return round((2 * r * asin( sqrt(hav) )))

def calcula_distancias(df):
    return [list([int(b) for b in a]) for a in df[['latitude','longitude']].apply(lambda x: df.apply(lambda y: haversine(x, y),axis=1) ,axis=1).values]

def gera_time_windows(df):
    return [(int(a[0]),int(a[1])) for a in df[['inicio_janela','termino_janela']].values]

def gera_volumetria(df):
    return [int(a) for a in df.volumetria.values]

def gera_peso(df):
    return [int(a) for a in df.peso.values]

def create_data_model():
    df = pd.read_csv('data.csv')
    data = {}
    data['distance_matrix'] = calcula_distancias(df)
    data['time_matrix'] = calcula_distancias(df)
    data['time_windows'] = gera_time_windows(df)
    data['demands'] = gera_volumetria(df)
    data['demands_p'] = gera_peso(df)
    data['vehicle_capacities'] = [55, 80, 100]
    data['vehicle_capacities_peso'] = [50, 70, 90]
    data['num_vehicles'] = 3
    data['depot_capacity'] = 0

    data['vehicle_load_time'] = 0
    data['vehicle_unload_time'] = 0
    data['depot'] = 0
    return data

def print_solution(data, manager, routing, assignment):
    time_dimension = routing.GetDimensionOrDie('Time')
    total_time = 0
    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        plan_output = 'Rota por Veiculo {}:\n'.format(vehicle_id)
        while not routing.IsEnd(index):
            time_var = time_dimension.CumulVar(index)
            plan_output += '{0} Tempo({1},{2}) -> '.format(
                manager.IndexToNode(index), assignment.Min(time_var),
                assignment.Max(time_var))
            index = assignment.Value(routing.NextVar(index))
        time_var = time_dimension.CumulVar(index)
        plan_output += '{0} Tempo({1},{2})\n'.format(manager.IndexToNode(index),
                                                    assignment.Min(time_var),
                                                    assignment.Max(time_var))
        plan_output += 'Tempo da Rota: {}min\n'.format(
            assignment.Min(time_var))
        print(plan_output)
        total_time += assignment.Min(time_var)
    print('Tempo total de todas as rotas: {}min'.format(total_time))

def main():
    data = create_data_model()

    manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),
                                           data['num_vehicles'], data['depot'])

    routing = pywrapcp.RoutingModel(manager)

    def time_callback(from_index, to_index):
        from_node = manager.IndexToNode(from_index)
        to_node = manager.IndexToNode(to_index)
        return data['time_matrix'][from_node][to_node]

    transit_callback_index = routing.RegisterTransitCallback(time_callback)

    routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

    time = 'Time'
    routing.AddDimension(
        transit_callback_index,
        0,
        500,
        False,
        time)
    time_dimension = routing.GetDimensionOrDie(time)
    for location_idx, time_window in enumerate(data['time_windows']):
        if location_idx == 0:
            continue
        index = manager.NodeToIndex(location_idx)
        time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],
                                                data['time_windows'][0][1])

    # Adiciona restrição de Volume
    def demand_callback(from_index):
        from_node = manager.IndexToNode(from_index)
        return data['demands'][from_node]

    demand_callback_index = routing.RegisterUnaryTransitCallback(
        demand_callback)
    routing.AddDimensionWithVehicleCapacity(
        demand_callback_index,
        0,
        data['vehicle_capacities'],
        True,
        'Capacity')

    # Adiciona restrição de Peso
    def peso_callback(from_index):
        from_node = manager.IndexToNode(from_index)
        return data['demands_p'][from_node]

    peso_callback_index = routing.RegisterUnaryTransitCallback(
        peso_callback)
    routing.AddDimensionWithVehicleCapacity(
        demand_callback_index,
        0,
        data['vehicle_capacities_peso'],
        True,
        'Capacity')

    solver = routing.solver()
    intervals = []
    for i in range(data['num_vehicles']):
        intervals.append(
            solver.FixedDurationIntervalVar(
                time_dimension.CumulVar(routing.Start(i)),
                data['vehicle_load_time'], 'depot_interval'))
        intervals.append(
            solver.FixedDurationIntervalVar(
                time_dimension.CumulVar(routing.End(i)),
                data['vehicle_unload_time'], 'depot_interval'))

    for i in range(data['num_vehicles']):
        routing.AddVariableMinimizedByFinalizer(
            time_dimension.CumulVar(routing.Start(i)))
        routing.AddVariableMinimizedByFinalizer(
            time_dimension.CumulVar(routing.End(i)))

    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (
        routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

    assignment = routing.SolveWithParameters(search_parameters)

    if assignment:
        print_solution(data, manager, routing, assignment)
    else:
        print('No solution found !')

if __name__ == '__main__':
    main()


from tqdm import tqdm
import json
import torch
import numpy as np
import re
import scipy.stats
import torch.nn.functional as F
from scipy.optimize import minimize
from loader import re_match, sequence_padding

def compute_kl_loss(p,q, pad_mask=None):
    p_loss = F.kl_div(F.log_softmax(p,dim=-1), F.softmax(q, dim=-1), reduction='none')
    q_loss = F.kl_div(F.log_softmax(q,dim=-1), F.softmax(p,dim=-1), reduction='none')
    if pad_mask is not None:
        p_loss.masked_fill_(pad_mask, 0.)
        q_loss.masked_fill_(pad_mask, 0.)
    p_loss = p_loss.sum()
    q_loss = q_loss.sum()
    loss = (p_loss+q_loss) / 2
    return loss

def cosent_loss(y_pred,y_true):
    y_true = y_true[::2]
    norms = (y_pred ** 2).sum(axis=1, keepdims=True) ** 0.5
    y_pred = y_pred / norms
    y_pred = torch.sum(y_pred[::2] * y_pred[1::2], dim=1) * 20
    y_pred = y_pred[:, None] - y_pred[None, :]
    y_true = y_true[:, None] < y_true[None, :]
    y_true = y_true.float()
    y_pred = y_pred - (1 - y_true) * 1e12
    y_pred = y_pred.view(-1)
    y_pred = torch.cat((torch.tensor([0]).float().cuda(), y_pred), dim=0)
    return torch.logsumexp(y_pred, dim=0)

def sscl_loss(y_pred, y_neg):
    tmp = 0.07
    fcos = torch.nn.CosineSimilarity(dim=-1)
    idxs = torch.arange(0, y_pred.size()[0])
    idxs_1 = idxs[None, :]
    idxs_2 = (idxs + 1 - idxs % 2 * 2)[:, None]
    y_true = idxs_1==idxs_2
    y_true = y_true.float().cuda()
    p_sim = fcos(y_pred.unsqueeze(1), y_pred.unsqueeze(0))  / tmp
    n_sim = fcos(y_pred.unsqueeze(1), y_neg.unsqueeze(0))  / tmp
    pp_sim = p_sim - (torch.eye(y_pred.size()[0]) * 1e12).to('cuda')
    fm = torch.logsumexp(n_sim, dim=0).unsqueeze(-1)
    pm = torch.logsumexp(pp_sim,dim=0).unsqueeze(-1)
    loss =(-(p_sim-(fm+pm))*y_true).mean()
    return loss

def l2_normalize(vecs):
    """标准化
    """
    norms = (vecs**2).sum(axis=1, keepdims=True)**0.5
    return vecs / np.clip(norms, 1e-8, np.inf)

def compute_corrcoef(x, y):
    """Spearman相关系数
    """
    return scipy.stats.spearmanr(x, y).correlation

def evaluate(model, cfg, data, tokenizer):
    def convert_to_ids(e_list):
        input_ids, input_mask = [], []
        for e in e_list:
            inputs = tokenizer(e, max_length=cfg.maxlen, truncation=True)
            input_ids.append(inputs['input_ids'])
            input_mask.append(inputs['attention_mask'])
        input_ids = torch.tensor(sequence_padding(input_ids)).long()
        input_mask = torch.tensor(sequence_padding(input_mask)).float()
        return input_ids, input_mask

    all_e1_vecs = []
    all_e2_vecs = []
    all_labels = []
    for line in data:
        e1, e2, label = line['e1'], line['e2'], line['label']
        e1, e2 = re_match(e1), re_match(e2)
        input_ids, input_mask = convert_to_ids([e1, e2])
        label = torch.tensor([label], dtype=torch.float)
        model.eval()
        with torch.no_grad():
            input_ids, input_mask = input_ids.to(cfg.device), input_mask.to(cfg.device)
            output,_= model(input_ids, input_mask)
            all_e1_vecs.append(output[0].cpu().numpy())
            all_e2_vecs.append(output[1].cpu().numpy())
            all_labels.extend(label.cpu().numpy())

    all_e1_vecs = np.array(all_e1_vecs)
    all_e2_vecs = np.array(all_e2_vecs)
    all_labels = np.array(all_labels)

    e1_vecs = l2_normalize(all_e1_vecs)
    e2_vecs = l2_normalize(all_e2_vecs)
    sims = (e1_vecs*e2_vecs).sum(axis=1)
    corrcoef = compute_corrcoef(all_labels, sims)
    print('corrcoef', corrcoef)
    return corrcoef


from html.parser import HTMLParser
import urllib.request
from pprint import pprint as pp
import pandas as pd
import sys
from datetime import *
import copy
import numpy as np
import json
import sys
from pprint import pprint as pp

def load_jsonfile(path):
    with open(path, 'r') as f:
        arr = json.load(f)
    return arr

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag: " + str(tag) + ". With attributes: ", str(attrs))
        attrs_dict = dict(attrs)
        if tag == "table" and attrs_dict['id'] == 'tb':
            print("Found it!")

    def handle_endtag(self, tag):
        print("Encountered an end tag :", tag)

    def handle_data(self, data):
        print("Encountered some data  :", data)

# parser = MyHTMLParser()
# parser.feed(mystr)

def find_between(s, first, last ):
    try:
        start = s.index( first ) + len( first )
        end = s.index( last, start )
        return s[start:end]
    except ValueError:
        return ""

def convert_date(str):
    t1 = datetime.strptime(str, '%I:%M%p')
    t0 = datetime(1900, 1, 1)
    return (t1-t0).total_seconds() / 60.0

def convert_normalised(str):
    try:
        value = float(str.replace("kW/kW", ""))
        return value
    except ValueError:
        return 0.0

def time_extend(pd, tcolname, tval):

    full_time = np.arange(0, 24*60, tval, dtype=float)

    full_list = []

    for t in full_time:
        select = pd.loc[pd[tcolname] == t]

        if select.empty:
            listtoadd = [t, 0, 0]
        else:
            listtoadd = [t, 0, float(select['NormalisedFloat'])]

        # print(listtoadd)
        full_list.append(listtoadd)

    full_list_np = np.array(full_list)
    full_list_np_sorted = full_list_np[full_list_np[:, 0].argsort()]
    full_list_sorted = full_list_np_sorted.tolist()

    return full_list_sorted

def pvoutput_org(url):

    opener = urllib.request.urlopen(url)
    mybytes = opener.read()
    mystr = mybytes.decode("utf8")
    opener.close()
    only_table = find_between(mystr, "
", "
")
    listof_frames = pd.read_html(only_table)
    frame = listof_frames[0]

    date = frame.iloc[2,0]
    date_str = str(date).replace("/", "_")
    name = str(frame.iloc[0, 0]).replace(" ", "_")
    file_nane = name + "_" + date_str

    # cut off not necessary ones
    mod = frame.drop([11], axis=1)
    first_row = list(mod.iloc[1])
    mod = mod.drop([0, 1])
    mod.columns = first_row
    mod = mod.reset_index(drop=True)

    # take only necessary data
    mod2 = mod[['Time', 'Normalised']]
    mod3 = copy.deepcopy(mod2)

    # substitite dates with minutes and cut off units
    mod3['TimeSeconds'] = mod2.Time.apply(convert_date)
    mod3['NormalisedFloat'] = mod2.Normalised.apply(convert_normalised)
    mod3['Forecast'] = 0
    final = mod3.drop(['Time', 'Normalised'], axis=1)

    tval = 5
    full_list_sorted = time_extend(final, 'TimeSeconds', tval)
    sh = len(full_list_sorted)

    path = "/home/iso/PycharmProjects/vpp/data/original_elia/pvoutput_org/min5/" + str(file_nane) + '.json'
    with open(path, 'w') as outfile:
        json.dump(full_list_sorted, outfile)

    print("Saving list to json (length: " + str(sh) + ", period: "+str(tval)+" min) to the file: \n" + path)

url = "https://pvoutput.org/intraday.jsp?id=33196&sid=30411&dt=20180629"
pvoutput_org(url)


import json
from socketserver import BaseRequestHandler, TCPServer

class MessageHandler(BaseRequestHandler):
    def handle(self) -> None:
        message_received = self.request.recv(1024)
        if message_received == b"boardcomputer":
            request = input("Boardcomputer request option: ")
            self.request.send(request.encode())
            print(self.request.recv(1024))
        elif message_received == b"geofence":
            request = input("Geofence request [enable/disable/coords]: ")
            if request == "enable":
                self.request.send(json.dumps({
                    "command": "set_status",
                    "data": True
                }).encode())
            elif request == "disable":
                self.request.send(json.dumps({
                    "command": "set_status",
                    "data": False
                }).encode())
            elif request == "coords":
                coords = [
                    {"latitude": float(input("Latitude #1:")),
                     "longitude": float(input("Longitude #1:"))},
                    {"latitude": float(input("Latitude #2:")),
                     "longitude": float(input("Longitude #2:"))}
                ]
                self.request.send(json.dumps({
                    "command": "set_coords",
                    "data": coords
                }).encode())
            print(self.request.recv(1024))

if __name__ == '__main__':
    server = TCPServer(("0.0.0.0", 5000), MessageHandler)
    try:
        server.serve_forever()
    except BaseException:
        server.shutdown()
        raise


import os.path as osp

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QFileDialog, QGridLayout, QVBoxLayout

from .base_view import _AbstractImageToolView, create_imagetool_view
from ..ctrl_widgets import CalibrationCtrlWidget
from ..plot_widgets import ImageViewF
from ...ipc import CalConstantsPub

@create_imagetool_view(CalibrationCtrlWidget)
class CalibrationView(_AbstractImageToolView):
    """CalibrationView class.

    Widget for visualizing image calibration.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._corrected = ImageViewF(hide_axis=False)
        self._corrected.setTitle("Corrected")
        self._dark = ImageViewF(hide_axis=False)
        self._dark.setTitle("Dark (averaged)")
        self._gain = ImageViewF(hide_axis=False)
        self._gain.setTitle("Gain constants (averaged)")
        self._offset = ImageViewF(hide_axis=False)
        self._offset.setTitle("Offset constants (averaged)")

        self._pub = CalConstantsPub()

        self.initUI()
        self.initConnections()

    def initUI(self):
        """Override."""
        view_splitter = QGridLayout()
        view_splitter.addWidget(self._corrected, 0, 0)
        view_splitter.addWidget(self._dark, 1, 0)
        view_splitter.addWidget(self._gain, 0, 1)
        view_splitter.addWidget(self._offset, 1, 1)

        layout = QVBoxLayout()
        layout.addLayout(view_splitter)
        layout.addWidget(self._ctrl_widget)
        layout.setContentsMargins(1, 1, 1, 1)
        self.setLayout(layout)

    def initConnections(self):
        """Override."""
        self._ctrl_widget.load_gain_btn.clicked.connect(self._loadGainConst)
        self._ctrl_widget.load_offset_btn.clicked.connect(
            self._loadOffsetConst)

        self._ctrl_widget.remove_gain_btn.clicked.connect(self._removeGain)
        self._ctrl_widget.remove_offset_btn.clicked.connect(
            self._removeOffset)

    def updateF(self, data, auto_update):
        """Override."""
        if auto_update or self._corrected.image is None:
            self._corrected.setImage(data.image.masked_mean)
            self._dark.setImage(data.image.dark_mean)
            self._offset.setImage(data.image.offset_mean)
            self._gain.setImage(data.image.gain_mean)

    @pyqtSlot()
    def _loadGainConst(self):
        filepath = QFileDialog.getOpenFileName(caption="Load gain",
                                               directory=osp.expanduser("~"),
                                               filter="Numpy files (*.npy)")[0]

        # do not remove reference if the user meant to cancel the selection
        if filepath:
            self._pub.set_gain(filepath)
            self._ctrl_widget.gain_fp_le.setText(filepath)

    @pyqtSlot()
    def _loadOffsetConst(self):
        filepath = QFileDialog.getOpenFileName(caption="Load offset",
                                               directory=osp.expanduser("~"),
                                               filter="Numpy files (*.npy)")[0]

        # do not remove reference if the user meant to cancel the selection
        if filepath:
            self._pub.set_offset(filepath)
            self._ctrl_widget.offset_fp_le.setText(filepath)

    @pyqtSlot()
    def _removeGain(self):
        self._pub.set_gain("")
        self._ctrl_widget.gain_fp_le.setText("")

    @pyqtSlot()
    def _removeOffset(self):
        self._pub.set_offset("")
        self._ctrl_widget.offset_fp_le.setText("")

    def onDeactivated(self):
        btn = self._ctrl_widget.record_dark_btn
        if btn.isChecked():
            btn.setChecked(False)


from pathlib import Path
from typing import *
from collections import Counter
import pandas
from loguru import logger

def checkdir(path:Union[str,Path])->Path:
	path = Path(path)
	if not path.exists():
		path.mkdir()
	return path
def get_sample_metadata(sample_label: str) -> Dict[str, str]:
	""" Extracts metadata contained in the sample name.
		Assume the sample name is formatted as '{strain}.{condition}.{plate}.{replicate}'
	"""
	try:
		strain, condition, plate, replicate = sample_label.split('.')
	except ValueError:
		message = f"Could not parse a sample label ('{sample_label}'). Labels should be formatted as [strain].[condition].[plate].[replicate]"
		raise ValueError(message)
	data = {
		'sample':    sample_label,
		'strain':    strain,
		'condition': condition,
		'plate':     f"plate{plate}",
		'replicate': replicate
	}
	return data

def extract_sample_metadata(sample_names:List[str]) -> pandas.DataFrame:
	# Attempts to extract strain, replicate, sample_type, etc from the input table.
	# Assume that column names are formatted as '{strain}.{condition}.{plate}.{replicate}'
	metadata_table = [get_sample_metadata(label) for label in sample_names]
	return pandas.DataFrame(metadata_table).set_index('sample')

def normalize_series(data: pandas.Series) -> pandas.Series:
	""" Subtracts the minimum measured value from all other values in the series."""
	return data - data.min()

def normalize_table(table: pandas.DataFrame) -> pandas.DataFrame:
	""" Normalizes each column in the table by the minimum measured value for that column"""
	for column in table.columns:
		table[column] = normalize_series(table[column])
	return table

def _showcount(strings:List[str], index = None):
	""" Shows how often a string shows up."""

	if index is None:
		array = strings
	else:
		array = [i.split('.')[index] for i in strings]
	counter = Counter(array)

	for key, value in sorted(counter.items()):
		print(key,"\t", value)

def validate_labels(labels:List[str], verbose:bool = False):
	""" Checks all of the sample labels to make sure they conform to the format [strain].[condition].[plate].[replicate]"""
	# The 'time' column should be ignored for now.
	labels = [i for i in labels if i.lower() != 'time']
	for label in labels:
		parts = label.split('.')
		# Check for any additional parts in the sample label.
		if len(parts) != 4:
			message = f"The label '{label}' does not conform to the expected format: [strain].[condition].[plate].[replicate]"
			logger.warning(message)
	# Check for typos
	if verbose:
		print("Found the following occurances of strains: ")
		_showcount(labels, 0)

		print("Found the following occurances of conditions: ")
		_showcount(labels, 1)

def showcolumns(table:pandas.DataFrame):
	for column in sorted(table.columns):
		print(column)
# Convert this into a typeddict when available.
class TukeyFields:
	confint: List[float]
	data: Iterable[float]
	df_total: int
	groups: Iterable[str]
	groupsunique: Iterable[str]
	meandiffs: Iterable[float]
	pvalues: Iterable[float]
	q_crit: float
	reject: Iterable[bool]
	reject2: Iterable[bool]
	std_pairs: List[float]
	variance: float

def tukey_to_json(result)->Dict[str,Any]:
	""" Converts TukeyHSDResults to a dictionary."""

	data = {
		'confint': list(tuple(i) for i in result.confint),
		'data': list(float(i) for i in result.data),
		'df_total': int(result.df_total),
		'groups': list(result.groups),
		'groupsunique': list(result.groupsunique),
		'meandiffs': list(float(i) for i in result.meandiffs),
		'pvalues': list(float(i) for i in result.pvalues),
		'q_crit': float(result.q_crit),
		'reject': list(bool(i) for i in result.reject),
		'reject2': list(bool(i) for i in result.reject2),
		'std_pairs': list(float(i) for i in result.std_pairs),
		'variance': float(result.variance)
	}
	return data

if __name__ == "__main__":
	import datetime
	current_date = datetime.datetime.now()
	print(current_date.time())
	print(str(current_date.date()))


import json
import random
import time
from datetime import datetime, timedelta
from operator import and_

import sqlalchemy
from sqlalchemy.orm import DeclarativeBase, sessionmaker, scoped_session

import login_secrets as secrets

engine = sqlalchemy.create_engine(
    f"mysql+pymysql://{secrets.MYSQL_USER}:{secrets.MYSQL_PASSWORD}@{secrets.MYSQL_HOST}/{secrets.MYSQL_DATABASE}"
)
connection = None

while not connection:
    try:
        connection = engine.connect()
    except Exception as e:
        print("Waiting for database to start...")
        print(e)
        time.sleep(2)

print("Connected to database")

session_maker = sessionmaker(bind=engine)

def get_session():
    return scoped_session(session_maker)()

class Base(DeclarativeBase):
    pass

class Record(Base):
    __tablename__ = "history"
    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
    monitor = sqlalchemy.Column(sqlalchemy.String(45))
    temperature = sqlalchemy.Column(sqlalchemy.Float)
    humidity = sqlalchemy.Column(sqlalchemy.Float)
    timestamp = sqlalchemy.Column(sqlalchemy.DateTime)

    def __repr__(self):
        return f"<Record {self.id} {self.monitor} {self.temperature} {self.humidity} {self.timestamp}>"

    def to_json(self):
        return {
            "temperature": self.temperature,
            "humidity": self.humidity,
            "timestamp": self.timestamp.isoformat()
        }

    @staticmethod
    def create(monitor: str, temperature: float, humidity: float):
        record = Record(
            monitor=monitor,
            temperature=temperature,
            humidity=humidity,
            timestamp=datetime.now()
        )

        with get_session() as session:
            session.add(record)
            session.commit()

        return record

    @staticmethod
    def get_recent_for_monitor(monitor: str, hours: int = 1, max_records: int = 1000):
        earliest = datetime.now() - timedelta(hours=hours)
        with get_session() as session:
            results = session.query(Record).filter(
                and_(
                    Record.monitor == monitor,
                    Record.timestamp >= earliest
                )
            )

            count = results.count()

            if count <= max_records or max_records == 0:
                return results.all()

            # Too many records, return evenly spaced records
            step = count // max_records
            stepped_records = results.filter(Record.id % step == 0)

            return stepped_records.limit(max_records)

    @staticmethod
    def get_json_for_monitor(monitor: str, hours: int = 1, max_records: int = 1000):
        records = Record.get_recent_for_monitor(monitor, hours, 0)  # Get all records within the time range
        number_of_records = len(records)

        if max_records == 0:
            # Return every record
            return json.dumps([record.to_json() for record in records])

        # Fetch a random sample of number_of_records - 2 records
        indices_to_keep = set(
            random.sample(range(1, number_of_records - 1), max(min(number_of_records, max_records) - 2, 0)))
        # Force the first and last record to be included
        if number_of_records > 0:
            indices_to_keep.add(0)
            indices_to_keep.add(number_of_records - 1)
        return json.dumps([record.to_json() for i, record in enumerate(records) if i in indices_to_keep])

def initialize_database():
    Base.metadata.create_all(engine)


import numpy as np

import rospy

import tf.transformations as tr

from chugg_learning.chugg_domain import ChuggDomainBase, quat_distance
from chugg_physics.ChuggSimulator import ChuggSimulator
from chugg_physics.ROSChuggSimulator import ROSChuggSimulator

# Our quaternion convention: (w, x, y, z)
# Transformations.py convention: (w, x, y, z)
# Simulator convention: (x, y, z, w)
# def to_sim_convention(q):
#     return np.array((q[1], q[2], q[3], q[0]))
# def from_sim_convention(q):
#     return np.array((q[3], q[0], q[1], q[2]))

class OfflineChuggSimulatorDomain(ChuggDomainBase):

    # Extra args are passed to physics simulator
    def __init__(self, sim_type=ChuggSimulator, **kwargs):

        self.sim_args = kwargs
        self.sim_type = sim_type
        self.sim = None

        super(OfflineChuggSimulatorDomain, self).__init__()

    def s0(self):
        if self.sim is None:
            self.sim = self.sim_type(**self.sim_args)

        if self.random_start:
            self.state = self._randomState()
        else:
            self.state = self.default_state

        self.traj = [self.state]

        # Used to compute penalty for ending early
        self.current_step = 0

        # Set the physics simulator state
        (ori, vel, wheel_vel) = self._state()
        # ori = to_sim_convention(ori)

        self.sim.setState(ori=ori, vel=vel, wheel_vel=wheel_vel)

        # Implicitly converted to tuple
        return self.state.copy(), self.isTerminal(), self.possibleActions()

    def step(self, action_idx):
        action = self.actions[action_idx]
        acc = action

        # print self.sim.ori, self.sim.vel, self.sim.wheel_vel
        # Step the physics simulator
        self.sim.step(acc, dt=self.dt)
        self._updateStateFromSimulator()

        new_state = self.state.copy()
        self.traj.append(new_state)

        reward = self._getReward(action)

        return (reward, new_state, self.isTerminal(), self.possibleActions() )

    def _updateStateFromSimulator(self):
        ori = self.sim.ori
        (roll, pitch, yaw) = tr.euler_from_quaternion(ori, self.euler_convention)
        rpy = np.array((roll, pitch, yaw))
        vel = self.sim.vel
        wheel_vel = self.sim.wheel_vel
        state = np.hstack((rpy, vel, wheel_vel))
        self.state = state

class OnlineChuggSimulatorDomain(OfflineChuggSimulatorDomain):

    speedup = 10

    def __init__(self):
        super(OnlineChuggSimulatorDomain, self).__init__(sim_type=ROSChuggSimulator, spin_thread=False)

    def showDomain(self, a):
        self.sim.publishState()
        # print "Ori: ", self.sim.ori, " vel: ", self.sim.vel, " wheel_vel: ", self.sim.wheel_vel
        rospy.sleep(self.dt/self.speedup)


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os
import pickle
import random
import time
from functools import partial
from helperFunctions import *
from smallestEnclosingCircle import make_circle
sns.set_style('white')
sns.set(font_scale=5)
#%%
# Load in a point cloud
df = pd.read_csv('./ROI-0_MainText.csv')
labels = {'T Helper Cell' : 1,
                   'Regulatory T Cell' : 2,
                   'Cytotoxic T Cell' : 3,
                   'Macrophage' : 4,
                   'Neutrophil' : 5,
                   'Epithelium' : 6
                    }

points = np.asarray([df['x'],df['y']]).transpose()

pc = generatePointCloud('ROI',points,domain=[[0,1000],[0,1000]])
pc.addLabels('Celltype','categorical',df.Celltype,cmap='tab10')

pc.changeIndividualLabelColor('Celltype', 'Epithelium', plt.cm.tab10(0))
pc.changeIndividualLabelColor('Celltype', 'T Helper Cell', plt.cm.tab10(1))
pc.changeIndividualLabelColor('Celltype', 'Macrophage', plt.cm.tab10(2))
pc.changeIndividualLabelColor('Celltype', 'Neutrophil', plt.cm.tab10(4))
pc.changeIndividualLabelColor('Celltype', 'Cytotoxic T Cell', plt.cm.tab10(3))
pc.changeIndividualLabelColor('Celltype', 'Regulatory T Cell', plt.cm.tab10(5))

visualisePointCloud(pc,'Celltype',markerSize=100)

#%% All cross-PCFs (Fig 5)
maxR=150
annulusStep = 10
annulusWidth = 10

avals = []
bvals = []
pcfs = []
for a in pc.labels['Celltype']['categories']:
    for b in pc.labels['Celltype']['categories']:
        print(a,b)
        r, pcf, contributions = pairCorrelationFunction(pc, 'Celltype', [a,b], maxR=maxR,annulusStep=annulusStep,annulusWidth=annulusWidth)
        avals.append(a)
        bvals.append(b)
        pcfs.append(pcf)

sns.set(font_scale=2.4)
fig, ax = plt.subplots(nrows=len(pc.labels['Celltype']['categories']), ncols=len(pc.labels['Celltype']['categories']),sharex=True,sharey=True)
it = 0
for i,a in enumerate(pc.labels['Celltype']['categories']):
    for j,b in enumerate(pc.labels['Celltype']['categories']):
        ax[i,j].plot(r,pcfs[it],lw=5)
        if i == 5:
            ax[i,j].set_xlabel(b)
        if j == 0:
            ax[i,j].set_ylabel(a)
        ax[i,j].set_ylim([0,10])
        ax[i,j].axhline(1,linestyle=':',c='k',lw=3)
        it = it + 1

#%% Selected cross-PCFs - g_{ThE}
sns.set(font_scale=5)
a = 'T Helper Cell'
b = 'Epithelium'
maxR=150
annulusStep = 1
annulusWidth = 20
r, pcf, contributions = pairCorrelationFunction(pc, 'Celltype', [a,b], maxR=maxR,annulusStep=annulusStep,annulusWidth=annulusWidth)

plt.figure(figsize=(18,18))
plt.plot(r, pcf, lw=5)
plt.gca().axhline(1,c='k',linestyle=':',lw=3)
plt.xlabel('$r$ ($\mu$m)')
plt.ylabel('$g_{ThE}(r)$')

#%%Selected cross-PCFs - g_{ThM}
a = 'T Helper Cell'
b = 'Macrophage'

maxR=150
annulusStep = 1
annulusWidth = 20
r, pcf, contributions = pairCorrelationFunction(pc, 'Celltype', [a,b], maxR=maxR,annulusStep=annulusStep,annulusWidth=annulusWidth)

plt.figure(figsize=(18,18))
plt.plot(r, pcf, lw=5)
plt.gca().axhline(1,c='k',linestyle=':',lw=3)
plt.xlabel('$r$ ($\mu$m)')
plt.ylabel('$g_{ThM}(r)$')

#%% TCM example
typea = 'T Helper Cell'
typeb = 'Macrophage'

tcm = topographicalCorrelationMap(pc,'Celltype',typea,'Celltype',typeb,radiusOfInterest=50,maxCorrelationThreshold=5.0,kernelRadius=150,kernelSigma=50,visualiseStages=False)

#%
plt.figure(figsize=(20,20))
l = int(np.ceil(np.max(np.abs([tcm.min(),tcm.max()]))))
plt.imshow(tcm,cmap='RdBu_r',vmin=-l,vmax=l,origin='lower')
plt.colorbar(label='$\Gamma_{C_1 C_2}(r=50)$')
ax = plt.gca()
ax.grid(False)

#%% NCF example

maxR = 150
celltypes = ['T Helper Cell','Macrophage','Neutrophil']

ns = {v:np.sum(df.Celltype == v) for v in celltypes}
circles, triplets = neighbourhoodCorrelationFunction(pc,'Celltype',celltypes,maxR=maxR)

step = 5
bins=np.arange(0,maxR+step,step)
vals_observed, rs = np.histogram(circles,bins=bins)

redoBootstrap = False
if redoBootstrap:
    bootstrappedRadii = []
    nBootstrap = 100000000
    for i in range(nBootstrap):
        if i % 100000 == 0:
            print(i)
        temp = make_circle(1000*np.random.rand(3,2))
        bootstrappedRadii.append(temp[2])
        vals_bootstrap, rs = np.histogram(bootstrappedRadii,bins=bins)
        vals_bootstrap = vals_bootstrap/nBootstrap
else:

    if (step == 5) & ~redoBootstrap:
        vals_bootstrap = np.array([     6,     86,    372,    890,   1957,   3455,   5578,   8315,
                12064,  16432,  21767,  28480,  36075,  45048,  54542,  65789,
                78113,  90920, 105552, 121675, 138988, 157609, 177132, 198158,
               221789, 245811, 270577, 296563, 323350, 353548])/100000000
    elif (step == 10) & ~redoBootstrap:
        vals_bootstrap = np.array([    92,   1262,   5412,  13893,  28496,  50247,  81123, 120331,
               169033, 227227, 296597, 375290, 467600, 567140, 676898])/100000000
    else:
        print('Bootstrapping values not pre-calculated for this radial step value, set redoBoostrap=True')
        assert(1==2) # I'm not good at errors
    vals_bootstrap = ns[celltypes[0]]*ns[celltypes[1]]*ns[celltypes[2]]*vals_bootstrap

plt.figure(figsize=(18,18))
plt.plot(rs[1:],vals_bootstrap,label='Expectation (CSR)',lw=5)
plt.plot(rs[1:],vals_observed,label='Observation',lw=5)
plt.xlabel('$r$ ($\mu$m)')
plt.ylabel('Number')
plt.legend()

plt.figure(figsize=(18,18))
plt.plot(rs[1:],vals_observed/vals_bootstrap,lw=5)
plt.gca().axhline(1,c='k',linestyle=':',lw=3)
plt.xlabel('$r$ ($\mu$m)')
plt.ylabel('NCF$_{Th M N}(r)$')

#%% wPCF example
pc.addLabels('Epithelium','categorical',df.Epithelium,cmap='tab10')
pc.addLabels('CD4','continuous',df.CD4,cmap='Oranges')

pc.changeIndividualLabelColor('Epithelium', 'Positive', plt.cm.tab10(0))
pc.changeIndividualLabelColor('Epithelium', 'Negative', [0.8,0.8,0.8,1])
visualisePointCloud(pc,'Epithelium',markerSize=100)
visualisePointCloud(pc,'CD4',markerSize=50,vmax=24,cmap='Oranges')

def weightingFunction(p,l_B):
    weights = 1-np.abs(p-l_B)/2
    weights = np.maximum(weights, np.zeros(np.shape(weights)))
    return weights

targetP = np.arange(0,25,1)
w = [weightingFunction(5, v) for v in targetP]
plt.figure()
plt.plot(targetP,w)

# Values used in manuscript:
    # annulusStep = 1
    # annulusWidth = 20
    # I've changed them here so that if you're running this code you won't get bored and think it's broken
    # If you want to reproduce the exact plot from the paper, stick these values in and go and get a cup of tea (it doesn't take that long, but it's a lot more calculations)
annulusStep = 10
annulusWidth = 20

r, targetP, wPCF = weightedPairCorrelationFunction(pc, 'Epithelium', 'Positive', 'CD4',maxR=150,annulusStep=annulusStep,annulusWidth=annulusWidth,targetP=targetP,weightingFunction=weightingFunction)
plotWeightedPCF(r,targetP,wPCF,vmin=0,vmax=5,ax=None,cm='plasma')

# Plot the cross-PCF over the top of the cross-sections
maxR = 150
a = 'Epithelium'
b = 'T Helper Cell'
r, pcf, contributions = pairCorrelationFunction(pc, 'Celltype', [a,b], maxR=maxR,annulusStep=annulusStep,annulusWidth=annulusWidth)
plt.figure(figsize=(18,18))
plt.gca().axhline(1,c='k',linestyle=':',lw=5)
for v in np.linspace(0,targetP[-1],5):
    v = int(np.floor(v))
    plt.plot(r,wPCF[:,v],label=f'CD4 = {targetP[v]}',c=plt.cm.viridis(v/len(targetP)),lw=7)
plt.plot(r,pcf,c='r',linestyle='--',lw=7,label='$g_{ETh}(r)$')
plt.legend()
plt.xlabel('Radius ($r$)')
plt.ylabel('wPCF($r$, $E$, CD4)')


from django.db import models

class Elimination(models.Model):
    game = models.ForeignKey(Game, related_name='eliminations', default=Game.get_current, on_delete=models.CASCADE)  # TODO: redundant; players already store game information
    quota_check = models.ForeignKey(QuotaCheck, related_name='eliminations', blank=True, null=True)
    attacker = models.ForeignKey(Player, related_name='eliminations_as_attacker')
    target = models.ForeignKey(Player, related_name='eliminations_as_target')
    is_reverse = models.BooleanField(default=False)  # NOTE: e.g. self.target was eliminated by self.target.target, not self.attacker
    timestamp = models.DateTimeField(auto_now_add=True)
    valid = models.BooleanField(default=True)

    class Meta:
        ordering = ('-pk',)

    def __str__(self):
        return str(self.game) + ": " + self.killer_name + " -> " + str(self.target)

    @property
    def from_quota_check(self):
        return self.quota_check_id is not None  # TODO: is id of null foreign key None or 0?

    @property
    def killer(self):
        return None if (self.quota_check or self.is_reverse) else self.attacker  # TODO: currently returns None if reverse elimination (target killed by target rather than attacker); implement way to track target

    @property
    def killer_name(self):
        return str(self.killer) if self.killer else "Quota check"

    def clean(self):
        if self.attacker.pk == self.target.pk:
            raise ValidationError(_('Attacker and target cannot be the same player'))
        if self.from_quota_check and self.is_reverse:
            raise ValidationError(_('Elimination due to quota check cannot be a reverse elimination'))

    def save(self, *args, **kwargs):
        if not self.pk:  # TODO: only on creation?
            # target = self.target
            # attacker = target.attacker  # database hit
            # target_target = target.target  # database hit
            # attacker.target = target_target
            # target.target = None
            # target.alive = False
            # target.save()
            # attacker.save()
            # self.attacker = attacker

            self.attacker = self.target.attacker  # single database hit
            self.attacker.target = self.target.target  # single database hit
            self.target.target = None
            self.target.alive = False
            self.target.save()
            self.attacker.save()
            if self.from_quota_check:  # killed by quota check
                self.game.send_message(self.target, ELIMINATED_BY_QUOTA_CHECK_MESSAGE)  # single database hit
                self.game.send_message(self.attacker, TARGET_ELIMINATED_BY_QUOTA_CHECK_MESSAGE % self.attacker.target)  # single database hit
            elif self.is_reverse:  # self-defense kill
                self.game.send_message(self.target, ELIMINATED_BY_TARGET_MESSAGE % self.attacker.target)  # single database hit
                self.game.send_message(self.attacker, TARGET_ELIMINATED_BY_TARGET_MESSAGE % (self.target, self.attacker.target))  # single database hit
                self.game.send_message(self.attacker.target, ATTACKER_ELIMINATED_BY_TARGET_MESSAGE % self.target)  # single database hit
            else:  # normal kill
                self.game.send_message(self.target, ELIMINATED_BY_ATTACKER_MESSAGE % self.attacker)  # single database hit
                self.game.send_message(self.attacker, TARGET_ELIMINATED_BY_ATTACKER_MESSAGE % (self.target, self.attacker.target))  # single database hit
            self.game.do_check_end()
        super(Elimination, self).save(*args, **kwargs)

    @property
    def num_dependencies(self):
        return 0  # TODO: return the number of dependent eliminations that would need to be reverted by self.revert() without actually having to call self.revert()

    # TODO: make sure e.revert_helper is never called directly outside of this class
    def revert_helper(self, revert_dependencies=True, revert_quota_check_dependencies=True):  # TODO: revert_helper means no need to check for future eliminations due to quota checks (none, or all reverted/invalidated already)
        num_reverted = 0
        if self.valid:
            num_reverted = 1
            print(TARGET_ELIMINATED_BY_QUOTA_CHECK_MESSAGE % self.target)  # TODO: remove
            # check for dependencies
            if revert_dependencies:
                if revert_quota_check_dependencies:
                    quota_checks = self.game.quota_checks.filter(timestamp__gt=self.timestamp).order_by('-pk').all()
                    for qc in quota_checks:
                        num_reverted += qc.revert(revert_dependencies=False)
                # INVARIANT: all quota_checks that come after this elimination have been reverted
                to_revert = []
                eliminations = self.game.eliminations.filter(valid=True).filter(pk__gt=self.pk).order_by('pk').all()  # TODO: in order of occurrence
                for e in eliminations:
                    # NOTE: self.from_quota_check CAN be true here; but for all e, e.from_quota_check MUST be false here - all future quota check eliminations should have been reverted/invalidated by this point
                    if e.attacker.pk == self.attacker.pk:  # TODO: ensure that the original self.target.target is alive: revert all eliminations e where e.attacker is self.attacker (attacker guaranteed not null - because any quota_checks in the future have been reverted at this point)
                        to_revert.append(e)
                    elif e.target.pk == self.attacker.pk:  # TODO: ensure that the original self.attacker is alive: if self.attacker was eliminated, revive him (e.g. revert that elimination); again - guaranteed not to have been eliminated by quota check at this point (e.g. attacker null)
                        num_reverted += e.revert_helper(revert_quota_check_dependencies=False)
                        break
                for e in reversed(to_revert):
                    num_reverted += e.revert_helper(revert_dependencies=False, revert_quota_check_dependencies=False)
            # INVARIANT: original self.attacker is alive, original self.target.target is alive, and original self.attacker.target is self.target.target now can revert this elimination
            # revert elimination
            target = Player.objects.get(pk=self.target.pk)  # NOTE: force reload updated object from database
            attacker = Player.objects.get(pk=self.attacker.pk)  # NOTE: force reload updated object from database

            print("Target: " + str(target.pk))
            print("Attacker: " + str(attacker.pk))
            print("Attacker's Target: " + str(attacker.target.pk))

            target.alive = True
            target.target = attacker.target
            print("Target's Target: " + str(target.target.pk))
            self.attacker.target = target
            print("Attacker's Target: " + str(attacker.target.pk))
            print("Target's Target: " + str(target.target.pk))
            self.attacker.save()
            print("Attacker's Target: " + str(attacker.target.pk))
            print("Target's Target: " + str(target.target.pk))
            target.save()
            self.valid = False
            self.save()
            # send messages
            self.game.send_message(target, REVIVED_BY_ADMIN_MESSAGE)  # TODO: clarify that attacker is the same as before?
            self.game.send_message(attacker, TARGET_REVIVED_BY_ADMIN_MESSAGE % (target, target))
        return num_reverted

    def revert(self):
        if self.from_quota_check:
            return self.quota_check.revert()
        else:
            return self.revert_helper()


import os

from setuptools import setup, find_packages

def read(fname):
    return open(os.path.join(os.path.dirname(__file__), fname)).read()

setup(
    name='ckanext-right_time_context',
    version='0.9',
    url='https://github.com/conwetlab/ckanext-right_time_context',
    author='CoNWeT Lab & FICODES',
    author_email='ckanextended@conwet.com',
    classifiers=[
        'Development Status :: 5 - Production/Stable',
        'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
    ],
    packages=find_packages(exclude=['contrib', 'docs', 'tests*']),
    install_requires=[],
    include_package_data=True,
    long_description=read('README.md'),
    long_description_content_type="text/markdown",
    package_data={
    },
    data_files=[],
    tests_require=[
        'parameterized',
    ],
    test_suite='nosetests',
    entry_points='''
        [ckan.plugins]
        right_time_context=ckanext.right_time_context.plugin:NgsiView
    ''',
)


import matplotlib.pyplot as plt
import pandas as pd

cube = pd.read_json('cube_closefit.json')
cube = cube.sort_values('tsn_ln_global_sales')

def quickplot(data):
    fig, ax = plt.subplots()
    for (label, axis) in data:
        ax.plot([x for x in cube[axis]], label=label)

    legend = ax.legend(loc='upper center', shadow=True, fontsize='x-large')
    legend.get_frame().set_facecolor('C0')
    plt.show()


import argparse

import common
import service
from common import File, request_download, debug_out

services = service.index_services()

def download_files(files: list[File], download_path):
    """
    Helper function for downloading multiple files
    :param files: list of files to download
    :param download_path: path to save
    :return:
    """
    file_count = len(files)
    for i, file in enumerate(files):
        print("\r", end='')
        print(f"Downloading files... ({i+1}/{file_count})", end='')
        request_download(
            file.link, download_path, file.name, modified=float(file.modtime)
        )
    print()
    print(f"{file_count} files downloaded.")

def oneshot(service_type, acct_id, download_path, post_id):
    """
    Parses and downloads images from a single post
    :param service_type: parser/service to use
    :param acct_id: account identifier
    :param download_path: path to download
    :param post_id: post identifier
    :return:
    """
    _service = services[service_type]
    files = _service.parse_post(acct_id, post_id)
    download_files(files, download_path)

def download_from_feed(service_type, acct_id, download_path, post_count=20, offset=0):
    """
    Parses and download images from recent feed
    :param service_type: parser/service to use
    :param acct_id: account identifier
    :param download_path: path to download
    :param post_count: number of posts to download; default = 20
    :param offset: number of most recent posts to skip; default = 0
    :return:
    """
    _service = services[service_type]
    feed = _service.get_recent_posts(acct_id, post_count, offset)
    files = []
    print("Searching posts...", end="")
    for i, post in enumerate(feed):
        print("\r", end="")
        files.extend(_service.extract_images(acct_id, post))
        print(f"Searching {i+1} out of {len(feed)} posts..."
              f" ({len(files)} image(s) collected)", end="")

    print(" OK.")
    download_files(files, download_path)

def main(args):
    """
    tumbl-down main function; program entry point
    :param args: parsed arguments by ArgumentParser
    :return:
    """
    service_type = args.service
    debug_out(f"Service type: {service_type}")
    common.DEBUG = args.verbose
    for i, account in enumerate(args.account_id):
        print(f"Fetching feed of {account}..."
              f" ({i+1}/{len(args.account_id)})")
        download_from_feed(service_type, account, account,
                           post_count=args.posts, offset=args.offset)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-v", "--verbose", help="increase output verbosity",
                        action="store_true")
    parser.add_argument("-n", "--posts", type=int, default=20,
                        help="specify number of posts to query")
    parser.add_argument("--offset", type=int, default=0,
                        help="specify offset of posts to query")
    parser.add_argument("--date-after", help="only download ")
    parser.add_argument("service", help="type of service to use")
    parser.add_argument("account_id",
                        help="the account ID or IDs to download images from",
                        nargs='+')
    main(args=parser.parse_args())


from .views import message_list,MessageList,message_view,chat_view
from django.urls import path
app_name='messaging'
urlpatterns = [
    path('', chat_view, name='chats'),

    path('messages/<int:sender>/<int:receiver>/', message_view, name='chat'),
# URL form : "/api/messages/1/2"
    path('api/messages/<int:sender>/<int:receiver>/',message_list,name='message_detail'),
    # URL form : "/api/messages/"
    path('api/messages/',message_list,name='message_list'),
]


import importlib
import operator as op

from django.core.exceptions import ImproperlyConfigured
from sidekick import lazy

class LazyMethod:
    """
    Lazily import a method from the given class and inject in the current class
    on first use.
    """

    @lazy
    def object(self):
        try:
            mod = importlib.import_module(self.module)
        except ImportError:
            raise ImproperlyConfigured(
                f"failed to import module: {self.module}\n"
                f"Please install this module in your environment."
            )
        return self.attr_getter(mod)

    def __init__(self, path, pip=None):
        self.module, _, self.path = path.partition(":")
        self.pip = pip
        self.attr_getter = op.attrgetter(self.path)

    def __get__(self, obj, cls=None):
        imported = self.object
        try:
            getter = imported.__get__
        except AttributeError:
            return self if obj is None else obj
        else:
            return getter(obj, cls)

    def __set__(self, obj, value):
        obj = self.object
        obj.__set__(obj, value)

    def __set_name__(self, owner, name):
        self.name = name

def with_base(bases, cls):
    """
    Return a copy of bases tuple that contains the given additional class `cls`.
    """

    if cls in bases:
        return bases

    bases = list(bases)
    tail = []
    while bases:
        if issubclass(cls, bases[-1]):
            tail.append(bases.pop())
        else:
            bases.append(cls)
            break

    return (*bases, *reversed(tail))


from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, Http404

from personal_collection. models import BookCopy
from .models import LendRequest, LendCopy

@login_required
def lend_request_view(request, copy_id):
    """View for handling lend request forms."""
    book_copy = BookCopy.objects.get(id=copy_id)
    requesting_user = request.user
    copy_owner = book_copy.owner

    lend_request = LendRequest.objects.get_or_create(
        requesting_user=requesting_user,
        copy_owner=copy_owner,
        copy=book_copy)

    return redirect('lend_manager:lend_overview')

@login_required
def cancel_lend_request_view(request, lend_request_id):
    """View for handling cancellation of a request."""
    canceled_request = LendRequest.objects.get(id=lend_request_id)
    if request.user != canceled_request.requesting_user:
        raise Http404
    else:
        canceled_request.delete()

    return redirect('lend_manager:lend_overview')

@login_required
def refuse_lend_request_view(request, lend_request_id):
    """View for handling refusing a lend request."""
    refused_request = LendRequest.objects.get(id=lend_request_id)
    if request.user != refused_request.copy_owner:
        raise Http404
    else:
        refused_request.delete()

    return redirect('lend_manager:lend_overview')

@login_required
def lend_accept_view(request, lend_request_id):
    """View for handling accepting a lend_request."""
    lend_request = LendRequest.objects.get(id=lend_request_id)

    lend_accept = LendCopy.objects.get_or_create(
        from_user=lend_request.copy_owner,
        to_user=lend_request.requesting_user,
        copy=lend_request.copy
    )
    lend_request = LendRequest.objects.get(id=lend_request_id).delete()
    return redirect('lend_manager:lend_overview')

@login_required
def book_return_confirmation_view(request, lend_copy_id):
    """Page for confirming a book return."""
    return_book = LendCopy.objects.filter(id=lend_copy_id).select_related().first()

    context = {'return_book': return_book, 'lend_copy_id': lend_copy_id}
    return render(request, 'lend_manager/return_confirmation.html', context)

@login_required
def book_return_view(request, lend_copy_id):
    """View for handling returning of a book."""
    returned_book = LendCopy.objects.get(id=lend_copy_id)
    if returned_book.from_user != request.user:
        raise Http404
    else:
        returned_book = LendCopy.objects.get(id=lend_copy_id).delete()
        return redirect('lend_manager:lend_overview')

@login_required
def lend_overview_view(request):
    """Summary overview of all book lent to and from the user."""
    lend_requests_by_user = LendRequest.objects.filter(requesting_user=request.user).select_related()
    lend_requests_to_user = LendRequest.objects.filter(copy_owner=request.user).select_related()
    books_lend_by_user =  LendCopy.objects.filter(from_user=request.user).select_related()
    books_lend_to_user = LendCopy.objects.filter(to_user=request.user).select_related()

    context = {
        'lend_requests_by_user': lend_requests_by_user,
        'lend_requests_to_user': lend_requests_to_user,
        'books_lend_by_user': books_lend_by_user,
        'books_lend_to_user': books_lend_to_user,
    }
    return render(request, 'lend_manager/lend_overview.html', context)