#!/usr/bin/python3

import matplotlib.pyplot as plt
import numpy as np
from typing import List, Tuple, Union
from PIL import Image
import time
import os

RADIUS = 150  # aim to 20 cm (/7.5)
SCREWS_AMOUNT = 210  # better resolution in 470
STRING_LENGTH = 7.5 * RADIUS * 615
THREAD_WEIGHT = 13
DISTANCE_WEIGHT = 20.7

class Gui:
    def __init__(self, screws_position: List[Tuple[float, float]]):
        self._screws_position = screws_position

    def draw_strings(self, strings: List[Tuple[int, int]]) -> None:
        for line in strings:
            self._draw_screws_string_connection(line[0], line[1])

    def draw_screws(self, labels=False) -> None:
        plt.scatter(self._screws_position[:, 0], self._screws_position[:, 1], s=1)
        if not labels:
            return
        for i, sc in enumerate(self._screws_position[::10]):
            plt.text(sc[0], sc[1], str(i * 10))

    def _draw_screws_string_connection(self, screw1: int, screw2: int) -> None:
        pos_1 = self._screws_position[screw1]
        pos_2 = self._screws_position[screw2]
        plt.plot([pos_1[0], pos_2[0]], [pos_1[1], pos_2[1]],
                 alpha=0.99, c='black', linewidth=0.233)

    def show(self) -> None:
        plt.axis('off')
        plt.gcf().tight_layout()
        plt.gca().invert_yaxis()
        plt.gcf().gca().set_aspect('equal', 'datalim')
        plt.show()

class Engine:
    def __init__(self, image_path: str, preprocess: bool = True):
        self._screws_position = None
        self._image = None
        self._distances = None
        self._samples = None
        self._prepare_image(image_path)
        self._init_screws()
        if preprocess:
            self._init_distances_and_samples()

    def _prepare_image(self, image_path: str) -> None:
        # load image as grayscale
        im = np.array(Image.open(image_path).convert('L'))
        # crop image to circle center
        center = np.floor(0.5 * np.array(im.shape)).astype(np.int32)
        im_radius = min(center)
        im_crop = im[center[0] - im_radius: center[0] + im_radius,
                  center[1] - im_radius: center[1] + im_radius]
        # scale to circle size
        im = np.array(Image.fromarray(im_crop).resize((RADIUS * 2 + 1, RADIUS * 2 + 1)))
        im = (100 / 255) * im
        self._image = im.copy()
        # TODO consider quantisizing, blurring, normalizing to gray

    def _init_screws(self) -> None:
        x0, y0 = np.array(self._image.shape[::-1]) * 0.5
        rads = (2 * np.pi / SCREWS_AMOUNT) * np.arange(SCREWS_AMOUNT)
        xys = np.array([[x0 + RADIUS * np.sin(angle), y0 + RADIUS * np.cos(angle)]
                        for angle in rads])
        self._screws_position = xys

    def _init_distances_and_samples(self) -> None:
        preprocessed_path = f'preprocessed_{RADIUS}_{SCREWS_AMOUNT}.npy'
        if os.path.exists(preprocessed_path):
            loaded_preprocessed = np.load(preprocessed_path, allow_pickle=True)
            self._distances, self._samples = loaded_preprocessed
            print('Working with preprocessed data.')
        else:
            assert self._screws_position is not None, 'screws not initialized'
            all_screws_pos = np.array(self._screws_position)
            all_screws_x_diff = np.subtract.outer(all_screws_pos[:, 0], all_screws_pos[:, 0])
            all_screws_y_diff = np.subtract.outer(all_screws_pos[:, 1], all_screws_pos[:, 1])
            self._distances = np.sqrt(np.sum(np.power(np.stack((all_screws_x_diff, all_screws_y_diff)), 2), axis=0))

            # TODO vectorise? (preprocess optimization is less crucial).
            self._samples = {}
            for i1, p1 in enumerate(self._screws_position):
                for i2, p2 in enumerate(self._screws_position[i1 + 1:], i1 + 1):
                    euclidean_distance = self._distances[i1, i2]
                    sample_rate = np.arange(np.floor(euclidean_distance - 1)) / euclidean_distance
                    xs = np.hstack([p1[0] + (p2[0] - p1[0]) * sample_rate, p2[0]])
                    ys = np.hstack([p1[1] + (p2[1] - p1[1]) * sample_rate, p2[1]])
                    self._samples[(i1, i2)] = (xs, ys)
            np.save(preprocessed_path[:-4], (self._distances, self._samples))
            print('saved preprocessed data.')

    def get_distance(self, screw1: int, screw2: int) -> float:
        if not (0 <= screw1 < SCREWS_AMOUNT) or \
                not (0 <= screw2 < SCREWS_AMOUNT):
            raise IndexError
        # s1, s2 = min(screw1, screw2), max(screw1, screw2)  # no need, profit is low.
        return self._distances[screw1, screw2]

    def sample_line(self, screw1: int, screw2: int) -> Tuple[List[float], List[float]]:
        if not (0 <= screw1 < SCREWS_AMOUNT) or \
                not (0 <= screw2 < SCREWS_AMOUNT):
            raise IndexError
        s1, s2 = min(screw1, screw2), max(screw1, screw2)
        return self._samples[(s1, s2)]

    def get_screws_positions(self) -> List[Tuple[float, float]]:  # each screw's (x,y)
        assert self._screws_position is not None, 'screws not initialized'
        return self._screws_position.copy()

    def get_image(self):
        return self._image

    @staticmethod
    def just_try(randomize: bool, connected: bool) -> Union[List[List[int]], List[Tuple[int, int]]]:
        if randomize:
            amount = 500
            if connected:
                return Engine.steps_to_tuples(np.random.randint(SCREWS_AMOUNT, size=amount))
            else:
                return np.random.randint(SCREWS_AMOUNT, size=(amount, 2))
        else:
            jump = 70
            return np.vstack([np.arange(SCREWS_AMOUNT - jump),
                              np.arange(SCREWS_AMOUNT - jump) + jump]).T

    @staticmethod
    def steps_to_tuples(steps: List[int]) -> List[Tuple[int, int]]:
        return list(zip(steps[:-1], steps[1:]))

# TODO separate all classes to different files.

class Algo:
    def __init__(self, engine):
        self._leftover_string = STRING_LENGTH
        self._engine = engine
        self._curr_state = engine.get_image().copy()
        self._steps = None

    def _update_state(self, from_screw: int, to_screw: int, state):
        xs, ys = self._engine.sample_line(from_screw, to_screw)
        ys = np.round(ys).astype(np.int)
        xs = np.round(xs).astype(np.int)
        ys = ys.clip(0, state.shape[0] - 1)
        xs = xs.clip(0, state.shape[1] - 1)
        edited_state = state.copy()
        edited_state[ys, xs] += THREAD_WEIGHT
        return edited_state

    def _get_next_naive(self, current_screw: int, state) -> Tuple[int, float]:
        if not (0 <= current_screw < SCREWS_AMOUNT):
            raise IndexError
        best_candidate = current_screw
        while best_candidate == current_screw:
            best_candidate = (current_screw + np.random.randint(SCREWS_AMOUNT)) % SCREWS_AMOUNT
        best_score = self._score_line_naive(current_screw, best_candidate, state)
        for screw_i in range(SCREWS_AMOUNT):
            if screw_i in (current_screw, best_candidate):
                continue
            score = self._score_line_naive(current_screw, screw_i, state)
            if score > best_score:
                best_candidate = screw_i
                best_score = score
        return best_candidate, best_score

    def _score_path_aux(self, degree: int, current_screw: int, next_screw: int,
                        state) -> Tuple[float, float, np.ndarray, List[int]]:
        state = self._update_state(current_screw, next_screw, state)
        cur2next_score = self._score_line_naive(current_screw, next_screw, state)
        cur2next_amount = self._engine.get_distance(current_screw, next_screw)
        score, amount, c_state, c_screws = self._get_path(degree - 1, next_screw, state)
        return cur2next_score + score, cur2next_amount + amount, c_state, [next_screw] + c_screws

    def _get_path(self, degree: int, current_screw: int, state) -> Tuple[float, float, np.ndarray, List[int]]:
        # recursively get the best next and returns (accumulative score, accumulative amount, state, final screw)
        assert degree > 0, f'Algo::_get_path called with invalid degree: {degree}'
        if degree == 1:
            following_screw, following_score = self._get_next_naive(current_screw, state)
            assert following_screw != current_screw
            following_state = self._update_state(current_screw, following_screw, state)
            following_amount = self._engine.get_distance(current_screw, following_screw)
            return following_score, following_amount, following_state, [following_screw]
        else:
            # typedef:   b_ prefix for best_something;  c_ prefix for candidate_something.
            best_candidate = current_screw
            while best_candidate == current_screw:
                best_candidate = (current_screw + np.random.randint(SCREWS_AMOUNT)) % SCREWS_AMOUNT
            b_score, b_amount, b_state, b_screws = self._score_path_aux(degree, current_screw, best_candidate, state)
            for screw_i in range(SCREWS_AMOUNT):
                if screw_i in (current_screw, best_candidate):
                    continue
                c_score, c_amount, c_state, c_screws = self._score_path_aux(degree, current_screw, screw_i, state)
                if c_score > b_score:
                    best_candidate = screw_i
                    b_score, b_amount, b_state, b_screws = c_score, c_amount, c_state, c_screws
            assert len(b_screws) == degree
            return b_score, b_amount, b_state, b_screws

    def _score_line_naive(self, screw1: int, screw2: int, state) -> float:
        xs, ys = self._engine.sample_line(screw1, screw2)
        ys = np.round(ys).astype(np.int)
        xs = np.round(xs).astype(np.int)
        ys = ys.clip(0, state.shape[0] - 1)
        xs = xs.clip(0, state.shape[1] - 1)
        return (-1 * np.sum(state[ys, xs])) / (DISTANCE_WEIGHT*self._engine.get_distance(screw1, screw2))

    def execute(self, degree: int) -> List[int]:
        current_screw = np.random.randint(SCREWS_AMOUNT)
        next_screws = [current_screw]
        steps = []
        modulus = 7 - (degree ** 2)
        while self._leftover_string > 0:
            score, amount, next_state, next_screws = self._get_path(degree, current_screw=current_screw,
                                                                    state=self._curr_state)
            steps.extend([current_screw] + next_screws[:-1])
            current_screw = next_screws[-1]
            self._leftover_string -= amount
            self._curr_state = next_state
            if len(steps) % modulus == 0:
                print(f'leftover: {self._leftover_string}')
        steps.append(next_screws[-1])
        return steps

def main_load(image_path: str, steps_path: str):
    infrastructure_engine = Engine(image_path, preprocess=False)
    steps = np.load(steps_path)
    steps = steps[1000:]
    steps = np.mod(steps + 157, 210)  # steps = np.roll(steps, 157)
    tup_steps = infrastructure_engine.steps_to_tuples(steps)
    print(len(steps))
    ui = Gui(infrastructure_engine.get_screws_positions())
    ui.draw_screws()
    ui.draw_strings(tup_steps)
    ui.show()
    stxt = 209 - steps
    with open('out_steps.txt', 'w') as f:
        f.write(', '.join([str(x) for x in stxt]))
    print(stxt)

def main(image_path: str, calculate_only: bool = False):
    print(f'Running with string length {STRING_LENGTH / (7.5 * 100 * 1000)} km, to create a circle with radius '
          f'{RADIUS / 6} cm, with {SCREWS_AMOUNT} screws.')
    infrastructure_engine = Engine(image_path)
    ui = Gui(infrastructure_engine.get_screws_positions())

    algo = Algo(infrastructure_engine)
    begin_time = time.time()
    res_steps = algo.execute(1)
    endtime = time.time()
    np.save(f'last_run_{STRING_LENGTH / (7.5 * 100 * 1000)}_{RADIUS / 7.5}_{SCREWS_AMOUNT}', res_steps)
    print('Algo time: ', endtime - begin_time)
    print('Steps amount: ', len(res_steps))

    # trial = infrastructure_engine.just_try(randomize=True, connected=True)
    if not calculate_only:
        ui.draw_screws()
        # plt.imshow(infrastructure_engine.get_image())
        ui.draw_strings(infrastructure_engine.steps_to_tuples(res_steps))
        ui.show()

if __name__ == '__main__':
    my_photo = '/home/ru/Pictures/myphotox2.jpg'
    main(my_photo)
    # npy_steps_path = '/home/ru/develop/StringsImage/list146.npy'
    # final_npy_steps_path = '/home/ru/develop/StringsImage/mypicture34.pnglast_run_3.0_25.0_210.npy'
    # main_load(my_photo, final_npy_steps_path)


from itertools import combinations

n = int(input())
A = input().split()
k = int(input())
list1 = list(A)
list2 = []
for i in range(1, n+1):
    list2.append(i)
t = len(list(combinations(list2,k)))

for i in range(1,n+1):
    if list1[i-1] == "a":
        list2.remove(i)

v = len(list(combinations(list2,k)))
print("{0:.3}".format((t-v)/t))


import logging
import binascii
import Crypto.Random
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

logger = logging.getLogger(__name__)

class Wallet:
    def __init__(self):
        self.private_key = None
        self.public_key = None

    def create_keys(self):
        """
        Function to create private and public keys to validate transactions
        """
        private_key, public_key = self.generate_keys()
        self.private_key = private_key
        self.public_key = public_key

    def save_keys(self):
        """
        Function to save keys to the disk
        """
        if not (self.public_key is None and self.private_key is None):
            try:
                with open('wallet.txt', 'w') as f:
                    f.write(self.public_key)
                    f.write("\n")
                    f.write(self.private_key)
                return True
            except (IOError,
                    IndexError):  # IndexError - File exists but is empty
                logger.error('Saving wallet failed')
                print('Saving wallet failed')
                return False

    def load_keys(self):
        """
        Function to load keys from the disk
        """
        try:
            with open('wallet.txt', 'r') as f:
                keys = f.readlines()
                # All characters except the line break
                self.public_key = keys[0][:-1]
                self.private_key = keys[1]
            return True
        except (IOError, IndexError):
            logger.error('Loading wallet failed')
            print('Loading wallet failed')
            return False

    def generate_keys(self):
        """
        Function to generate private and public keys
        """
        private_key = RSA.generate(1024, Crypto.Random.new().read)
        public_key = private_key.publickey()
        # Returning string representation of the key
        return (binascii.hexlify(
            private_key.exportKey(format='DER')).decode('ascii'),
                binascii.hexlify(
                    public_key.exportKey(format='DER')).decode('ascii'))

    def sign_transaction(self, sender, recipient, amount):
        signer = PKCS1_v1_5.new(
            RSA.importKey(binascii.unhexlify(self.private_key)))
        hhash = SHA256.new(
            (str(sender) + str(recipient) + str(amount)).encode('utf8'))

        signature = signer.sign(hhash)
        return binascii.hexlify(signature).decode('ascii')

    @staticmethod
    def verify_transaction_signature(transaction):
        public_key = RSA.importKey(binascii.unhexlify(transaction.sender))
        verifier = PKCS1_v1_5.new(public_key)
        hhash = SHA256.new(
            (str(transaction.sender) + str(transaction.recipient) +
             str(transaction.amount)).encode('utf8'))

        return verifier.verify(hhash, binascii.unhexlify(
            transaction.signature))  # Returns Boolean value


from fbs import fbs_subscribe, fbs_login, fbs_connect
import time
import websocket
import flatbuffers
import Hoevo
import Hoevo.VehicleInfo
import Hoevo.Any
import Hoevo.Msg
import Hoevo.Payload
import Hoevo.PayloadType
import Hoevo.Login
import Hoevo.Project
import Hoevo.PUBLISH
import Hoevo.Role
import Hoevo.QoS
import Hoevo.Flag

def set_vehicle_info_to_data():
    data = {
        'uuid': "test_data",
        'player_id': "test_data",
        'device_id': "test_data",
        'bEngineStart': False,
        'bHandBrake': False,
        'ClutchIntensity': 0.5,
        'BrakePedalIntensity': 1,
        'ThrottleIntensity': 0.5,
        'bSafetyBelt': False,
        'CurrentGear': 1,
        'bAddGearByDegrees': False,
        'bSubGearByDegrees': False,
        'CorneringLampState': 1,
        'bHorn': False,
        'bDoubleFlash': False,
        'SteeringWheelAngle': 0.5,
        'Speed': 0.0,
        'TrainingProgram': 304,
        'TimeStamp': 1234567,
        'bVehicleBodyHit': False,
        'bVehicleFLWheelHit': True,
        'bVehicleFRWheelHit': False,
        'bVehicleBLWheelHit': False,
        'bVehicleBRWheelHit': False,
        'bProgramEnd': False,
        'bFlameOut': False,
        'ReverseParkingLeftCount': 1,
        'ReverseParkingRightCount': 1,
        'bParkingTrace': False,
        'bIsInParkingArea': False,
        'PassThroughCheckpointCount': 2,
        'bIsPassingThroughCheckpoint': False,
        'bBridge1': False,
        'bBridge2': False,
        'bBridge3': False,
        'bBridge4': False,
        'bRampParking1': False,
        'bRampParking2': False,
        'RPM': 1,
        'bIsOnZebraCrossing': False,
        'bCanVehiclePassThrough': False,
        'bFLWheelHitDottedLine': False,
        'bFRWheelHitDottedLine': False,
        'bBLWheelHitDottedLine': False,
        'bBRWheelHitDottedLine': False,
        'bWheelHitSolidLine': False,
        'bIsInTurnAroundArea': False,
        'bWiperOn': False,
        'bIsHeadLightsOn': False,
        'WiperState': 2,
        'HeadlightsState': 1,
        'bFogLampOn': False,
        'bWidthIndicator': False,
        'bLimitDoorCheckPoint': False,
        'bHitPeopleOrCar': False,
        'bEmergencyOperation': False,
        'EmergencyTraining': 23,
        'bOnRightRoad': False,
        'bRunOverbedgeOfTheRoad': False,
        'bDrivingThroughRollingRoad': False,
        'bStopOnEmergencyVehicleLane': False,
        'bAboutToLeaveTheTunnel': False,
        'bDecelerateWithinTheSpecifiedRange': False,
        'bTurnAccordingToTheRules': False,
        'bGearOperationCorrect': False,
        'bStopInFiftyCm': False,
        'bStopInThirtyCm': False,
        'bAlternateUseLight': False,
        'bTurnAfterThreeSecond': False,
        'bActiveGuidancePracticeSuccessed': False,
        'bTurnAroundStep1': False,
        'bTurnAroundStep2': False,
        'bTurnAroundStep3': False,
        'bTurnAroundStep4': False
    }

    builder = flatbuffers.Builder(flatbuffers.Builder.MAX_BUFFER_SIZE)
    topic_string = builder.CreateString(str("server"))
    device_uuid = builder.CreateString(str("vehicle_client_test"))
    uuid = builder.CreateString(str(data['uuid']))
    player_id = builder.CreateString(str(data['player_id']))
    device_id = builder.CreateString(str(data['device_id']))

    Hoevo.VehicleInfo.VehicleInfoStart(builder)
    Hoevo.VehicleInfo.VehicleInfoAddUuid(builder, uuid)
    Hoevo.VehicleInfo.VehicleInfoAddPlayerId(builder, player_id)
    Hoevo.VehicleInfo.VehicleInfoAddDeviceId(builder, device_id)
    Hoevo.VehicleInfo.VehicleInfoAddEngineStart(builder, data['bEngineStart'])
    Hoevo.VehicleInfo.VehicleInfoAddHandBrake(builder, data['bHandBrake'])
    Hoevo.VehicleInfo.VehicleInfoAddClutchIntensity(builder, data['ClutchIntensity'])
    Hoevo.VehicleInfo.VehicleInfoAddBrakePedalIntensity(builder, data['BrakePedalIntensity'])
    Hoevo.VehicleInfo.VehicleInfoAddThrottleIntensity(builder, data['ThrottleIntensity'])
    Hoevo.VehicleInfo.VehicleInfoAddSafetyBelt(builder, data['bSafetyBelt'])
    Hoevo.VehicleInfo.VehicleInfoAddCurrentGear(builder, data['CurrentGear'])
    Hoevo.VehicleInfo.VehicleInfoAddAddGearByDegrees(builder, data['bAddGearByDegrees'])
    Hoevo.VehicleInfo.VehicleInfoAddCorneringLampState(builder, data['CorneringLampState'])
    Hoevo.VehicleInfo.VehicleInfoAddHorn(builder, data['bHorn'])
    Hoevo.VehicleInfo.VehicleInfoAddDoubleFlash(builder, data['bDoubleFlash'])
    Hoevo.VehicleInfo.VehicleInfoAddSteeringWheelAngle(builder, data['bDoubleFlash'])
    Hoevo.VehicleInfo.VehicleInfoAddSpeed(builder, 10)
    Hoevo.VehicleInfo.VehicleInfoAddTrainingProgram(builder, data['TrainingProgram'])
    Hoevo.VehicleInfo.VehicleInfoAddTimestamp(builder, data['TimeStamp'])
    Hoevo.VehicleInfo.VehicleInfoAddVehicleBodyHit(builder, data['bVehicleBodyHit'])
    Hoevo.VehicleInfo.VehicleInfoAddVehicleFlWheelHit(builder, data['bVehicleFLWheelHit'])
    Hoevo.VehicleInfo.VehicleInfoAddVehicleFrWheelHit(builder, data['bVehicleFRWheelHit'])
    Hoevo.VehicleInfo.VehicleInfoAddVehicleBlWheelHit(builder, data['bVehicleBLWheelHit'])
    Hoevo.VehicleInfo.VehicleInfoAddVehicleBrWheelHit(builder, data['bVehicleBRWheelHit'])
    Hoevo.VehicleInfo.VehicleInfoAddProgramEnd(builder, data['bProgramEnd'])
    Hoevo.VehicleInfo.VehicleInfoAddFlameout(builder, data['bFlameOut'])
    Hoevo.VehicleInfo.VehicleInfoAddReverseParkingLeftCount(builder, data['ReverseParkingLeftCount'])
    Hoevo.VehicleInfo.VehicleInfoAddReverseParkingRightCount(builder, data['ReverseParkingRightCount'])
    Hoevo.VehicleInfo.VehicleInfoAddParkingTrace(builder, data['bParkingTrace'])
    Hoevo.VehicleInfo.VehicleInfoAddInParkingArea(builder, data['bIsInParkingArea'])
    Hoevo.VehicleInfo.VehicleInfoAddPassThroughCheckpointCount(builder, data['PassThroughCheckpointCount'])
    Hoevo.VehicleInfo.VehicleInfoAddPassingThroughCheckpoint(builder, data['bIsPassingThroughCheckpoint'])
    Hoevo.VehicleInfo.VehicleInfoAddBridge1(builder, data['bBridge1'])
    Hoevo.VehicleInfo.VehicleInfoAddBridge2(builder, data['bBridge2'])
    Hoevo.VehicleInfo.VehicleInfoAddBridge3(builder, data['bBridge3'])
    Hoevo.VehicleInfo.VehicleInfoAddBridge4(builder, data['bBridge4'])
    Hoevo.VehicleInfo.VehicleInfoAddRampParking1(builder, data['bRampParking1'])
    Hoevo.VehicleInfo.VehicleInfoAddRampParking2(builder, data['bRampParking2'])
    Hoevo.VehicleInfo.VehicleInfoAddRpm(builder, data['RPM'])
    Hoevo.VehicleInfo.VehicleInfoAddOnZebraCrossing(builder, data['bIsOnZebraCrossing'])
    Hoevo.VehicleInfo.VehicleInfoAddCanVehiclePassThrough(builder, data['bCanVehiclePassThrough'])
    Hoevo.VehicleInfo.VehicleInfoAddFlWheelHitDottedLine(builder, data['bFLWheelHitDottedLine'])
    Hoevo.VehicleInfo.VehicleInfoAddFrWheelHitDottedLine(builder, data['bFRWheelHitDottedLine'])
    Hoevo.VehicleInfo.VehicleInfoAddBlWheelHitDottedLine(builder, data['bBLWheelHitDottedLine'])
    Hoevo.VehicleInfo.VehicleInfoAddBrWheelHitDottedLine(builder, data['bBRWheelHitDottedLine'])
    Hoevo.VehicleInfo.VehicleInfoAddWheelHitSolidLine(builder, data['bWheelHitSolidLine'])
    Hoevo.VehicleInfo.VehicleInfoAddInTurnAroundArea(builder, data['bIsInTurnAroundArea'])
    Hoevo.VehicleInfo.VehicleInfoAddWiperOn(builder, data['bWiperOn'])
    Hoevo.VehicleInfo.VehicleInfoAddIsHeadLightsOn(builder, data['bIsHeadLightsOn'])
    Hoevo.VehicleInfo.VehicleInfoAddWiperState(builder, data['WiperState'])
    Hoevo.VehicleInfo.VehicleInfoAddHeadlightsState(builder, data['HeadlightsState'])
    Hoevo.VehicleInfo.VehicleInfoAddFogLampOn(builder, data['bFogLampOn'])
    Hoevo.VehicleInfo.VehicleInfoAddWidthIndicator(builder, data['bWidthIndicator'])
    Hoevo.VehicleInfo.VehicleInfoAddLimitDoorCheckpoint(builder, data['bLimitDoorCheckPoint'])
    Hoevo.VehicleInfo.VehicleInfoAddHitPeopleOrCar(builder, data['bHitPeopleOrCar'])
    Hoevo.VehicleInfo.VehicleInfoAddEmergencyOperation(builder, data['bEmergencyOperation'])
    Hoevo.VehicleInfo.VehicleInfoAddEmergencyTraining(builder, data['EmergencyTraining'])
    Hoevo.VehicleInfo.VehicleInfoAddOnRightRoad(builder, data['bOnRightRoad'])
    Hoevo.VehicleInfo.VehicleInfoAddRunOverbedgeOfTheRoad(builder, data['bRunOverbedgeOfTheRoad'])
    Hoevo.VehicleInfo.VehicleInfoAddDrivingThroughRollingRoad(builder, data['bDrivingThroughRollingRoad'])
    Hoevo.VehicleInfo.VehicleInfoAddStopOnEmergencyVehicleLane(builder, data['bStopOnEmergencyVehicleLane'])
    Hoevo.VehicleInfo.VehicleInfoAddAboutToLeaveTheTunnel(builder, data['bAboutToLeaveTheTunnel'])
    Hoevo.VehicleInfo.VehicleInfoAddDecelerateWithinTheSpecifiedRange(builder, data['bDecelerateWithinTheSpecifiedRange'])
    Hoevo.VehicleInfo.VehicleInfoAddTurnAccordingToTheRules(builder, data['bTurnAccordingToTheRules'])
    Hoevo.VehicleInfo.VehicleInfoAddGearOperationCorrect(builder, data['bGearOperationCorrect'])
    Hoevo.VehicleInfo.VehicleInfoAddStopInFiftyCm(builder, data['bStopInFiftyCm'])
    Hoevo.VehicleInfo.VehicleInfoAddStopInThirtyCm(builder, data['bStopInThirtyCm'])
    Hoevo.VehicleInfo.VehicleInfoAddAlternateUseLight(builder, data['bAlternateUseLight'])
    Hoevo.VehicleInfo.VehicleInfoAddTurnAfterThreeSecond(builder, data['bTurnAfterThreeSecond'])
    Hoevo.VehicleInfo.VehicleInfoAddActiveGuidancePracticeSuccessed(builder, data['bActiveGuidancePracticeSuccessed'])
    Hoevo.VehicleInfo.VehicleInfoAddTurnAroundStep1(builder, data['bTurnAroundStep1'])
    Hoevo.VehicleInfo.VehicleInfoAddTurnAroundStep2(builder, data['bTurnAroundStep2'])
    Hoevo.VehicleInfo.VehicleInfoAddTurnAroundStep3(builder, data['bTurnAroundStep3'])
    Hoevo.VehicleInfo.VehicleInfoAddTurnAroundStep4(builder, data['bTurnAroundStep4'])
    vehicle_info_data = Hoevo.VehicleInfo.VehicleInfoEnd(builder)

    Hoevo.Payload.PayloadStart(builder)
    Hoevo.Payload.PayloadAddAnyType(builder, Hoevo.Any.Any().VehicleInfo)
    Hoevo.Payload.PayloadAddAny(builder, vehicle_info_data)
    payload = Hoevo.Payload.PayloadEnd(builder)

    builder.Finish(payload)
    payload = builder.Output()

    payload_bytes = bytearray(payload)
    Hoevo.PUBLISH.StartPayloadVector(builder, len(payload_bytes))
    for i in reversed(range(0, len(payload_bytes))):
        print(payload_bytes[i])
        builder.PrependByte(payload_bytes[i])
    payload = builder.EndVector()

    Hoevo.PUBLISH.PUBLISHStart(builder)
    Hoevo.PUBLISH.PUBLISHAddPayload(builder, payload)
    Hoevo.PUBLISH.PUBLISHAddPayloadType(builder, Hoevo.PayloadType.PayloadType().FBS)
    Hoevo.PUBLISH.PUBLISHAddTopic(builder, topic_string)
    Hoevo.PUBLISH.PUBLISHAddClientId(builder, device_uuid)
    Hoevo.PUBLISH.PUBLISHAddQos(builder, Hoevo.QoS.QoS().AtMostOnce)
    PUBLISH = Hoevo.PUBLISH.PUBLISHEnd(builder)

    Hoevo.Msg.MsgStart(builder)
    Hoevo.Msg.MsgAddFlag(builder, PUBLISH)
    Hoevo.Msg.MsgAddFlagType(builder, Hoevo.Flag.Flag().PUBLISH)
    msg = Hoevo.Msg.MsgEnd(builder)

    builder.Finish(msg)
    data = builder.Output()

    return data

def send_connect(ws):
    print("### send connect ###")
    connect = fbs_connect.SendConnect()
    connect.client_id = "vehicle_client_test"
    data = connect.send_fbs_connect()
    ws.send(data, 0x2)
    global websocket_connect
    websocket_connect = True
    time.sleep(2)
    send_login(ws)
    time.sleep(2)
    send_subscribe(ws)
    while True:
        send_VehicleInfo(ws)

def send_login(ws):
    print("### send login ###")
    login = fbs_login.SendLogin()
    login.client_id = "vehicle_client_test"
    login.ip = "127.0.0.1"
    data = login.send_fbs_login()
    ws.send(data, 0x2)

def send_VehicleInfo(ws):
    print("### send send_VehicleInfo ###")
    data = set_vehicle_info_to_data()
    ws.send(data, 0x2)

def send_subscribe(ws):
    print("### send subscribe ###")
    subscribe = fbs_subscribe.SendSubscribe()
    subscribe.topic = "server/#"
    subscribe.topic_1 = "server"
    subscribe.client_id = "vehicle_client_test"
    data = subscribe.send_subscribe()
    ws.send(data, 0x2)

def send_test_data(ws):
    print("### send subscribe ###")

def ws_connect():
    #websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://127.0.0.1:4001/ws/")
    ws.on_open = send_connect
    ws.run_forever()

if __name__ == '__main__':
    while True:
        ws_connect()


import pygame
from pygame.sprite import Sprite

class Alien( Sprite ):
    """ Класс, пришельца """
    def __init__( self, game_settings, screen ):
        super().__init__()
        self.screen = screen
        self.game_settings = game_settings

        # Загрузка изображения и назначение атрибута rect
        self.image = pygame.image.load('images/alien.bmp')
        self.rect = self.image.get_rect()

        # Каждый новый прищелец появляется в верхнем углу
        self.rect.x = self.rect.width
        self.rect.x = self.rect.height

        self.x = float( self.rect.x )

    def blitme( self ):
        """ """
        self.screen.blit( self.image, self.rect )

    def check_edges( self ):
        """ True, если достиг края"""
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right: return True
        elif self.rect.right <= 0: return True

    def update( self ):
        """ перемещает прищельца в право"""
        self.x += self.game_settings.alien_speed_factor * self.game_settings.fleet_direction
        self.rect.x = self.x


import pandas as pd
import numpy as np

def handle_extreme_weather(special_dates_df, base_activity_level):
    # 获取极端天气日期
    extreme_weather_dates = special_dates_df[special_dates_df['type'] == 'extreme_weather']

    # 处理极端天气
    for _, row in extreme_weather_dates.iterrows():
        # 消费量前移
        base_activity_level[row['start_date'] - pd.Timedelta(days=2):row['start_date'] - pd.Timedelta(days=1)] *= 2
        # 极端天气期间消费量下降
        base_activity_level[row['start_date']:row['end_date']] *= 0.5
        # 恢复期消费量逐步恢复
        recovery_dates = pd.date_range(start=row['end_date'] + pd.Timedelta(days=1), periods=min(3, len(base_activity_level) - row['end_date'].dayofyear))
        for i, date in enumerate(recovery_dates):
            base_activity_level[date] *= (0.7 + 0.1 * (i + 1))

    return base_activity_level

# 读取特殊日期数据
special_dates_df = pd.read_csv('../special_dates.csv')
special_dates_df['start_date'] = pd.to_datetime(special_dates_df['start_date'])
special_dates_df['end_date'] = pd.to_datetime(special_dates_df['end_date'])

# 创建基础活动级别
dates = pd.date_range(start='2022-01-01', periods=365)
base_activity_level = pd.Series(np.random.uniform(low=0.2, high=0.2, size=365), index=dates)

# 处理极端天气
base_activity_level = handle_extreme_weather(special_dates_df, base_activity_level)

# 打印结果
print(base_activity_level)

import matplotlib.pyplot as plt

# 使用上面的代码处理极端天气
# ...

# 创建一个新的figure和axes
fig, ax = plt.subplots()

# 绘制活动级别
ax.plot(base_activity_level.index, base_activity_level.values, label='Activity Level')

# 添加标题和标签
ax.set_title('Activity Level Over Time')
ax.set_xlabel('Date')
ax.set_ylabel('Activity Level')

# 显示图例
ax.legend()
plt.show()


from skimage.feature import peak_local_max
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage as ndi
import sys
import torch
# from support.layer.nms import nms
import torchvision

from skimage import filters
from skimage.measure import regionprops

rel_peak_thr = .3
rel_rel_thr = .3
ioa_thr = .6
topk_boxes = 3

def heat2bbox(heat_map, original_image_shape):
    h, w = heat_map.shape

    bounding_boxes = []

    heat_map = heat_map - np.min(heat_map)
    heat_map = heat_map / np.max(heat_map)

    bboxes = []
    box_scores = []

    peak_coords = peak_local_max(heat_map, exclude_border=False,
                                 threshold_rel=rel_peak_thr)  # find local peaks of heat map

    heat_resized = cv2.resize(heat_map, (
    original_image_shape[1], original_image_shape[0]))  ## resize heat map to original image shape
    peak_coords_resized = ((peak_coords + 0.5) *
                           np.asarray([original_image_shape]) /
                           np.asarray([[h, w]])
                           ).astype('int32')

    for pk_coord in peak_coords_resized:
        pk_value = heat_resized[tuple(pk_coord)]
        mask = heat_resized > pk_value * rel_rel_thr
        labeled, n = ndi.label(mask)
        l = labeled[tuple(pk_coord)]
        yy, xx = np.where(labeled == l)
        min_x = np.min(xx)
        min_y = np.min(yy)
        max_x = np.max(xx)
        max_y = np.max(yy)
        bboxes.append((min_x, min_y, max_x, max_y))
        box_scores.append(pk_value)  # you can change to pk_value * probability of sentence matching image or etc.

    ## Merging boxes that overlap too much
    box_idx = np.argsort(-np.asarray(box_scores))
    box_idx = box_idx[:min(topk_boxes, len(box_scores))]
    bboxes = [bboxes[i] for i in box_idx]
    box_scores = [box_scores[i] for i in box_idx]

    to_remove = []
    for iii in range(len(bboxes)):
        for iiii in range(iii):
            if iiii in to_remove:
                continue
            b1 = bboxes[iii]
            b2 = bboxes[iiii]
            isec = max(min(b1[2], b2[2]) - max(b1[0], b2[0]), 0) * max(min(b1[3], b2[3]) - max(b1[1], b2[1]), 0)
            ioa1 = isec / ((b1[2] - b1[0]) * (b1[3] - b1[1]))
            ioa2 = isec / ((b2[2] - b2[0]) * (b2[3] - b2[1]))
            if ioa1 > ioa_thr and ioa1 == ioa2:
                to_remove.append(iii)
            elif ioa1 > ioa_thr and ioa1 >= ioa2:
                to_remove.append(iii)
            elif ioa2 > ioa_thr and ioa2 >= ioa1:
                to_remove.append(iiii)

    for i in range(len(bboxes)):
        if i not in to_remove:
            bounding_boxes.append({
                'score': box_scores[i],
                'bbox': bboxes[i],
                'bbox_normalized': np.asarray([
                    bboxes[i][0] / heat_resized.shape[1],
                    bboxes[i][1] / heat_resized.shape[0],
                    bboxes[i][2] / heat_resized.shape[1],
                    bboxes[i][3] / heat_resized.shape[0],
                ]),
            })

    return bounding_boxes

def img_heat_bbox_disp(image, heat_map, title='', en_name='', alpha=0.6, cmap='viridis', cbar='False', dot_max=False,
                       bboxes=[], order=None, show=True):
    thr_hit = 1  # a bbox is acceptable if hit point is in middle 85% of bbox area
    thr_fit = .60  # the biggest acceptable bbox should not exceed 60% of the image
    H, W = image.shape[0:2]
    # resize heat map
    heat_map_resized = cv2.resize(heat_map, (H, W))

    # display
    fig = plt.figure(figsize=(15, 5))
    fig.suptitle(title, size=15)
    ax = plt.subplot(1, 3, 1)
    plt.imshow(image)
    if dot_max:
        max_loc = np.unravel_index(np.argmax(heat_map_resized, axis=None), heat_map_resized.shape)
        plt.scatter(x=max_loc[1], y=max_loc[0], edgecolor='w', linewidth=3)

    if len(bboxes) > 0:  # it gets normalized bbox
        if order == None:
            order = 'xxyy'

        for i in range(len(bboxes)):
            bbox_norm = bboxes[i]
            if order == 'xxyy':
                x_min, x_max, y_min, y_max = int(bbox_norm[0] * W), int(bbox_norm[1] * W), int(bbox_norm[2] * H), int(
                    bbox_norm[3] * H)
            elif order == 'xyxy':
                x_min, x_max, y_min, y_max = int(bbox_norm[0] * W), int(bbox_norm[2] * W), int(bbox_norm[1] * H), int(
                    bbox_norm[3] * H)
            x_length, y_length = x_max - x_min, y_max - y_min
            box = plt.Rectangle((x_min, y_min), x_length, y_length, edgecolor='w', linewidth=3, fill=False)
            plt.gca().add_patch(box)
            if en_name != '':
                ax.text(x_min + .5 * x_length, y_min + 10, en_name,
                        verticalalignment='center', horizontalalignment='center',
                        # transform=ax.transAxes,
                        color='white', fontsize=15)
                # an = ax.annotate(en_name, xy=(x_min,y_min), xycoords="data", va="center", ha="center", bbox=dict(boxstyle="round", fc="w"))
                # plt.gca().add_patch(an)

    plt.imshow(heat_map_resized, alpha=alpha, cmap=cmap)

    # plt.figure(2, figsize=(6, 6))
    plt.subplot(1, 3, 2)
    plt.imshow(image)
    # plt.figure(3, figsize=(6, 6))
    plt.subplot(1, 3, 3)
    plt.imshow(heat_map_resized)
    fig.tight_layout()
    fig.subplots_adjust(top=.85)

    if show:
        plt.show()
    else:
        plt.close()

    return fig

def filter_bbox(bbox_dict, order=None):
    thr_fit = .90  # the biggest acceptable bbox should not exceed 80% of the image
    if order == None:
        order = 'xxyy'

    filtered_bbox = []
    filtered_bbox_norm = []
    filtered_score = []
    if len(bbox_dict) > 0:  # it gets normalized bbox
        for i in range(len(bbox_dict)):
            bbox = bbox_dict[i]['bbox']
            bbox_norm = bbox_dict[i]['bbox_normalized']
            bbox_score = bbox_dict[i]['score']
            if order == 'xxyy':
                x_min, x_max, y_min, y_max = bbox_norm[0], bbox_norm[1], bbox_norm[2], bbox_norm[3]
            elif order == 'xyxy':
                x_min, x_max, y_min, y_max = bbox_norm[0], bbox_norm[2], bbox_norm[1], bbox_norm[3]
            if bbox_score > 0:
                x_length, y_length = x_max - x_min, y_max - y_min
                if x_length * y_length < thr_fit:
                    filtered_score.append(bbox_score)
                    filtered_bbox.append(bbox)
                    filtered_bbox_norm.append(bbox_norm)
    return filtered_bbox, filtered_bbox_norm, filtered_score

def crop_resize_im(image, bbox, size, order='xxyy'):
    H, W, _ = image.shape
    if order == 'xxyy':
        roi = image[int(bbox[2] * H):int(bbox[3] * H), int(bbox[0] * W):int(bbox[1] * W), :]
    elif order == 'xyxy':
        roi = image[int(bbox[1] * H):int(bbox[3] * H), int(bbox[0] * W):int(bbox[2] * W), :]
    roi = cv2.resize(roi, size)
    return roi

def im2double(im):
    return cv2.normalize(im.astype('float'), None, 0.0, 1.0, cv2.NORM_MINMAX)

def IoU(boxA, boxB):
    # order = xyxy
    xA = max(boxA[0], boxB[0])
    yA = max(boxA[1], boxB[1])
    xB = min(boxA[2], boxB[2])
    yB = min(boxA[3], boxB[3])

    # compute the area of intersection rectangle
    interArea = max(0, xB - xA) * max(0, yB - yA)

    # compute the area of both the prediction and ground-truth
    # rectangles
    boxAArea = (boxA[2] - boxA[0]) * (boxA[3] - boxA[1])
    boxBArea = (boxB[2] - boxB[0]) * (boxB[3] - boxB[1])

    # compute the intersection over union by taking the intersection
    # area and dividing it by the sum of prediction + ground-truth
    # areas - the interesection area
    iou = interArea / float(boxAArea + boxBArea - interArea)

    # return the intersection over union value
    return iou

def img_heat_bbox_disp(image, heat_map, size, title='', en_name='', alpha=0.6, cmap='viridis', cbar='False', dot_max=True,
                       gt=[], bbox=[], order=None, show=False, filename=''):

    heat_map = (256 * heat_map).astype(np.uint8)
    thr_hit = 1  # a bbox is acceptable if hit point is in middle 85% of bbox area
    thr_fit = .60  # the biggest acceptable bbox should not exceed 60% of the image
    H, W = size
    # resize heat map
    heat_map_resized = cv2.resize(heat_map, (W, H))
    image = cv2.resize(image, (W, H))
    # heat_map_resized = heat_map
    # display
    fig = plt.figure(figsize=(15, 5))
    fig.suptitle(title, size=15)
    ax = plt.subplot(1, 3, 1)
    plt.imshow(image)
    if dot_max:
        max_loc = np.unravel_index(np.argmax(heat_map_resized, axis=None), heat_map_resized.shape)
        plt.scatter(x=max_loc[1], y=max_loc[0], edgecolor='w', linewidth=3)

    # if len(bboxes) > 0:  # it gets normalized bbox
    #     if order == None:
    #         order = 'xxyy'
    #
    #     for i in range(len(bboxes)):
    #         bbox_norm = bboxes[i]
    #         if order == 'xxyy':
    #             x_min, x_max, y_min, y_max = int(bbox_norm[0] * W), int(bbox_norm[1] * W), int(bbox_norm[2] * H), int(
    #                 bbox_norm[3] * H)
    #         elif order == 'xyxy':
    #             x_min, x_max, y_min, y_max = int(bbox_norm[0] * W), int(bbox_norm[2] * W), int(bbox_norm[1] * H), int(
    #                 bbox_norm[3] * H)
    # x_length, y_length = x_max - x_min, y_max - y_min

    # if en_name != '':
    #     ax.text(x_min + .5 * x_length, y_min + 10, en_name,
    #             verticalalignment='center', horizontalalignment='center',
    #             # transform=ax.transAxes,
    #             color='white', fontsize=15)
        # an = ax.annotate(en_name, xy=(x_min,y_min), xycoords="data", va="center", ha="center", bbox=dict(boxstyle="round", fc="w"))
        # plt.gca().add_patch(an)

    plt.imshow(heat_map_resized, alpha=alpha, cmap=cmap)

    # plt.figure(2, figsize=(6, 6))
    plt.subplot(1, 3, 2)
    plt.imshow(image)
    # box = plt.Rectangle((gt[0, 0], gt[0, 1]), gt[0, 2] - gt[0, 0], gt[0, 3] - gt[0, 1],
    #                     edgecolor='w', linewidth=3, fill=False, color='green')
    # plt.gca().add_patch(box)
    # if len(bbox) > 0:
    #     box = plt.Rectangle((bbox[0][0], bbox[0][1]), bbox[0][2] - bbox[0][0], bbox[0][3] - bbox[0][1],
    #                         edgecolor='w', linewidth=3, fill=False, color='red')
    #     plt.gca().add_patch(box)
    # plt.figure(3, figsize=(6, 6))
    plt.subplot(1, 3, 3)
    plt.imshow(heat_map_resized, cmap='jet')
    fig.tight_layout()
    fig.subplots_adjust(top=.85)

    if show:
        plt.show()
    else:
        plt.savefig(filename, bbox_inches='tight')
    plt.close()

def isCorrect(bbox_annot, bbox_pred, iou_thr=.5, size_h=224):
    for bbox_p in bbox_pred:
        bbox_p = (np.array(bbox_p) / size_h).tolist()
        for bbox_a in bbox_annot:
            if IoU(bbox_p, bbox_a) >= iou_thr:
                return 1
    return 0

def isCorrectHit(bbox_annot, heatmap, orig_img_shape):
    H, W = orig_img_shape
    heatmap_resized = cv2.resize(heatmap, (W, H))
    max_loc = np.unravel_index(np.argmax(heatmap_resized, axis=None), heatmap_resized.shape)

    # try:
    #     threshold_value = filters.threshold_minimum(heatmap_resized)
    #     labeled_foreground = (heatmap_resized > threshold_value).astype(int)
    #     properties = regionprops(labeled_foreground, heatmap_resized)
    #     center_of_mass = properties[0].centroid
    #     weighted_center_of_mass = properties[0].weighted_centroid
    #     max_loc = weighted_center_of_mass
    # except:
    #     max_loc = np.unravel_index(np.argmax(heatmap_resized, axis=None), heatmap_resized.shape)

    for bbox in bbox_annot:
        if bbox[0] <= max_loc[1] <= bbox[2] and bbox[1] <= max_loc[0] <= bbox[3]:
            return 1
    return 0

def check_percent(bboxes):
    for bbox in bboxes:
        x_length = bbox[2] - bbox[0]
        y_length = bbox[3] - bbox[1]
        if x_length * y_length < .05:
            return False
    return True

def union(bbox):
    if len(bbox) == 0:
        return []
    if type(bbox[0]) == type(0.0) or type(bbox[0]) == type(0):
        bbox = [bbox]
    maxes = np.max(bbox, axis=0)
    mins = np.min(bbox, axis=0)
    return [[mins[0], mins[1], maxes[2], maxes[3]]]

def attCorrectness(bbox_annot, heatmap, orig_img_shape):
    H, W = orig_img_shape
    heatmap_resized = cv2.resize(heatmap, (W, H))
    h_s = np.sum(heatmap_resized)
    if h_s == 0:
        return 0
    else:
        heatmap_resized /= h_s
    att_correctness = 0
    for bbox in bbox_annot:
        x0, y0, x1, y1 = bbox
        att_correctness += np.sum(heatmap_resized[y0:y1, x0:x1])
    return att_correctness

def calc_correctness(annot, heatmap, orig_img_shape):
    # bbox_dict = heat2bbox(heatmap, orig_img_shape)
    size_h = heatmap.shape[-1]
    bbox_dict = generate_bbox(heatmap)
    # bbox, bbox_norm, bbox_score = filter_bbox(bbox_dict=bbox_dict, order='xyxy')
    annot = process_gt_bbox(annot, orig_img_shape)
    bbox_norm_annot = union(annot['bbox_norm'])
    bbox_annot = annot['bbox']
    bbox_dict = union(np.array(bbox_dict)[:, :4])
    bbox_correctness = isCorrect(bbox_norm_annot, bbox_dict, iou_thr=.5, size_h=size_h)
    hit_correctness = isCorrectHit(bbox_annot, heatmap, orig_img_shape)
    # att_correctness = attCorrectness(bbox_annot, heatmap, orig_img_shape)
    # return bbox_correctness, hit_correctness, att_correctness, bbox
    # return bbox_correctness, hit_correctness, att_correctness
    return bbox_correctness, hit_correctness, 0

def process_gt_bbox(annot, orig_img_shape):
    out = {}
    h, w = orig_img_shape
    bbox = torch.tensor(annot).numpy()
    out['bbox'] = bbox.copy()
    bbox = bbox.astype(np.float)
    bbox[:, 0] = bbox[:, 0] / w
    bbox[:, 1] = bbox[:, 1] / h
    bbox[:, 2] = bbox[:, 2] / w
    bbox[:, 3] = bbox[:, 3] / h
    out['bbox_norm'] = bbox.copy()
    return out

def no_tuple(a):
    out = []
    for item in a:
        out.append(item[0])
    return out

def cluster_gt(bbox, heatmap):
    out = {}
    bbox = torch.tensor(bbox).numpy().squeeze()
    for i in range(len(bbox)):
        curr_heatmap = heatmap[i:i+1].clone()
        curr_bbox = bbox[i].copy()
        if len(out.keys()) == 0:
            out[str(len(out.keys()))] = (curr_bbox, curr_heatmap)
            continue
        flag = False
        for j, key in enumerate(out.keys()):
            old_bbox, old_heatmap = out[key]
            if IoU(curr_bbox, old_bbox) == 1:
                out[key] = (curr_bbox, torch.cat((old_heatmap, curr_heatmap), dim=0))
                flag = True
                break
        if not flag:
            out[str(len(out.keys()))] = (curr_bbox, curr_heatmap)

    for ix, key in enumerate(out.keys()):
        curr_bbox, old_heatmap = out[key]
        old_heatmap = old_heatmap.mean(dim=0).squeeze().detach().clone().cpu().numpy()
        out[key] = (np.expand_dims(curr_bbox, axis=0),
                    old_heatmap)
    return out

def intensity_to_rgb(intensity, cmap='cubehelix', normalize=False):
    assert intensity.ndim == 2, intensity.shape
    intensity = intensity.astype("float")

    if normalize:
        intensity -= intensity.min()
        intensity /= intensity.max()

    cmap = plt.get_cmap(cmap)
    intensity = cmap(intensity)[..., :3]
    return intensity.astype('float32') * 255.0

def generate_bbox(cam, threshold=0.5, nms_threshold=0.05, max_drop_th=0.5):
    heatmap = intensity_to_rgb(cam, normalize=True).astype('uint8')
    gray_heatmap = cv2.cvtColor(heatmap, cv2.COLOR_RGB2GRAY)

    thr_val = threshold * np.max(gray_heatmap)

    _, thr_gray_heatmap = cv2.threshold(gray_heatmap,
                                        int(thr_val), 255,
                                        cv2.THRESH_TOZERO)
    try:
        _, contours, _ = cv2.findContours(thr_gray_heatmap,
                                          cv2.RETR_TREE,
                                          cv2.CHAIN_APPROX_SIMPLE)
    except:
        contours, _ = cv2.findContours(thr_gray_heatmap,
                                       cv2.RETR_TREE,
                                       cv2.CHAIN_APPROX_SIMPLE)
    if len(contours) != 0:
        proposals = [cv2.boundingRect(c) for c in contours]
        # proposals = [(x, y, w, h) for (x, y, w, h) in proposals if h * w > 0.05 * 224 * 224]
        if len(proposals) > 0:
            proposals_with_conf = [thr_gray_heatmap[y:y + h, x:x + w].mean()/255 for (x, y, w, h) in proposals]
            inx = torchvision.ops.nms(torch.tensor(proposals).float(),
                                      torch.tensor(proposals_with_conf).float(),
                                      nms_threshold)
            estimated_bbox = torch.cat((torch.tensor(proposals).float()[inx],
                                        torch.tensor(proposals_with_conf)[inx].unsqueeze(dim=1)),
                                       dim=1).tolist()
            estimated_bbox = [(x, y, x+w, y+h, conf) for (x, y, w, h, conf) in estimated_bbox
                              if conf > max_drop_th * np.max(proposals_with_conf)]
        else:
            estimated_bbox = [[0, 0, 1, 1, 0], [0, 0, 1, 1, 0]]
    else:
        estimated_bbox = [[0, 0, 1, 1, 0], [0, 0, 1, 1, 0]]
    return estimated_bbox

def generate_proposals(cam, threshold=0.5):
    heatmap = intensity_to_rgb(cam, normalize=True).astype('uint8')
    gray_heatmap = cv2.cvtColor(heatmap, cv2.COLOR_RGB2GRAY)
    thr_val = threshold * np.max(gray_heatmap)
    _, gray_heatmap = cv2.threshold(gray_heatmap,
                                    int(thr_val), 255,
                                    cv2.THRESH_TOZERO)
    try:
        _, contours, _ = cv2.findContours(gray_heatmap,
                                          cv2.RETR_TREE,
                                          cv2.CHAIN_APPROX_SIMPLE)
    except:
        contours, _ = cv2.findContours(gray_heatmap,
                                       cv2.RETR_TREE,
                                       cv2.CHAIN_APPROX_SIMPLE)
    proposals = []
    for c in contours:
        if c.shape[0]<5:
            continue
        x, y, w, h = cv2.boundingRect(c)
        energy = gray_heatmap[y:y + h, x:x + w].sum() / gray_heatmap.sum()
        if energy < 1:
            proposals.append([x, y, x + w, y + h, energy])
    return proposals, gray_heatmap

def get_scores(proposals, mask):
    scores = []
    bboxes = []
    for p in proposals:
        x, y, w, h = p
        if w*h < 0.05*224*224:
            continue
        energy = (mask[y:y + h, x:x + w, :]/255/3).sum()/(w*h)
        scores.append(energy)
        bboxes.append([x, y, x+w, h+y])
    return bboxes, scores


import asyncio

from sanic import Sanic, response
from sanic.config import Config
from sanic.exceptions import RequestTimeout

Config.REQUEST_TIMEOUT = 1
app = Sanic("Example")

@app.route("/")
async def test(request):
    await asyncio.sleep(3)
    return response.text("Hello, world!")

@app.exception(RequestTimeout)
def timeout(request, exception):
    return response.text("RequestTimeout from error_handler.", 408)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)


from distutils.command.upload import upload
from email.policy import default
from pickle import TRUE
from django.db import models
from django.forms import CharField, FileField
from django.utils import timezone
from django.contrib.auth.models import User
from django_countries.fields import CountryField
from multiselectfield import MultiSelectField
from django import forms
from ckeditor.fields import RichTextField

#CHOICES
PROGRAMME_LEVEL = [
    ('1', '1'),
    ('2', '2'),
    ('3', '3'),
    ('4', '4'),
    ('5', '5'),
    ('6', '6'),
    ('7', '7'),
    ('8', '8'),
    ('9', '9'),
    ('10', '10'),
    ('11', '11'),
]
TERTIARY_AUTHORITY = [
    ('NQA', 'Namibia Qualification Authority'),
]
MODE_OF_STUDY = [
    ('Full-time', 'Full-time'),
    ('Part-time', 'Part-time'),
    ('Online', 'Online'),
]

COURSE_CATEGORY = [
    ('Shortcourse', 'Shortcourse'),
    ('Undergraduate', 'Undergraduate'),
    ('Postgraduate', 'Postgraduate'),
]

BASE_ON_LEVEL = [('Grade-11', 'Grade-11'), ('Grade-12', 'Grade-12'),
                 ('Mature-age', 'Mature age'),
                 ('Other-qualitication', 'Other Qualitication')]

STATUS_OF_APPLICATION = [
    ('In progress', 'In progress'),
    ('Pending', 'Pending'),
    ('Rejected', 'Rejected'),
    ('Approved', 'Approved'),
    ('Cancelled', 'Cancelled'),
]

GENDER = [
    ('Male', 'Male'),
    ('Female', 'Female'),
]
PERMIT_TYPE = [
    ('Study', 'Study'),
    ('Work', 'Work'),
    ('Diplomatic', 'Diplomatic'),
    ('Tourism', 'Tourism'),
]
CONDITIONAL_ANSWER = [
    ('YES', 'YES'),
    ('NO', 'NO'),
    ('MAYBE', 'MAYBE'),
]
CONDITIONAL_ANSWER_BINARY = [
    ('NO', 'NO'),
    ('YES', 'YES'),
]
TITLE = [
    ('MR', 'MR'),
    ('MS', 'MS'),
    ('MRS', 'MRS'),
    ('DR', 'DR'),
]

MARITAL_STATUS = [
    ('Single', 'Single'),
    ('Married', 'Married'),
    ('Divorsed', 'Divorsed'),
    ('Separated', 'Separated'),
    ('Widowed', 'Widowed'),
]

RELATIONSHIP_TYPE = [
    ('Parent', 'Parent'),
    ('Spouse', 'Spouse'),
    ('Guardian', 'Guardian'),
]

SPONSORSHIP_TYPE = [
    ('Self Sponsored', 'Self Sponsored'),
    ('Sponsored by a Third-party', 'Sponsored by a Third-party'),
]

NAMIBIAN_REGION = [
    ('Erongo', 'Erongo'),
    ('Hardap', 'Hardap'),
    ('Karas', 'Karas'),
    ('Khomas', 'Khomas'),
    ('Kunene', 'Kunene'),
    ('Kavango East', 'Kavango East'),
    ('Kavango West', 'Kavango West'),
    ('Otjozondjupa', 'Otjozondjupa'),
    ('Oshana', 'Oshana'),
    ('Oshikoto', 'Oshikoto'),
    ('Omusati', 'Omusati'),
    ('Zambezi', 'Zambezi'),
    ('Omaheke', 'Omaheke'),
    ('Ohangwena', 'Ohangwena'),
]

LANGUAGE = [
    ('English', 'English'),
    ('Oshiherero', 'Oshiherero'),
    ('Damara / Nama', 'Damara / Nama'),
    ('AfriKaans', 'AfriKaans'),
    ('Portuguese', 'Portuguese'),
    ('French', 'French'),
    ('Spanish', 'Spanish'),
    ('German', 'German'),
    ('Russian', 'Russian'),
    ('Chinise / Mandarine', 'Chinise / Mandarine'),
    ('Other', 'Other'),
]

#UNIVERSITY TABLES
class Faculty(models.Model):
    dean = models.ForeignKey(User,
                             on_delete=models.CASCADE,
                             blank=True,
                             null=True)
    name = models.CharField(max_length=100, blank=True, null=True)
    creation_date = models.DateTimeField(auto_now_add=True,
                                         blank=True,
                                         null=True)
    updation_date = models.DateTimeField(auto_now=True, blank=True, null=True)

    def __str__(self):
        return str(self.name)

class Programme(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    level = models.CharField(max_length=3,
                             choices=PROGRAMME_LEVEL,
                             blank=True,
                             null=True)
    authority = models.CharField(max_length=50,
                                 choices=TERTIARY_AUTHORITY,
                                 blank=True,
                                 null=True)

    def __str__(self):
        return str(self.name) + " " + str(self.authority) + " (" + str(
            self.level) + ")"

class Course(models.Model):
    faculty = models.ForeignKey(Faculty, on_delete=models.CASCADE)
    name = models.CharField(max_length=100, blank=True, null=True)
    course_code = models.CharField(max_length=10, blank=True, null=True)
    level = models.ForeignKey(Programme,
                              on_delete=models.SET_NULL,
                              max_length=100,
                              blank=True,
                              null=True)
    mode_of_study = MultiSelectField(choices=MODE_OF_STUDY,
                                     blank=True,
                                     null=True)
    tuition_fee = models.DecimalField(max_digits=10,
                                      decimal_places=2,
                                      blank=True,
                                      null=True)
    credits = models.PositiveIntegerField(blank=True, null=True)
    number_years = models.PositiveIntegerField(blank=True, null=True)
    creation_date = models.DateTimeField(auto_now_add=True,
                                         blank=True,
                                         null=True)
    updation_date = models.DateTimeField(auto_now=True, blank=True, null=True)

    def __str__(self):
        return str(self.name)

class Secondary_course(models.Model):
    course = models.OneToOneField(Course, on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.course.name}'

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

class Campus(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    campus_code = models.CharField(max_length=10, blank=True, null=True)
    contact = models.CharField(max_length=10, blank=True, null=True)
    email = models.EmailField(max_length=50, blank=True, null=True)
    country = CountryField(blank_label='(select country)', default="NA")
    town = models.CharField(max_length=50, blank=True, null=True)
    address = models.TextField(max_length=200, blank=True, null=True)

    creation_date = models.DateTimeField(auto_now_add=True,
                                         blank=True,
                                         null=True)
    updation_date = models.DateTimeField(auto_now=True, blank=True, null=True)

    def __str__(self):
        return str(self.name)

class Subject(models.Model):
    lecturer = models.ForeignKey(User,
                                 on_delete=models.SET_NULL,
                                 default="unavailable",
                                 blank=True,
                                 null=True)
    faculty = models.ForeignKey(Faculty,
                                on_delete=models.CASCADE,
                                default="unavailable",
                                blank=True,
                                null=True)
    name = models.CharField(max_length=100, blank=True, null=True)
    subject_code = models.CharField(max_length=50, blank=True, null=True)
    level = models.PositiveIntegerField(blank=True, null=True)
    credits = models.PositiveIntegerField(blank=True, null=True)
    subject_outline = models.TextField(max_length=1000, blank=True, null=True)

    def __str__(self):
        return str(self.subject_code) + " - " + str(self.name)

#APPLICATION TABLES
class Application(models.Model):
    owner = models.ForeignKey(User,
                              on_delete=models.CASCADE,
                              blank=True,
                              null=True)
    programme = models.ForeignKey(Programme,
                                  on_delete=models.SET('deleted'),
                                  blank=True,
                                  null=True)
    course_first_choice = models.ForeignKey(Course,
                                            on_delete=models.SET('deleted'),
                                            blank=True,
                                            null=True)
    course_second_choice = models.ForeignKey(Secondary_course,
                                             on_delete=models.SET('deleted'),
                                             blank=True,
                                             null=True)

    category = MultiSelectField(max_length=50,
                                choices=COURSE_CATEGORY,
                                blank=True,
                                null=True)
    prefered_campus = models.ForeignKey(Campus,
                                        on_delete=models.SET('deleted'),
                                        blank=True,
                                        null=True)
    based_on_level = models.CharField(max_length=50,
                                      choices=BASE_ON_LEVEL,
                                      blank=True,
                                      null=True)
    other_level = models.CharField(max_length=100, blank=True, null=True)
    current_step = models.SmallIntegerField(default=0, blank=True, null=True)

    prefered_period = models.CharField(
        max_length=50,
        choices=MODE_OF_STUDY,
        default='Full-time',
    )

    status = models.CharField(
        max_length=50,
        choices=STATUS_OF_APPLICATION,
        default=STATUS_OF_APPLICATION[0],
    )
    creation_date = models.DateTimeField(auto_now_add=True,
                                         blank=True,
                                         null=True)
    submition_date = models.DateTimeField(auto_now=True, blank=True, null=True)

    def __str__(self):
        return "owner: " + str(self.owner) + " | programme: " + str(
            self.category) + "   " + str(self.status)

class Profile(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    nationality = CountryField(blank_label='(select country)', default="NA")
    namibian_region = models.CharField(choices=NAMIBIAN_REGION,
                                       default=NAMIBIAN_REGION[0],
                                       max_length=50,
                                       null=True)
    title = models.CharField(
        choices=TITLE,
        default=TITLE[0],
        max_length=10,
    )
    gender = models.CharField(
        choices=GENDER,
        default=GENDER[0],
        max_length=10,
    )
    full_name = models.CharField(max_length=100, blank=True, null=True)
    surname = models.CharField(max_length=100, blank=True, null=True)

    date_of_birth = models.DateField(blank=True, null=True)
    marital_status = models.CharField(
        choices=MARITAL_STATUS,
        default=MARITAL_STATUS[0],
        max_length=10,
    )
    id_number = models.PositiveIntegerField(blank=True, null=True)
    passport_number = models.CharField(max_length=20, blank=True, null=True)
    passport_expiry_date = models.DateField(blank=True, null=True)
    permit_number = models.PositiveIntegerField(blank=True, null=True)
    permit_type = models.CharField(
        choices=PERMIT_TYPE,
        default=PERMIT_TYPE[0],
        max_length=30,
    )
    permit_expiry_date = models.DateField(blank=True, null=True)
    has_medical_condition = models.CharField(
        choices=CONDITIONAL_ANSWER_BINARY,
        default='NO',
        max_length=20,
    )
    has_medical_needs = models.CharField(
        choices=CONDITIONAL_ANSWER_BINARY,
        default='NO',
        max_length=20,
    )
    medical_condition_description = models.TextField(max_length=500,
                                                     blank=True,
                                                     null=True)

    def __str__(self):
        return str(self.application)

class Contact(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    cellphone_number_1 = models.PositiveIntegerField(blank=True, null=True)
    cellphone_number_2 = models.PositiveIntegerField(blank=True, null=True)
    telephone = models.IntegerField(blank=True, null=True)
    email = models.EmailField(max_length=50, blank=True, null=True)
    namibia_postal_address = models.CharField(max_length=15,
                                              blank=True,
                                              null=True)
    namibia_residential_address = models.TextField(max_length=100,
                                                   blank=True,
                                                   null=True)
    origin_postal_address = models.CharField(max_length=15,
                                             blank=True,
                                             null=True)
    origin_residential_address = models.TextField(max_length=100,
                                                  blank=True,
                                                  null=True)

    def __str__(self):
        return str(self.application)

class Kin(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    kin_title = models.CharField(
        choices=TITLE,
        default=TITLE[0],
        max_length=10,
    )
    first_name = models.CharField(max_length=50, blank=True, null=True)
    last_name = models.CharField(max_length=50, blank=True, null=True)
    kin_id_number = models.CharField(max_length=50, blank=True, null=True)
    relationship_type = models.CharField(
        choices=RELATIONSHIP_TYPE,
        default=RELATIONSHIP_TYPE[0],
        max_length=15,
    )
    kin_email = models.EmailField(max_length=50, blank=True, null=True)
    kin_cellphone_number = models.PositiveIntegerField(blank=True, null=True)
    kin_telephone = models.PositiveIntegerField(blank=True, null=True)

    kin_residential_address = models.TextField(max_length=100,
                                               blank=True,
                                               null=True)
    kin_postal_address = models.CharField(max_length=15, blank=True, null=True)
    kin_occupation = models.CharField(max_length=50, blank=True, null=True)
    Work_telephone = models.PositiveIntegerField(blank=True, null=True)

    def __str__(self):
        return str(self.application)

class Employer(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    employer_name = models.CharField(max_length=50, blank=True, null=True)
    occupation = models.CharField(max_length=50, blank=True, null=True)
    employer_telephone = models.PositiveIntegerField(blank=True, null=True)
    employer_email = models.EmailField(max_length=50, blank=True, null=True)
    start_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)
    duties = models.TextField(blank=True, null=True)

    def __str__(self):
        return str(self.application)

class Outstanding_result(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    has_out_standing_exam = models.CharField(
        choices=CONDITIONAL_ANSWER_BINARY,
        default='NO',
        max_length=20,
    )
    out_standing_exam = models.CharField(max_length=50, blank=True, null=True)
    out_standing_exam_date = models.DateField(blank=True, null=True)

    def __str__(self):
        return str(self.application)

class Language(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    school_language = models.CharField(
        choices=LANGUAGE,
        default=LANGUAGE[0],
        max_length=50,
    )
    home_language = models.CharField(
        choices=LANGUAGE,
        default=LANGUAGE[0],
        max_length=50,
    )
    has_english_course = models.CharField(
        choices=CONDITIONAL_ANSWER_BINARY,
        default="NO",
        max_length=20,
    )
    english_course = models.CharField(max_length=50, blank=True, null=True)
    applying_english_course = models.CharField(
        choices=CONDITIONAL_ANSWER_BINARY,
        default="NO",
        max_length=20,
    )

    def __str__(self):
        return str(self.application)

class Post_acadmic_qualification(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    has_past_qualification = models.CharField(
        choices=CONDITIONAL_ANSWER_BINARY,
        default='NO',
        max_length=20,
    )
    institution_name = models.CharField(max_length=50, blank=True, null=True)
    location = CountryField(blank_label='(select country)',
                            default="NA",
                            blank=True,
                            null=True)
    post_qualification = models.CharField(max_length=100,
                                          blank=True,
                                          null=True)
    year_start = models.PositiveBigIntegerField(blank=True, null=True)
    year_end = models.PositiveBigIntegerField(blank=True, null=True)

    def __str__(self):
        return str(self.application)

class School_leaving(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    school_name = models.CharField(max_length=100, blank=True, null=True)
    highest_grade = models.CharField(max_length=10, blank=True, null=True)
    exam_year = models.PositiveSmallIntegerField(blank=True, null=True)
    exam_authority = models.CharField(max_length=30, blank=True, null=True)

    def __str__(self):
        return str(self.application)

class School_leaving_subject(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    school = models.ForeignKey(School_leaving,
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True)
    subject_name = models.CharField(max_length=30, blank=True, null=True)
    subject_level = models.CharField(max_length=15, blank=True, null=True)
    symbol = models.CharField(max_length=1, blank=True, null=True)
    point = models.PositiveIntegerField(blank=True, null=True)

    def __str__(self):
        return str(self.application)

class Sponsor(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       default="unavailable")
    sponsor_name = models.CharField(max_length=100, blank=True, null=True)
    sponsor_signatory_name = models.CharField(max_length=100,
                                              blank=True,
                                              null=True)
    sponsorship_type = models.CharField(
        choices=SPONSORSHIP_TYPE,
        max_length=50,
        default='Self Sponsored',
    )
    sponsor_postal_address = models.CharField(max_length=30,
                                              blank=True,
                                              null=True)
    sponsor_cellphone = models.PositiveIntegerField(blank=True, null=True)
    sponsor_telephone = models.PositiveIntegerField(blank=True, null=True)
    sponsor_email = models.EmailField(max_length=50, blank=True, null=True)
    tuition_fee = models.DecimalField(max_digits=10,
                                      decimal_places=2,
                                      blank=True,
                                      null=True)
    registration_fee = models.DecimalField(max_digits=10,
                                           decimal_places=2,
                                           blank=True,
                                           null=True)
    student_fund = models.DecimalField(max_digits=10,
                                       decimal_places=2,
                                       blank=True,
                                       null=True)

    total_fee = models.DecimalField(max_digits=10,
                                    decimal_places=2,
                                    blank=True,
                                    null=True)

    def __str__(self):
        return str(self.application)

def user_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/<username>/<filename>
    return '{0}/application_documents/{1}'.format(
        instance.application.owner.username, filename)

class Document(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       blank=True,
                                       null=True)
    medical_documents = models.FileField(upload_to=user_directory_path,
                                         blank=True,
                                         null=True)
    certified_id_copy = models.FileField(upload_to=user_directory_path,
                                         blank=True,
                                         null=True)
    passport_photo = models.FileField(upload_to=user_directory_path,
                                      blank=True,
                                      null=True)
    evidence_of_payment = models.FileField(upload_to=user_directory_path,
                                           blank=True,
                                           null=True)
    foreign_qualification = models.FileField(upload_to=user_directory_path,
                                             blank=True,
                                             null=True)
    foreign_qualification_translation = models.FileField(
        upload_to=user_directory_path, blank=True, null=True)
    namibia_highest_qualification_copy = models.FileField(
        upload_to=user_directory_path, blank=True, null=True)
    other_documents = models.FileField(upload_to=user_directory_path,
                                       blank=True,
                                       null=True)

    def __str__(self):
        return str(self.application)

class TermsAndConditions(models.Model):
    application = models.OneToOneField(Application,
                                       on_delete=models.CASCADE,
                                       blank=True,
                                       null=True)
    title = models.CharField(max_length=200, blank=True, null=False)
    general_rule = RichTextField(blank=True, null=False)
    application_form_acknowledgement = models.BooleanField(default=False)

    def __str__(self):
        return str(self.application) + " - " + str(self.title)


import csv
import argparse
import os
import pickle
from array import array

# Some global variables
num_nt = 0
hb_design_dict = {}

def cli_parser(prog="convert_hb_to_nt_status.py"):
    parser = argparse.ArgumentParser(prog=prog, description="convert hb list to nt status")
    parser.add_argument('top', type=str, nargs=1, help="Topology file")
    parser.add_argument('hb_design', type=str, nargs=1, help="The designed hb list")
    parser.add_argument('hb_list', type=str, nargs=1, help="The hb list from the trajectory")
    parser.add_argument('output_file', type=str, nargs=1, help="Name of the file to save the text format output")
    parser.add_argument('-p', '--pickle', type=str, dest='pickle', nargs=1, help='Name of the file to save the pickle format output')
    return parser

def construct_hb_design(hb_design_file: str) -> dict:
    hb_design_dict = {}

    with open(hb_design_file, 'rt') as f:
        csv_read = csv.reader(f, delimiter=' ', skipinitialspace=True)
        # omit the header (the first line)
        next(csv_read)
        for line in csv_read:
            if len(line) == 2:
                # print(line)
                hb_design_dict[int(line[0])] = int(line[1])

    return hb_design_dict

def new_frame() -> list:
    global num_nt
    return [0] * num_nt

def parse_one_frame(reader: csv.reader) -> list:
    hb_frame_list = new_frame()

    for row in reader:
        if len(row) == 0:

            return hb_frame_list

        if len(row) == 2:
            first_nt = int(row[0])
            second_nt = int(row[1])
            if first_nt in hb_design_dict:
                if hb_design_dict[first_nt] == second_nt:
                    # designed to be hb, correct hb
                    hb_frame_list[first_nt] = (2, second_nt)
                    hb_frame_list[second_nt] = (2, first_nt)
                else:
                    # first nt designed to be hb, but wrong partner
                    hb_frame_list[first_nt] = -2
                    if second_nt in hb_design_dict:
                        # second nt designed to be hb, but wrong partner
                        hb_frame_list[second_nt] = -2
                    else:
                        # second nt designed to be single, but paired
                        hb_frame_list[second_nt] = -1

            else: # first nt designed to be single, but paired
                hb_frame_list[first_nt] = -1
                if second_nt in hb_design_dict:
                    # second nt designed to be hb, but wrong partner
                    hb_frame_list[second_nt] = -2
                else:
                    # second nt designed to be single, but paired
                    hb_frame_list[second_nt] = -1

    return hb_frame_list

def parse_hb_list(hb_list_file: str) -> dict:
    hb_traj_list = []

    with open(hb_list_file, 'rt') as f:
        csv_reader = csv.reader(f, delimiter=' ', skipinitialspace=True)
        for row in csv_reader:
            if row[0] == '#':
                hb_frame_list = parse_one_frame(csv_reader)

                # check for the nt that are designed to be single, and is single
                # assign 1 to them
                # for all the remaining 0, if they are in the dict, then they remain 0
                # otherwise, they should be 1
                for nt_idx, nt_status in enumerate(hb_frame_list):
                    if nt_status == 0:
                        if nt_idx not in hb_design_dict and nt_idx not in hb_design_dict.values():
                            hb_frame_list[nt_idx] = 1

                frame = int(row[2])
                hb_traj_list.append((frame, hb_frame_list))

    return hb_traj_list

def get_num_nt(top_file: str) -> int:
    with open(top_file, 'rt') as top:
        header = top.readline()

        return int(header.split()[0])

def main():
    parser = cli_parser(os.path.basename(__file__))
    args = parser.parse_args()

    top_file = args.top[0]
    hb_design = args.hb_design[0]
    hb_list = args.hb_list[0]
    output_file = args.output_file[0]

    global hb_design_dict
    hb_design_dict = construct_hb_design(hb_design)

    global num_nt
    num_nt = get_num_nt(top_file)

    hb_traj_list = parse_hb_list(hb_list)

    with open(output_file, 'wt') as out:
        for frame in hb_traj_list:
            print("t = " + str(frame[0]), file=out)
            for item in frame[1]:
                if isinstance(item, int):
                    print(item, file=out)
                else:
                    print(item[0], item[1], file=out)

    if args.pickle:
        pickle_file = args.pickle[0]
        with open(pickle_file, 'wb') as out_pickle:
            pickle.dump(hb_traj_list, file=out_pickle, protocol=pickle.HIGHEST_PROTOCOL)

if __name__ == '__main__':
    main()


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

import torch
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.nn.functional as F
from tqdm import tqdm

import higher
from time import ctime
from torch.utils.tensorboard import SummaryWriter
import my_utils as ut
import my_models as md
from my_utils import DatasetWithMetaCelebA, DatasetWithMeta
import fair_algs as fair
import options
torch.backends.cudnn.enabled = True
torch.backends.cudnn.benchmark = True
import warnings
warnings.filterwarnings("ignore")

args = options.args_parser()
args.bilevel=1
f_name = (
        f"{ctime()}_bilevel_data:{args.data}_Tout:{args.T_out}_Tin:{args.T_in}_"
        f"trBS:{args.tr_bs}_demBS:{args.dem_bs}_innerwd:{args.inner_wd}_"
        f"outerwd:{args.outer_wd}_equalDist:{args.equal_dist}_demLabeled:{args.use_dem_labeled}_"
        f"demRatio:{args.dem_ratio}_labelNoise:{args.label_noise}"
        )
writer = SummaryWriter(f'logs/{f_name}')

# datasets
tr_ds, v_ds, te_ds = ut.get_data(args.data)
tr_dem_ds, tr_ds = ut.get_dem_data(tr_ds, dem_size=0, dem_ratio=args.dem_ratio, equal_dist=args.equal_dist)
print(len(tr_dem_ds), ut.get_ds_stats(tr_dem_ds))
if args.label_noise:
    tr_ds = ut.add_random_noise_to_labels(tr_ds, noise_ratio=args.label_noise)
if args.dem_noise:
    tr_ds = ut.add_random_noise_to_dems(tr_ds, noise_ratio=args.dem_noise)

# join dem_ds, tr_ds to tr_dsAS
tr_ds.inputs = torch.cat((tr_ds.inputs, tr_dem_ds.inputs))
tr_ds.metas = torch.cat((tr_ds.metas, tr_dem_ds.metas))
tr_ds.labels = torch.cat((tr_ds.labels, tr_dem_ds.labels))

# dataloaders
tr_loader = DataLoader(tr_ds, args.tr_bs, shuffle=True, pin_memory=True, num_workers=args.num_workers,\
                       persistent_workers=False)
v_loader = DataLoader(v_ds, args.tr_bs, shuffle=True, pin_memory=True, num_workers=args.num_workers,\
                      persistent_workers=False)
te_loader = DataLoader(te_ds, args.tr_bs, shuffle=False, pin_memory=True, num_workers=args.num_workers)
dem_loader = DataLoader(tr_dem_ds, args.dem_bs, shuffle=True, pin_memory=True, num_workers=args.num_workers,\
                           persistent_workers=False)

dem_generator = ut.inf_dataloader(dem_loader)
tr_generator = ut.inf_dataloader(tr_loader)

model = md.get_model(args.data, input_size=tr_ds.inputs.shape[1]).to(args.device)
opt = torch.optim.Adam(model.parameters(), weight_decay=args.inner_wd)
es = ut.EarlyStopping(patience=args.es_tol, verbose=True, path=f'../models/{f_name}.pt')

w = torch.rand((len(tr_ds)), 1, requires_grad=False, device=args.device)
#w /= torch.norm(w, p=1)
#w.clip_(min=0)
w.requires_grad=True
opt_weights = torch.optim.Adam([w], weight_decay=args.outer_wd)

tr_loss_sum = 0
for t_out in tqdm(range(args.T_out)):
    with higher.innerloop_ctx(model, opt) as (fmodel, diffopt):
        # inner optimization
        for t_in in range(args.T_in):
            if args.use_dem_labeled:
                _, (tr_didx, tr_inp, tr_lbl, _) = next(dem_generator)
            else:
                _, (tr_didx, tr_inp, tr_lbl, _) = next(tr_generator)
            tr_inp, tr_lbl = tr_inp.to(args.device, non_blocking=True),\
                        tr_lbl.to(args.device, non_blocking=True).unsqueeze(1),\

            tr_out = fmodel(tr_inp)
            tr_loss = F.binary_cross_entropy_with_logits(tr_out, tr_lbl, reduction = 'none')
            tr_loss_sum += tr_loss.mean().item()
            tr_loss *= w[tr_didx]
            diffopt.step(tr_loss.mean())

        # outer optimization
        _, (_, dem_inp, dem_lbl, dem_meta) = next(dem_generator)
        dem_inp, dem_lbl, dem_meta = dem_inp.to(args.device, non_blocking=True),\
                        dem_lbl.to(args.device, non_blocking=True).unsqueeze(1),\
                        dem_meta.to(args.device, non_blocking=True).unsqueeze(1)

        dem_out = fmodel(dem_inp)
        dem_util_loss = F.binary_cross_entropy_with_logits(dem_out, dem_lbl, reduction='none')
        dem_fair_loss = ut.get_fairness_loss(dem_out, dem_lbl, dem_meta, loss=dem_util_loss)
        dem_total_loss = dem_fair_loss + args.util_lambda*dem_util_loss.mean()

        opt_weights.zero_grad()
        w.grad = torch.autograd.grad(dem_total_loss, w)[0]
        opt_weights.step()
        with torch.no_grad():
            #w /= torch.norm(w, p=1)
            #w.clip_(min=0)
            model.load_state_dict(fmodel.state_dict())

    if (t_out+1) % (len(tr_loader)*args.chkpt) == 0:
        with torch.no_grad():
            ep = t_out // len(tr_loader)
            model.eval()
            tr_loss_sum /= (len(tr_loader)*args.chkpt*args.T_in)
            _, v_metrics  = ut.infer(model, v_loader, args.device, threshold=0.5)
            _, dem_metrics  = ut.infer(model, dem_loader, args.device, threshold=0.5)
            ut.log_tensorboard(v_metrics, writer, ep, typ='Val')
            ut.log_tensorboard(dem_metrics, writer, ep, typ='Dem')
            writer.add_scalar(f'Loss/Train/Loss',  tr_loss_sum, ep)

            if ep > 15:
                es(v_metrics['loss'], model)
                if es.early_stop:
                    print("Early stopping")
                    break
            model.train()
            tr_loss_sum = 0

# post-training inference
with torch.no_grad():
    model.eval()
    v_threshold, v_metrics = ut.infer(model, v_loader, args.device, threshold=None)
    ut.log_tensorboard(v_metrics, writer, 0, typ='Val_Final')

    _, te_metrics = ut.infer(model, te_loader, args.device, threshold=v_threshold)
    ut.log_tensorboard(te_metrics, writer, 0, typ='Test', print_extra=False)
    writer.flush()
    writer.close()
    print(v_metrics, te_metrics)


import csv
import sys
import requests

# rain data from .
# https://coastwatch.pfeg.noaa.gov/erddap/griddap/chirps20GlobalPentadP05.html
# used dataset:
# https://coastwatch.pfeg.noaa.gov/erddap/griddap/chirps20GlobalPentadP05.csv?precip%5B(2021-8-01T00:00:00Z):1:(2021-11-26T00:00:00Z)%5D%5B(30.0):.25:(42.0)%5D%5B(-123.0):.25:(-113.0)%5D
# note eben: The url above had an invalid parameter, had to set stride from 0.25 to 1
# https://coastwatch.pfeg.noaa.gov/erddap/griddap/chirps20GlobalPentadP05.csv?precip%5B(2021-8-01T00:00:00Z):1:(2021-11-26T00:00:00Z)%5D%5B(30.0):1:(42.0)%5D%5B(-123.0):1:(-113.0)%5D

def load_rain_data(filename=None) -> list:
    """
    Load precipitation data from file.
    :param filename: The path to the CSV file containing precipitation data.
    :return: The contents of filename as a list.
    :raises: FileNotFoundError
    """
    from pathlib import Path
    filename = filename or Path(__file__).parent.joinpath('data/chirps20GlobalPentadP05_1da0_1624_398c.csv').resolve()
    with open(filename) as file:
        csv_reader = csv.reader(file, delimiter=",")
        line_count = 0
        rows = list()
        for row in csv_reader:
            line_count += 1
            if line_count <= 2:
                continue
            elif line_count >= 10e10:
                break
            rows.append(row)
        return rows

def get_lat_lon(city_name: str) -> tuple:
    """
    Get the longitude and latitude of a city.
    :param city_name: The name of the city.
    :return: The longitude and latitude of the city as a two-tuple.
    :raises: ValueError, requests.exceptions.HTTPError, requests.exceptions.RequestException
    """
    query = {'city': city_name, 'format': 'jsonv2', 'namedetails': 0, 'addressdetails': 0, 'limit': 1}
    response = requests.get("https://nominatim.openstreetmap.org/search.php", query)
    response.raise_for_status()
    city_data = response.json()

    if len(city_data) == 0:
        raise ValueError(f"{city_name} doesn't appear to be a valid city.")

    try:
        lat = float(city_data[0]["lat"])
        lon = float(city_data[0]["lon"])
    except (KeyError, ValueError):
        raise RuntimeError('Retrieved invalid city data from web service.')

    return lat, lon

def filter_rainy_days(location: tuple, data: list, dist_thresh=0.05, rain_thresh=8.0) -> list:
    """
    Filter data to just those periods where there was precipitation.
    :param location: The longitude and latitude where you want to conduct your search.
    :param data: Parsed precipitation data.
    :param dist_thresh: Search radius.
    :param rain_thresh: Minimum precipitation threshold.
    :return: List containing just those periods where there was precipitation.
    """
    assert len(location) == 2

    rainy_days = list()
    for row in data:
        t, lat, lon, rain = row
        if rain != "NaN" and float(rain) >= rain_thresh:
            lat_diff = abs(float(lat) - location[0])
            lon_diff = abs(float(lon) - location[1])
            if lat_diff < dist_thresh and lon_diff < dist_thresh:
                rainy_days.append((t[:10], rain))
    return rainy_days

if __name__ == '__main__':
    sys.tracebacklimit = 0

    try:
        rain_data = load_rain_data()
    except FileNotFoundError:
        raise SystemExit('Rain data file not found.')

    city = str(input("Enter city name:[San Jose]") or "San Jose")

    try:
        city_lat_lon = get_lat_lon(city)
    except (ValueError, requests.exceptions.HTTPError) as e:
        raise SystemExit(e)
    except requests.exceptions.RequestException:
        raise SystemExit('Network error.')

    filtered_rain_data = filter_rainy_days(city_lat_lon, rain_data)

    for date, val in filtered_rain_data:
        print(f'PERIOD STARTING: {date}, PRECIPITATION: {val} mm/(5days)')

    print(f'Number of 5-days periods with precipitation: {len(filtered_rain_data)}')


import argparse
import cv2
import torchvision.transforms as transforms
import torch

from PIL import Image

from models.vgg16 import vgg16
from models.tiny_yolo import tinyYolo
from communication import serverCommunication

WINDOW_NAME = 'CameraDemo'

def parse_args():
    # Parse input arguments
    desc = 'ANS in edge server side'
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('--dnn', dest='dnn_model',
                        help='vgg, yolo',
                        default='yolo', type=str)
    parser.add_argument('--host', dest='host',
                        help='Ip address',
                        default='192.168.1.72', type=str)
    parser.add_argument('--port', dest='port',
                        help='Ip port',
                        default=8080, type=int)
    args = parser.parse_args()
    return args

if __name__ == '__main__':
    args = parse_args()
    print('Called with args:')
    print(args)
    print('OpenCV version: {}'.format(cv2.__version__))

    if args.dnn_model == 'vgg':
        model = vgg16()
        model.eval()
    else:
        model = tinyYolo()
        model.eval()

    model.cuda()

    communication = serverCommunication(args.host, args.port)

    while True:
        try:
            conn, addr = communication.accept_conn()
            with conn:
                recv_data = communication.receive_msg(conn)
                print('receive data from mobile device !!!')
                partition_point = recv_data[0]
                data = recv_data[1]
                data = torch.autograd.Variable(data)
                prediction = model(data.cuda(), server=True, partition=partition_point)
                res = prediction.data

                msg = communication.send_msg(conn, res)

        except KeyboardInterrupt or TypeError or OSError:
            communication.close_channel()