from tensorpack.tfutils.summary import add_moving_summary
from tensorpack import *
from tensorpack.tfutils.gradproc import MapGradient, SummaryGradient
from tensorpack.tfutils import (
    get_current_tower_context, optimizer)
from tensorpack.utils.gpu import get_nr_gpu
import tensorflow.contrib.slim as slim
import tensorflow.contrib.rnn as rnn
import sys
import os
import multiprocessing
import tensorpack.dataflow
import tensorflow as tf
import numpy as np
import gym
import cv2
import tensorflow.contrib.rnn as rnn
import VAE

STEPS_PER_EPOCH = 100
BATCH_SIZE = 8
ACTION_DIM = 3
Z_DIM = 32
SEQ_LEN = 20
MIX_GAUSSIANS = 5

class RNNDataflow(RNGDataFlow, Callback):
    def __init__(self, env):
        self.env = env
        # self.pred = OnlinePredictor(PredictConfig(
        #     model=FusedModel(),
        #     session_init=get_model_loader('train_log/auto_encoder/checkpoint'),
        #     input_names=['state_in'],
        #     output_names=['AutoEncoder/encoding']
        # ))

    def _setup_graph(self):
        # op = self.graph.get_operations()
        # print([m.values() for m in op])
        self.pred = self.trainer.get_predictor(
            ['state_in'], ['AutoEncoder/encoding'])
        # OnlinePredictor(['state_in:0'], ['tower0/AutoEncoder/output:0'])

    def get_data(self):
        while True:
            episode_z_buffer = []
            episode_a_buffer = []
            self.env.reset()
            # observation = self.env.state
            # img = cv2.resize(observation, (64, 64))
            # img = img.astype(np.float32) / 255.
            # episode_z_buffer.append(self.pred([img[None, :, :, :]])[0][0])
            while True:
                action = self.env.action_space.sample()
                observation, reward, done, info = self.env.step(action)
                img = cv2.resize(observation, (64, 64))
                img = img.astype(np.float32) / 255.

                if self.env.env.t < 1.:
                    continue

                episode_a_buffer.append(action)
                episode_z_buffer.append(self.pred([img[None, :, :, :]])[0][0])

                if done:
                    episode_a_buffer.pop(0)
                    episode_a = np.asarray(episode_a_buffer, dtype=np.float32)
                    episode_z = np.asarray(episode_z_buffer, dtype=np.float32)
                    for i in range(len(episode_a_buffer) // SEQ_LEN + 1):
                        sample_idx = np.random.randint(len(episode_a_buffer), size=SEQ_LEN)
                        # print(len(episode_a_buffer))
                        yield [np.zeros([64, 64, 3], dtype=np.float32),
                                episode_a[sample_idx],
                                episode_z[sample_idx],
                                episode_z[sample_idx + 1]]
                    break

class Model(ModelDesc):
    def inputs(self):
        return [tf.placeholder(tf.float32, [None, SEQ_LEN, ACTION_DIM], 'action_input'),
                tf.placeholder(tf.float32, [None, SEQ_LEN, Z_DIM], 'z_input'),
                tf.placeholder(tf.float32, [None, SEQ_LEN, Z_DIM], 'z_target')]

    def build_graph(self, action, z_in, z_target):
        scope = 'MDN-RNN'
        with tf.variable_scope(scope):
            hidden_dim = 256
            cell = rnn.BasicLSTMCell(hidden_dim)
            init_state = rnn.LSTMStateTuple(tf.placeholder_with_default(tf.zeros(tf.stack([tf.shape(action)[0], hidden_dim]), name='cz'),
                                                     shape=[None, hidden_dim], name='c'),
                                            tf.placeholder_with_default(
                                                tf.zeros(tf.stack([tf.shape(action)[0], hidden_dim]), name='hz'),
                                                shape=[None, hidden_dim], name='h'))
            x = tf.concat([slim.fully_connected(action, 32), z_in], axis=-1)
            x_list = tf.unstack(x, axis=1)

            outputs, last_state = rnn.static_rnn(cell, x_list, init_state)
            last_state = tf.identity('last_state')

            # is_training = get_current_tower_context().is_training
            # if not is_training:
            #     return

            # B * S * H
            outputs = tf.stack(outputs, axis=1)
            # outputs = tf.Print(outputs, [tf.shape(outputs)], summarize=10)
            # elements in in z are independent mix-gaussians
            dense = slim.fully_connected(tf.reshape(outputs, [-1, hidden_dim]), 3 * Z_DIM * MIX_GAUSSIANS, activation_fn=None)
            mean = tf.reshape(dense[:, :Z_DIM * MIX_GAUSSIANS], [-1, MIX_GAUSSIANS, Z_DIM])
            sigma = tf.reshape(tf.exp(dense[:, Z_DIM * MIX_GAUSSIANS:2*Z_DIM * MIX_GAUSSIANS]), [-1, MIX_GAUSSIANS, Z_DIM])
            pi = tf.nn.softmax(tf.reshape(dense[:, -Z_DIM * MIX_GAUSSIANS:], [-1, MIX_GAUSSIANS, Z_DIM]), axis=1)

            # sample from mixture of gaussian
            z = tf.reshape(tf.tile(z_target, [1, 1, MIX_GAUSSIANS]), [-1, MIX_GAUSSIANS, Z_DIM])
            # z = tf.Print(z, [tf.shape(z), tf.shape(mean)], summarize=10)
            # a const positive scalar (2pi)^(-D/2) is omitted
            probs = pi * tf.exp(-tf.square(z - mean) / (2 * tf.square(sigma) + 1e-8)) / (sigma + 1e-8)

            # (B * S) * Z
            probs = tf.reduce_sum(probs, axis=1)

        loss = tf.reduce_sum(-tf.log(probs), name='loss')
        add_moving_summary(loss)

        return loss

    def optimizer(self):
        lr = tf.get_variable('learning_rate', initializer=1e-4, trainable=False)
        opt = tf.train.AdamOptimizer(lr)
        gradprocs = [MapGradient(lambda grad: tf.clip_by_average_norm(grad, 0.3))]
        # SummaryGradient()]
        opt = optimizer.apply_grad_processors(opt, gradprocs)
        return opt

class FusedModel(ModelDesc):
    def __init__(self):
        self.mdn_rnn_model = Model()
        self.vae_model = VAE.Model()

    def inputs(self):
        return self.vae_model.inputs() + self.mdn_rnn_model.inputs()

    def build_graph(self, img, action, z_in, z_target):
        self.vae_model.build_graph(img)
        return self.mdn_rnn_model.build_graph(action, z_in, z_target)

    def optimizer(self):
        return self.mdn_rnn_model.optimizer()

def train():
    dirname = os.path.join('train_log', 'mdn-rnn')
    logger.set_logger_dir(dirname)

    # assign GPUs for training & inference
    nr_gpu = get_nr_gpu()
    if nr_gpu > 0:
        train_tower = list(range(nr_gpu)) or [0]
        logger.info("[Batch-SL] Train on gpu {}".format(
            ','.join(map(str, train_tower))))
    else:
        logger.warn("Without GPU this model will never learn! CPU is only useful for debug.")
        train_tower = [0], [0]

    ds = RNNDataflow(gym.make('CarRacing-v0'))
    # if os.name == 'nt':
    #     dataflow = PrefetchData(ds, nr_proc=multiprocessing.cpu_count() // 2,
    #                             nr_prefetch=multiprocessing.cpu_count() // 2)
    # else:
    #     dataflow = PrefetchDataZMQ(ds, nr_proc=multiprocessing.cpu_count() // 2)
    dataflow = BatchData(ds, BATCH_SIZE)
    config = TrainConfig(
        model=FusedModel(),
        dataflow=dataflow,
        callbacks=[
            ModelSaver(),
            EstimatedTimeLeft(),
            ds,
            # ScheduledHyperParamSetter('learning_rate', [(20, 0.0003), (120, 0.0001)]),
            # ScheduledHyperParamSetter('entropy_beta', [(80, 0.005)]),
            # HumanHyperParamSetter('learning_rate'),
        ],
        session_init=get_model_loader('train_log/auto_encoder/checkpoint'),
        steps_per_epoch=STEPS_PER_EPOCH,
        max_epoch=100,
    )
    trainer = AsyncMultiGPUTrainer(train_tower) if nr_gpu > 1 else SimpleTrainer()
    launch_train_with_config(config, trainer)

if __name__ == '__main__':
    train()


import torch

class FFNetwork(torch.nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes, **kwargs):
        torch.nn.Module.__init__(self)

        self.input_size = input_size
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.num_classes = num_classes

        self.add_module("input", torch.nn.Linear(input_size, hidden_size))
        self.add_module("activation_input", torch.nn.Sigmoid())
        for i in range(0, num_layers):
            self.add_module("l"+str(i), torch.nn.Linear(hidden_size, hidden_size))
            self.add_module("a"+str(i), torch.nn.Sigmoid())
        self.add_module("output", torch.nn.Linear(hidden_size, num_classes))
        self.add_module("activation_output", torch.nn.Sigmoid())

    def forward(self, input):
        for module in self._modules.values():
            input = module(input)
        return input

    def forward_batch(self, batch_data):
        batch_out = self(batch_data.view(-1, batch_data.shape[1] * batch_data.shape[2]).type(torch.float32))
        return batch_out

    def evaluate_batch(self, batch_data, batch_target):
        out = self(batch_data.view(-1, batch_data.shape[1] * batch_data.shape[2]).type(torch.float32))
        return (out.max(1)[1] == (batch_target.to(batch_data.device))).sum().item()


import numpy as np

import settings
import evaluate.evaluate_main as ev
import utils.convert_pose as cp

def test_evaluate_pose():
    pose_pred0 = np.array([[1, 2, 3, 0, 0, 1.], [4, 5, 6, 0, 0, 1.5], [1, 2, 3, 0, 0, 1.], [4, 5, 6, 0, 0, 1.5]])
    pose_true = pose_pred0.copy()

    # scaling trajectory does not affect error
    pose_pred1 = pose_pred0.copy()
    pose_pred1[:, :3] = pose_pred1[:, :3] * 2
    print("predicted_pose\n", pose_pred1)
    pose_true = cp.pose_rvec2matr(pose_true)
    trj_err, rot_err = ev.evaluate_pose(pose_pred1, pose_true)
    print("trajectory error\n", trj_err)
    assert np.isclose(trj_err, 0).all()

    # change orientations
    pose_pred2 = pose_pred0.copy()
    rotation = np.array([0, -1, 1, 2])
    pose_pred2[:, 5] = pose_pred2[:, 5] + rotation
    print("predicted_pose\n", pose_pred2)
    trj_err, rot_err = ev.evaluate_pose(pose_pred2, pose_true)
    print("rotational error\n", rot_err)
    assert np.isclose(rot_err[1:], np.abs(rotation[[1, 0, 2, 3]])).all()

    # change orientation of origin
    pose_pred3 = pose_pred0.copy()
    rotation = np.array([1, 0, 0, 0])
    pose_pred3[:, 5] = pose_pred3[:, 5] + rotation
    print("predicted_pose\n", pose_pred3)
    trj_err, rot_err = ev.evaluate_pose(pose_pred3, pose_true)
    print("rotational error\n", rot_err)
    assert np.isclose(rot_err[1:], np.abs(rotation[0])).all()

    print("!!! test_evaluate_pose passed")

if __name__ == "__main__":
    np.set_printoptions(precision=3, suppress=True, linewidth=100)
    test_evaluate_pose()


# Import re library to cleaning text
import re

# Forming alphabet to converting words. Alphabet have double size because we want add delta in "z" literal
alphabet = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"

def to_decrypt(cryptotext, delta):

    print(cryptotext)

    text_clean = re.findall(r'[a-zA-Z ]', cryptotext)
    text_clean = "".join(text_clean)

    print(text_clean)

    # Erse cryptotext for new encrypted sentences
    cryptotext = ""

    for let in text_clean:
        if let == " ":
            cryptotext += " "
            continue
        else:
            for idx, val in enumerate(alphabet):
                if let == val:
                    cryptotext += alphabet[idx+delta]
                    break
    print(cryptotext)
    return cryptotext

if __name__ == '__main__':
    # print("Example:")
    # print(to_decrypt('abc', 10))

    #These "asserts" using only for self-checking and not necessary for auto-testing
    assert to_decrypt("!d! [e] &f*", -3) == "a b c"
    assert to_decrypt("x^$# y&*( (z):-)", 3) == "a b c"
    assert to_decrypt("iycfbu!@# junj%&", -16) == "simple text"
    assert to_decrypt("*$#%swzybdkxd !)(^#%dohd", -10) == "important text"
    assert to_decrypt("fgngr **&&frperg^__^", 13) == "state secret"
    print("Coding complete? Click 'Check' to earn cool rewards!")


#!/usr/bin/python

# Plot the number of transcripts against expression value, use counts matrix as input

import os
import getopt
import sys
import shlex
import numpy as np
from subprocess import call, Popen, PIPE
import matplotlib.pyplot as plt

def usage():
	print("Usage:")
	print("	python plot_transcripts_filtering.py -i [isoforms.matrix] -r [start,stop,step] -o [outDir]\n")
	print("Input:")
	print("	-i / --matrix file containing the counts matrix (isoforms or genes)")
	print("	-r / --range for filtering range (format: start,stop,step) (default:0,6,0.5)")
	print("output:")
	print("	-o / --outputDir for output directory (default: current directory)")
	print("	-n / --noplot to skip the plot generation")
	print("")
	print("-h / --help for help")
	print("-v / --verbose to activate verbose mode")

# Default values
outDir = "./"
matrix = None
start = 0
stop = 6
step = 0.5
verbose = False
noplot = False

################################## GET OPTS ##################################################
try:
    opts, args = getopt.getopt(sys.argv[1:], "hi:r:o:vn", ["help", "matrix=", "range=", "outputDir=", "verbose", "noplot"])
except getopt.GetoptError as err:
	# will print something like "option -a not recognized"
    print(str(err))
	# print help information and exit:
    usage()
    sys.exit(2)

for o, a in opts:
	if o in ("-i", "--matrix"):
		matrix = a
	elif o in ("-r", "--range"):
		start,stop,step = a.split(",")
		start = float(start)
		stop = float(stop)
		step = float(step)
	elif o in ("-o", "--outputDir"):
		outDir = a
	elif o in ("-h", "--help"):
		usage()
		sys.exit()
	elif o in ("-v", "--verbose"):
		verbose = True
	elif o in ("-n", "--noplot"):
		noplot = True
	else:
		assert False, "unhandled option"

# Check Input
if(matrix == None):
	print("Please provide a count matrix as input (option -i / --matrix)\n")
	usage()
	sys.exit()

if(outDir == None):
	print("Please provide output directory (option -o / --outputDir)\n")
	usage()
	sys.exit()

if not(isinstance(start,(int, float))):
	print("Check your range, 'start' is not an int or float !\n")
	sys.exit()

if not(isinstance(stop, (int, float))):
	print("Check your range, 'stop' is not an int or float !\n")
	sys.exit()

if not(isinstance(step, (int, float))):
	print("Check your range, 'step' is not an int or float !\n")
	sys.exit()

if not(os.path.isdir(outDir)):
	print(str(outDir)+" is not a directory !\n")
	sys.exit()

if not(os.path.exists(matrix)):
	print(str(matrix)+" does not exists !\n")
	sys.exit()

################################## PLOT ########################################################
thresholds = list()
nbIsoforms = list()

# We need to create the plot now to add the text as we go along the filtering in the loop below
if(noplot == False):
	plt.figure(figsize=(20,10))

if(verbose == True):
	print(matrix)

#For each TPM thresholds in 'range'
for tpmThreshold in np.arange(start, stop+step, step):
	if(verbose == True):
		print("Current Threshold: " + str(tpmThreshold))

	# First, remove header line from the matrix
	cmd1 = "tail -n +2 " + str(matrix)
	p1 = Popen(shlex.split(cmd1), shell=False, stdout=PIPE)

	# Then keep the line only if max_expressed(Transcript) > current_threshold
	cmd2 = "awk \'{max=$2; for(i=2;i<=NF;i++) if($i>max) max=$i; if(max >= " + str(tpmThreshold) + ") {print max};}\'"
	p2 = Popen(shlex.split(cmd2), shell=False, stdin=p1.stdout, stdout=PIPE)

	# Finally get the number of transcript for the result
	cmd3 = "wc -l"
	result = Popen(shlex.split(cmd3), shell=False, stdin=p2.stdout, stdout=PIPE).communicate()[0]
	# Popen is outputing bytes, so we use "decode()" to change it to string
	result = result.decode()

	# 'thresholds' and 'nbIsoforms' works in parallel: thresholds[i] corresponds to nbIsoforms[i]
	thresholds.append(tpmThreshold)
	nbIsoforms.append(result)

	#Plot coordinates in the plot next to the dots
	strResult = str(result).replace("\n", "")

	if(noplot == False):
		plt.text(tpmThreshold, result, "("+strResult+")")

	if(verbose == True):
		print("Number of transcripts: " + strResult + "\n")

# Saving output as txt file
textOutputFile = outDir + "/Nb_transcripts_"+ os.path.basename(matrix)+".txt"

if(verbose == True):
		print("Saving txt output in:" + textOutputFile + "\n")

index = 0
with open(textOutputFile, "w") as outTxtFile:
	outTxtFile.write("Threshold\tNumber_Isoforms_Left\n")
	while index < len(thresholds):
		outTxtFile.write(str(thresholds[index])+"\t"+str(nbIsoforms[index]))
		index = index + 1

# If noplot NOT activated, we plot the figure
if(noplot == False):
	# Print the plot using the lists created in the previous for loop
	plt.scatter(thresholds, nbIsoforms, color='dodgerblue', s=40)
	plt.xlabel('Expression level')
	plt.ylabel('Number of isoforms > expression')
	plt.xlim(start, stop+1)
	plt.title(os.path.basename(matrix))

	# Saving graph
	graphFile = outDir + "/Nb_transcripts_"+ os.path.basename(matrix)+".png"
	if(verbose == True):
		print("Saving graph :" + graphFile + "\n")
	plt.savefig(graphFile, bbox_inches='tight')


# -*- coding: utf-8 -*-
from cv2 import *
import numpy as np

def main():
	filename=['c1-0.jpg','c1-1.jpg','c1-2.jpg','c1-3.jpg','c2-0.jpg','c2-1.jpg','c2-2.jpg','c2-3.jpg']
	for i in range(0,8):
		name=filename[i]
		print(name)
		img=imread(name)
		out=cvtColor(img,COLOR_RGB2GRAY)
		R=4
		r=1
		fac=10
		fac_R=1
		fac_r=fac
		out=eye(out,R,r,-fac_R,fac_r)
		vis,out=apply_canny(out,img)
		out,draw=apply_contours(out,img)
		imwrite('e'+name,out)
		imwrite('d'+name,draw)
		#显示效果
		height,width=out.shape[:2]
		res=resize(out,(width/4,height/4))
		imshow('out',res)
		res=resize(draw,(width/6,height/6))
		imshow('draw',res)
		res=resize(vis,(width/6,height/6))
		imshow('vis',res)
		waitKey(0)

def apply_canny(gray,img):
	thrs1=3500
	thrs2=3200
	edge=Canny(gray,thrs1,thrs2,apertureSize=5)
	vis=img.copy()
	vis=np.uint8(vis/2.)
	vis[edge!=0]=(0,255,0)
	return (vis,edge)

def apply_contours(gray,img):
	_,Contours,_=findContours(gray,RETR_TREE,CHAIN_APPROX_NONE)
	drawing=np.zeros(img.shape)
	mu=[]
	mc=[]
	mx=0
	my=0
	s=0.0
	count=0
	n=0
	for c in Contours:
		count+=1
		M=moments(c)
		if M['m00']!=0:
			mc=[int(M['m10']/M['m00']),int(M['m01']/M['m00'])]
			if (M["m00"]>70 and M["m00"]<1000):
				n+=1
				contours_poly=approxPolyDP(c,3,True)
				drawContours(drawing,c,-1,(255,255,255),1,8)
				drawContours(img,c,-1,(0,255,0),1,8)
	print(n)
	return (img,drawing)

def eye(img,R,r,fac_R,fac_r):
	x,y=np.meshgrid(np.linspace(1,R*2+1,R*2+1),np.linspace(1,R*2+1,R*2+1))
	dis=np.sqrt(np.multiply((x-(R+1)),(x-(R+1)))+np.multiply((y-(R+1)),(y-(R+1))))
	flag1=(dis<=r)
	flag2=(np.logical_and(dis>r,dis<=R))
	kernal=flag1*fac_r+flag2*fac_R
	#在python2.7中要加入float()
	kernal=kernal/float(kernal.sum())

	out=filter2D(img,-1,kernal)
	return out

if __name__=='__main__':
	main()


import functools
import logging

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
from torch.cuda.amp import autocast, GradScaler

from codebase.torchutils.distributed import world_size
from codebase.torchutils.metrics import AccuracyMetric, AverageMetric, EstimatedTimeArrival
from codebase.torchutils.common import GradientAccumulator
from codebase.torchutils.common import ThroughputTester, time_enumerate

_logger = logging.getLogger(__name__)

scaler = None

def _run_one_epoch(is_training: bool,
                   epoch: int,
                   model: nn.Module,
                   loader: data.DataLoader,
                   criterion: nn.modules.loss._Loss,
                   optimizer: optim.Optimizer,
                   scheduler: optim.lr_scheduler._LRScheduler,
                   use_amp: bool,
                   accmulated_steps: int,
                   device: str,
                   memory_format: str,
                   log_interval: int):
    phase = "train" if is_training else "eval"
    model.train(mode=is_training)

    global scaler
    if scaler is None:
        scaler = GradScaler(enabled=use_amp and is_training)

    gradident_accumulator = GradientAccumulator(steps=accmulated_steps, enabled=is_training)

    time_cost_metric = AverageMetric("time_cost")
    loss_metric = AverageMetric("loss")
    accuracy_metric = AccuracyMetric(topk=(1, 5))
    eta = EstimatedTimeArrival(len(loader))
    speed_tester = ThroughputTester()

    if is_training and scheduler is not None:
        scheduler.step(epoch)

    lr = optimizer.param_groups[0]['lr']
    _logger.info(f"{phase.upper()} start, epoch={epoch:04d}, lr={lr:.6f}")

    for time_cost, iter_, (inputs, targets) in time_enumerate(loader, start=1):
        inputs = inputs.to(device=device, non_blocking=True, memory_format=memory_format)
        targets = targets.to(device=device, non_blocking=True)

        with torch.set_grad_enabled(mode=is_training):
            with autocast(enabled=use_amp and is_training):
                outputs = model(inputs)
                loss: torch.Tensor = criterion(outputs, targets)

        gradident_accumulator.backward_step(model, loss, optimizer, scaler)

        time_cost_metric.update(time_cost)
        loss_metric.update(loss)
        accuracy_metric.update(outputs, targets)
        eta.step()
        speed_tester.update(inputs)

        if iter_ % log_interval == 0 or iter_ == len(loader):
            _logger.info(", ".join([
                phase.upper(),
                f"epoch={epoch:04d}",
                f"iter={iter_:05d}/{len(loader):05d}",
                f"fetch data time cost={time_cost_metric.compute()*1000:.2f}ms",
                f"fps={speed_tester.compute()*world_size():.0f} images/s",
                f"{loss_metric}",
                f"{accuracy_metric}",
                f"{eta}",
            ]))
            time_cost_metric.reset()
            speed_tester.reset()

    _logger.info(", ".join([
        phase.upper(),
        f"epoch={epoch:04d} {phase} complete",
        f"{loss_metric}",
        f"{accuracy_metric}",
    ]))

    return {
        f"{phase}/lr": lr,
        f"{phase}/loss": loss_metric.compute(),
        f"{phase}/top1_acc": accuracy_metric.at(1).rate,
        f"{phase}/top5_acc": accuracy_metric.at(5).rate,
    }

train_one_epoch = functools.partial(_run_one_epoch, is_training=True)
evaluate_one_epoch = functools.partial(_run_one_epoch, is_training=False)


#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Author  ：fangpf
@Date    ：2022/2/8 15:32
"""
import math
import warnings
from collections import OrderedDict

import cv2
import imgaug
import pyclipper
import torch
import torchvision
from PIL import Image
import numpy as np
from shapely.geometry import Polygon
import imgaug.augmenters as iaa

'''
数据增强变换方法
'''

class BaseAugment():
    '''
    通过 imgaug.augmenters 进行基础变换，包括尺寸调整、翻转、旋转等
    '''

    def __init__(self, only_resize=False, keep_ratio=False, augmenters=None, resize_shape=None):
        self.only_resize = only_resize
        self.keep_ratio = keep_ratio
        self.augmenter = augmenters
        self.resize_shape = resize_shape

    def resize_image(self, image):
        origin_height, origin_width, _ = image.shape
        height = self.resize_shape['height']
        width = self.resize_shape['width']
        if self.keep_ratio:  # 是否保持图像长宽比不变
            width = origin_width * height / origin_height
            N = math.ceil(width / 32)
            width = N * 32
        image = cv2.resize(image, (width, height))
        return image

    def process(self, data):
        image = data['image']
        shape = image.shape

        if self.augmenter:
            aug = self.augmenter.to_deterministic()
            if self.only_resize:
                data['image'] = self.resize_image(image)  # 只进行尺寸调整
            else:
                data['image'] = aug.augment_image(image)  # 图像变换
            self.may_augment_annotation(aug, data, shape)  # 对 polygon 标注进行对应的变换

        filename = data.get('filename', data.get('data_id', ''))
        data.update(filename=filename, shape=shape[:2])
        return data

    def may_augment_annotation(self, aug, data, shape):
        if aug is None:
            return data

        line_polys = []
        for line in data['lines']:
            if self.only_resize:
                new_poly = [(p[0], p[1]) for p in line['poly']]
            else:
                new_poly = self.may_augment_poly(aug, shape, line['poly'])
            line_polys.append({
                'points': new_poly,
                'ignore': line['text'] == '###',  # 图像是否是困难样本（模糊不可辨），本任务数据集中不存在困难样本
                'text': line['text'],
            })
        data['polys'] = line_polys
        return data

    def may_augment_poly(self, aug, img_shape, poly):
        keypoints = [imgaug.Keypoint(p[0], p[1]) for p in poly]
        keypoints = aug.augment_keypoints([imgaug.KeypointsOnImage(keypoints, shape=img_shape)])[0].keypoints
        poly = [(p.x, p.y) for p in keypoints]
        return poly

class ColorJitter():
    '''
    颜色增强，包括亮度、对比度、饱和度、色相变换
    '''

    def __init__(self, b=0.2, c=0.2, s=0.15, h=0.15):
        self.color_jitter = torchvision.transforms.ColorJitter(
            brightness=b, contrast=c, saturation=s, hue=h)

    def process(self, data):
        img = data['image']
        image = Image.fromarray(img.astype('uint8')).convert('RGB')  # 数据类型转换
        img = np.array(self.color_jitter(image)).astype(np.float64)
        data['image'] = img
        return data

class RandomCropData():
    '''
    随机裁剪图像，并保证裁剪时不切割到图像中的文字区域
    '''

    def __init__(self, size=(640, 640)):
        self.size = size
        self.max_tries = 10  # 裁剪尝试的最大次数（因为存在裁剪区域太小等裁剪失败情况）
        self.min_crop_side_ratio = 0.1  # 裁剪区域边长最小比例，即裁剪的图像边长与原始图像边长的比值不能小于 min_crop_side_ratio

    def process(self, data):
        img = data['image']

        ori_img = img
        ori_lines = data['polys']
        all_care_polys = [line['points'] for line in data['polys'] if not line['ignore']]
        crop_x, crop_y, crop_w, crop_h = self.crop_area(img, all_care_polys)  # 裁剪区域的左上角坐标(x, y)以及区域宽高(w, h)

        # 根据裁剪区域参数对图像进行裁剪，并填充空白以得到指定 size 的图像（在右侧或者底侧进行填充）
        scale_w = self.size[0] / crop_w
        scale_h = self.size[1] / crop_h
        scale = min(scale_w, scale_h)
        h = int(crop_h * scale)
        w = int(crop_w * scale)
        padimg = np.zeros((self.size[1], self.size[0], img.shape[2]), img.dtype)
        padimg[:h, :w] = cv2.resize(img[crop_y:crop_y + crop_h, crop_x:crop_x + crop_w], (w, h))
        img = padimg

        # 根据裁剪区域参数对文字位置坐标进行转换
        lines = []
        for line in data['polys']:
            poly = ((np.array(line['points']) - (crop_x, crop_y)) * scale).tolist()
            if not self.is_poly_outside_rect(poly, 0, 0, w, h): lines.append({**line, 'points': poly})  # 不保留裁剪区域之外的文字

        data['polys'] = lines
        data['image'] = img

        return data

    def is_poly_outside_rect(self, poly, x, y, w, h):
        # 判断文字polygon 是否在矩形区域外
        poly = np.array(poly)
        if poly[:, 0].max() < x or poly[:, 0].min() > x + w:
            return True
        if poly[:, 1].max() < y or poly[:, 1].min() > y + h:
            return True
        return False

    def split_regions(self, axis):
        # 返回可划切割线的连续区域
        regions = []
        min_axis = 0
        for i in range(1, axis.shape[0]):
            if axis[i] != axis[i - 1] + 1:
                region = axis[min_axis:i]
                min_axis = i
                regions.append(region)
        return regions

    def random_select(self, axis, max_size):
        # 从一块连续区域中选择两条切割线
        xx = np.random.choice(axis, size=2)
        xmin = np.min(xx)
        xmax = np.max(xx)
        xmin = np.clip(xmin, 0, max_size - 1)
        xmax = np.clip(xmax, 0, max_size - 1)
        return xmin, xmax

    def region_wise_random_select(self, regions, max_size):
        # 从两块连续区域中选择两条切割线
        selected_index = list(np.random.choice(len(regions), 2))
        selected_values = []
        for index in selected_index:
            axis = regions[index]
            xx = int(np.random.choice(axis, size=1))
            selected_values.append(xx)
        xmin = min(selected_values)
        xmax = max(selected_values)
        return xmin, xmax

    def crop_area(self, img, polys):
        # 裁剪区域
        h, w, _ = img.shape
        h_array = np.zeros(h, dtype=np.int32)
        w_array = np.zeros(w, dtype=np.int32)
        for points in polys:
            points = np.round(points, decimals=0).astype(np.int32)
            minx = np.min(points[:, 0])
            maxx = np.max(points[:, 0])
            w_array[minx:maxx] = 1
            miny = np.min(points[:, 1])
            maxy = np.max(points[:, 1])
            h_array[miny:maxy] = 1
        # h_array == 1 的位置表示有文本，h_array == 0 的位置表示无文本；w_array 同理
        h_axis = np.where(h_array == 0)[0]
        w_axis = np.where(w_array == 0)[0]

        if len(h_axis) == 0 or len(w_axis) == 0:
            return 0, 0, w, h

        h_regions = self.split_regions(h_axis)
        w_regions = self.split_regions(w_axis)

        for i in range(self.max_tries):
            if len(w_regions) > 1:
                # 有多块可切割区域时
                xmin, xmax = self.region_wise_random_select(w_regions, w)
            else:
                # 只有一块可切割区域时
                xmin, xmax = self.random_select(w_axis, w)
            if len(h_regions) > 1:
                ymin, ymax = self.region_wise_random_select(h_regions, h)
            else:
                ymin, ymax = self.random_select(h_axis, h)

            if xmax - xmin < self.min_crop_side_ratio * w or ymax - ymin < self.min_crop_side_ratio * h:
                # 切割区域太小，不可取
                continue
            num_poly_in_rect = 0

            # 保证至少有一个文字区域在切割出的区域中即可
            for poly in polys:
                if not self.is_poly_outside_rect(poly, xmin, ymin, xmax - xmin, ymax - ymin):
                    num_poly_in_rect += 1
                    break

            if num_poly_in_rect > 0:
                return xmin, ymin, xmax - xmin, ymax - ymin

        return 0, 0, w, h

class MakeSegDetectionData():
    '''
    构造文本区域二值图（DB论文中的 probability map），以及用于计算loss的mask
    '''

    def __init__(self, min_text_size=8, shrink_ratio=0.4):
        self.min_text_size = min_text_size
        self.shrink_ratio = shrink_ratio  # polygon 收缩比例

    def process(self, data):
        # 数据结构调整统一，方便后续操作
        polygons = []
        ignore_tags = []
        annotations = data['polys']
        for annotation in annotations:
            polygons.append(np.array(annotation['points']))
            ignore_tags.append(annotation['ignore'])
        ignore_tags = np.array(ignore_tags, dtype=np.uint8)
        filename = data.get('filename', data['data_id'])
        shape = np.array(data['shape'])
        data = OrderedDict(image=data['image'],
                           polygons=polygons,
                           ignore_tags=ignore_tags,
                           shape=shape,
                           filename=filename,
                           is_training=data['is_training'])

        image = data['image']
        polygons = data['polygons']
        ignore_tags = data['ignore_tags']
        image = data['image']
        filename = data['filename']

        h, w = image.shape[:2]
        if data['is_training']:
            polygons, ignore_tags = self.validate_polygons(polygons, ignore_tags, h, w)
        gt = np.zeros((h, w), dtype=np.float32)
        mask = np.ones((h, w), dtype=np.float32)
        for i in range(len(polygons)):
            polygon = polygons[i]
            height = max(polygon[:, 1]) - min(polygon[:, 1])
            width = max(polygon[:, 0]) - min(polygon[:, 0])
            if ignore_tags[i] or min(height, width) < self.min_text_size:  # 文本区域太小时，作为困难样本 ignore
                cv2.fillPoly(mask, polygon.astype(np.int32)[np.newaxis, :, :], 0)
                ignore_tags[i] = True
            else:
                # 收缩 polygon 并绘制 probability map
                polygon_shape = Polygon(polygon)
                distance = polygon_shape.area * (1 - np.power(self.shrink_ratio, 2)) / polygon_shape.length
                subject = [tuple(l) for l in polygons[i]]
                padding = pyclipper.PyclipperOffset()
                padding.AddPath(subject, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
                shrinked = padding.Execute(-distance)
                if shrinked == []:
                    cv2.fillPoly(mask, polygon.astype(np.int32)[np.newaxis, :, :], 0)
                    ignore_tags[i] = True
                    continue
                shrinked = np.array(shrinked[0]).reshape(-1, 2)
                cv2.fillPoly(gt, [shrinked.astype(np.int32)], 1)

        if filename is None:
            filename = ''
        data.update(image=image,
                    polygons=polygons,
                    gt=gt, mask=mask, filename=filename)
        return data

    def validate_polygons(self, polygons, ignore_tags, h, w):
        '''
        统一polygon坐标顺序，并且ignore面积为0的polygons
        '''
        if len(polygons) == 0:
            return polygons, ignore_tags
        assert len(polygons) == len(ignore_tags)
        for polygon in polygons:
            polygon[:, 0] = np.clip(polygon[:, 0], 0, w - 1)
            polygon[:, 1] = np.clip(polygon[:, 1], 0, h - 1)

        for i in range(len(polygons)):
            area = self.polygon_area(polygons[i])
            if abs(area) < 1:
                ignore_tags[i] = True
            if area > 0:
                polygons[i] = polygons[i][::-1, :]  # 调整坐标顺序
        return polygons, ignore_tags

    def polygon_area(self, polygon):
        edge = 0
        for i in range(polygon.shape[0]):
            next_index = (i + 1) % polygon.shape[0]
            edge += (polygon[next_index, 0] - polygon[i, 0]) * (polygon[next_index, 1] + polygon[i, 1])

        return edge / 2.

class MakeBorderMap():
    '''
    构造文本边界二值图（DB论文中的 threshold map），以及用于计算loss的mask
    '''

    def __init__(self, shrink_ratio=0.4, thresh_min=0.3, thresh_max=0.7):
        self.shrink_ratio = shrink_ratio
        self.thresh_min = thresh_min
        self.thresh_max = thresh_max
        warnings.simplefilter("ignore")

    def process(self, data):
        image = data['image']
        polygons = data['polygons']
        ignore_tags = data['ignore_tags']
        canvas = np.zeros(image.shape[:2], dtype=np.float32)
        mask = np.zeros(image.shape[:2], dtype=np.float32)

        for i in range(len(polygons)):
            if ignore_tags[i]:
                continue
            self.draw_border_map(polygons[i], canvas, mask=mask)  # 绘制 border map
        canvas = canvas * (self.thresh_max - self.thresh_min) + self.thresh_min
        data['thresh_map'] = canvas
        data['thresh_mask'] = mask
        return data

    def draw_border_map(self, polygon, canvas, mask):
        polygon = np.array(polygon)
        assert polygon.ndim == 2
        assert polygon.shape[1] == 2

        polygon_shape = Polygon(polygon)
        distance = polygon_shape.area * (1 - np.power(self.shrink_ratio, 2)) / polygon_shape.length
        subject = [tuple(l) for l in polygon]
        padding = pyclipper.PyclipperOffset()
        padding.AddPath(subject, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
        padded_polygon = np.array(padding.Execute(distance)[0])
        cv2.fillPoly(mask, [padded_polygon.astype(np.int32)], 1.0)

        xmin = padded_polygon[:, 0].min()
        xmax = padded_polygon[:, 0].max()
        ymin = padded_polygon[:, 1].min()
        ymax = padded_polygon[:, 1].max()
        width = xmax - xmin + 1
        height = ymax - ymin + 1

        polygon[:, 0] = polygon[:, 0] - xmin
        polygon[:, 1] = polygon[:, 1] - ymin

        xs = np.broadcast_to(np.linspace(0, width - 1, num=width).reshape(1, width), (height, width))
        ys = np.broadcast_to(np.linspace(0, height - 1, num=height).reshape(height, 1), (height, width))

        distance_map = np.zeros((polygon.shape[0], height, width), dtype=np.float32)
        for i in range(polygon.shape[0]):
            j = (i + 1) % polygon.shape[0]
            absolute_distance = self.distance(xs, ys, polygon[i], polygon[j])
            distance_map[i] = np.clip(absolute_distance / distance, 0, 1)
        distance_map = distance_map.min(axis=0)

        xmin_valid = min(max(0, xmin), canvas.shape[1] - 1)
        xmax_valid = min(max(0, xmax), canvas.shape[1] - 1)
        ymin_valid = min(max(0, ymin), canvas.shape[0] - 1)
        ymax_valid = min(max(0, ymax), canvas.shape[0] - 1)
        canvas[ymin_valid:ymax_valid + 1, xmin_valid:xmax_valid + 1] = np.fmax(
            1 - distance_map[
                ymin_valid - ymin:ymax_valid - ymax + height,
                xmin_valid - xmin:xmax_valid - xmax + width],
            canvas[ymin_valid:ymax_valid + 1, xmin_valid:xmax_valid + 1])

    def distance(self, xs, ys, point_1, point_2):
        # 计算图像中的点到 文字polygon 边界的距离
        height, width = xs.shape[:2]
        square_distance_1 = np.square(
            xs - point_1[0]) + np.square(ys - point_1[1])
        square_distance_2 = np.square(
            xs - point_2[0]) + np.square(ys - point_2[1])
        square_distance = np.square(
            point_1[0] - point_2[0]) + np.square(point_1[1] - point_2[1])

        cosin = (square_distance - square_distance_1 - square_distance_2) / (
                    2 * np.sqrt(square_distance_1 * square_distance_2))
        square_sin = 1 - np.square(cosin)
        square_sin = np.nan_to_num(square_sin)
        result = np.sqrt(square_distance_1 * square_distance_2 * square_sin / square_distance)

        result[cosin < 0] = np.sqrt(np.fmin(square_distance_1, square_distance_2))[cosin < 0]
        return result

class NormalizeImage():
    '''
    将图像元素值归一化到[-1, 1]
    '''
    RGB_MEAN = np.array([122.67891434, 116.66876762, 104.00698793])

    def process(self, data):
        assert 'image' in data, '`image` in data is required by this process'
        image = data['image']
        image -= self.RGB_MEAN
        image /= 255.
        image = torch.from_numpy(image).permute(2, 0, 1).float()
        data['image'] = image
        return data

    @classmethod
    def restore(self, image):
        image = image.permute(1, 2, 0).to('cpu').numpy()
        image = image * 255.
        image += self.RGB_MEAN
        image = image.astype(np.uint8)
        return image

class FilterKeys():
    '''
    过滤掉后续不需要的键值对
    '''

    def __init__(self, superfluous):
        self.superfluous_keys = set(superfluous)

    def process(self, data):
        for key in self.superfluous_keys:
            del data[key]
        return data


# def p(c,d):
#     print("The sum of", c, "and", d, "is", c+d )
# p(4,7)

# value = (input("How old are you: "))

# if value > 18:
#     print("You are an adult")

# else:
#     print("You are young")

def calculator(operation, a, b):
    if operation == "add":
        return a + b
    elif operation == "substract":
        return a - b
    elif operation == "divide":
        return a/b
    else:
        return "The maths is difficult"

    result = print(substract, 10, 3)


import pandas as pd
import numpy as np

import ctdcal.odf_io as odf_io
#import libODF_precalibration as precal

std_dir = f'/Users/jgum/work_code/cruises/'
cruise_dir = f'{std_dir}NBP1707/'
data_dir = f'{cruise_dir}ctd_proc_rewrite/data/'
bottle_dir = f'{data_dir}bottle/'
salt_dir = f'{data_dir}salt/'

ssscc_file = '../ssscc.csv'

ssscc = []
with open(ssscc_file, 'r') as filename:
    ssscc = [line.strip() for line in filename]

corrected_salts = pd.DataFrame()
for x in ssscc:
    #Boilerplate
    df = odf_io.load_short_salts_2017(f'{salt_dir}{x}')
    df = odf_io.salts_create_index_time(df)
    p = odf_io.autosal_drift_calibration(df)
    df = odf_io.autosal_drift_fit(df)
    df = odf_io.compute_salinity(df)
    df = odf_io.formatted_salt_file(df)

    #Put together the frames to make one big one
    corrected_salts = pd.concat([corrected_salts, df], axis = 0)

corrected_salts.to_pickle(f'{data_dir}/scratch_folder/all_corrected_salts.pkl')


#!/usr/bin/env python

# ros
import rospy
from std_msgs.msg import String
from trajectory_msgs.msg import MultiDOFJointTrajectory, MultiDOFJointTrajectoryPoint
from geometry_msgs.msg import Pose, Twist, Transform
from nav_msgs.msg import Odometry
from sensor_msgs.msg import Imu
from gazebo_msgs.msg import ModelState
from unreal_cv_ros.msg import UeSensorRaw
from sensor_msgs.msg import PointCloud2
from std_srvs.srv import Empty
from gazebo_msgs.srv import SetModelState, GetModelState
import tf

# Python
import sys
import math
import numpy as np
import time
from collections import deque

class SimulationManager:

    def __init__(self):
        '''  Initialize ros node and read params '''
        # Parse parameters
        self.ns_gazebo = rospy.get_param('~ns_gazebo', "/gazebo")
        self.ns_mav = rospy.get_param('~ns_mav', "/firefly")
        self.regulate = rospy.get_param('~regulate', False)  # Manage odom throughput for unreal_ros_client
        self.monitor = rospy.get_param('~monitor', False)  # Measure performance of unreal pipeline
        self.initial_position = rospy.get_param('~initial_position', [0, 0, 0])  # x, y, z [m]

        if self.monitor:
            self.horizon = rospy.get_param('~horizon', 10)  # How many messages are kept for monitoring

            # Monitoring arrays
            self.mon_client_rate_real = deque(maxlen=self.horizon)
            self.mon_client_rate_ros = deque(maxlen=self.horizon)
            self.mon_client_prev_real = None
            self.mon_client_prev_ros = None
            self.mon_client_delay_ros = deque(maxlen=self.horizon)
            self.mon_client_time = deque(maxlen=self.horizon)
            self.mon_sensor_rate_real = deque(maxlen=self.horizon)
            self.mon_sensor_rate_ros = deque(maxlen=self.horizon)
            self.mon_sensor_prev_real = None
            self.mon_sensor_prev_ros = None
            self.mon_sensor_delay_ros = deque(maxlen=self.horizon)
            self.mon_sensor_time = deque(maxlen=self.horizon)

            # Subscribers
            self.ue_raw_sub = rospy.Subscriber("ue_raw_in", UeSensorRaw, self.mon_raw_callback, queue_size=10)
            self.ue_out_sub = rospy.Subscriber("ue_out_in", PointCloud2, self.mon_out_callback, queue_size=10)

            # Printing service
            rospy.Service('~display_monitor', Empty, self.mon_print_handle)

        if self.regulate:
            # Subscribers and publishers
            self.odom_sub = rospy.Subscriber("odom_in", Odometry, self.odom_callback, queue_size=10)
            self.odom_pub = rospy.Publisher("~odom_out", Odometry, queue_size=10)

        # Run the startup
        self.ready_pub = rospy.Publisher("~simulation_ready", String, queue_size=10)
        self.launch_simulation()

    def launch_simulation(self):
        # Wait for Gazebo services
        rospy.loginfo("Starting unreal MAV simulation setup coordination...")
        rospy.wait_for_service(self.ns_gazebo + "/unpause_physics")
        rospy.wait_for_service(self.ns_gazebo + "/set_model_state")

        # Prepare initialization trajectory command
        traj_pub = rospy.Publisher(self.ns_mav + "/command/trajectory", MultiDOFJointTrajectory, queue_size=10)
        traj_msg = MultiDOFJointTrajectory()
        traj_msg.joint_names = ["base_link"]
        transforms = Transform()
        transforms.translation.x = self.initial_position[0]
        transforms.translation.y = self.initial_position[1]
        transforms.translation.z = self.initial_position[2]
        point = MultiDOFJointTrajectoryPoint([transforms], [Twist()], [Twist()], rospy.Duration(0))
        traj_msg.points.append(point)

        # Prepare initialization Get/SetModelState service
        set_model_srv = rospy.ServiceProxy(self.ns_gazebo + "/set_model_state", SetModelState)
        get_model_srv = rospy.ServiceProxy(self.ns_gazebo + "/get_model_state", GetModelState)
        mav_name = self.ns_mav[np.max([i for i in range(len(self.ns_mav)) if self.ns_mav[i] == "/"]) + 1:]
        pose = Pose()
        pose.position.x = self.initial_position[0]
        pose.position.y = self.initial_position[1]
        pose.position.z = self.initial_position[2]
        model_state_set = ModelState(mav_name, pose, Twist(), "world")

        # Wake up gazebo
        rospy.loginfo("Waiting for gazebo to wake up ...")
        unpause_srv = rospy.ServiceProxy(self.ns_gazebo + "/unpause_physics", Empty)
        while not unpause_srv():
            rospy.sleep(0.1)
        rospy.loginfo("Waiting for gazebo to wake up ... done.")

        # Wait for drone to spawn (imu is publishing)
        rospy.loginfo("Waiting for MAV to spawn ...")
        rospy.wait_for_message(self.ns_mav + "/imu", Imu)
        rospy.loginfo("Waiting for MAV to spawn ... done.")

        # Initialize drone stable at [0, 0, 0]
        rospy.loginfo("Waiting for MAV to stabilize ...")
        dist = 10  # Position and velocity
        while dist >= 0.1:
            traj_msg.header.stamp = rospy.Time.now()
            traj_pub.publish(traj_msg)
            set_model_srv(model_state_set)
            rospy.sleep(0.1)
            state = get_model_srv(mav_name, "world")
            pos = state.pose.position
            twist = state.twist.linear
            dist = np.sqrt((pos.x - self.initial_position[0]) ** 2 + (pos.y - self.initial_position[1]) ** 2 +
                           (pos.z - self.initial_position[2]) ** 2) + np.sqrt(
                twist.x ** 2 + twist.y ** 2 + twist.z ** 2)
        rospy.loginfo("Waiting for MAV to stabilize ... done.")

        # Wait for unreal client
        rospy.loginfo("Waiting for unreal client to setup ...")
        rospy.wait_for_message("ue_out_in", PointCloud2)
        rospy.loginfo("Waiting for unreal client to setup ... done.")

        # Finish
        self.ready_pub.publish(String("Simulation Ready"))
        rospy.loginfo("Unreal MAV simulation setup successfully.")

    def mon_raw_callback(self, ros_data):
        # Measure walltime and rostime between callbacks
        time_real = time.time()
        time_ros = rospy.get_time()
        if self.mon_client_prev_real is None:
            # Initialization
            self.mon_client_prev_real = time_real
            self.mon_client_prev_ros = time_ros
            return

        self.mon_client_rate_real.append(time_real - self.mon_client_prev_real)
        self.mon_client_prev_real = time_real
        self.mon_client_rate_ros.append(time_ros - self.mon_client_prev_ros)
        self.mon_client_prev_ros = time_ros
        self.mon_client_delay_ros.append(time_ros - ros_data.header.stamp.to_sec())
        self.mon_client_time.append(time_ros)

    def mon_out_callback(self, ros_data):
        # Measure walltime and rostime between callbacks
        time_real = time.time()
        time_ros = rospy.get_time()
        if self.mon_sensor_prev_real is None:
            # Initialization
            self.mon_sensor_prev_real = time_real
            self.mon_sensor_prev_ros = time_ros
            return

        self.mon_sensor_rate_real.append(time_real - self.mon_sensor_prev_real)
        self.mon_sensor_prev_real = time_real
        self.mon_sensor_rate_ros.append(time_ros - self.mon_sensor_prev_ros)
        self.mon_sensor_prev_ros = time_ros
        self.mon_sensor_delay_ros.append(time_ros - ros_data.header.stamp.to_sec())
        self.mon_sensor_time.append(time_ros)

    def mon_print_handle(self, _):
        print("=" * 14 + " performance monitor " + "=" * 14)
        print("Fields: [Hz] / [s]   avg  -  std  -  min  -  max ")
        values = 1.0 / np.array(self.mon_client_rate_real)
        if len(values) > 0:
            print("Client rate (wall): {0:05.2f} - {1:05.2f} - {2:05.2f} - {3:05.2f}"
                  .format(np.mean(values), np.std(values), np.min(values), np.max(values)))
        values = 1.0 / np.array(self.mon_client_rate_ros)
        if len(values) > 0:
            print("Client rate  (ros): {0:05.2f} - {1:05.2f} - {2:05.2f} - {3:05.2f}"
                  .format(np.mean(values), np.std(values), np.min(values), np.max(values)))
        values = np.array(self.mon_client_delay_ros)
        if len(values) > 0:
            print("Client delay (ros): {0:05.2f} - {1:05.2f} - {2:05.2f} - {3:05.2f}"
                  .format(np.mean(values), np.std(values), np.min(values), np.max(values)))
        values = 1.0 / np.array(self.mon_sensor_rate_real)
        if len(values) > 0:
            print("Sensor rate (wall): {0:05.2f} - {1:05.2f} - {2:05.2f} - {3:05.2f}"
                  .format(np.mean(values), np.std(values), np.min(values), np.max(values)))
        values = 1.0 / np.array(self.mon_sensor_rate_ros)
        if len(values) > 0:
            print("Sensor rate  (ros): {0:05.2f} - {1:05.2f} - {2:05.2f} - {3:05.2f}"
                  .format(np.mean(values), np.std(values), np.min(values), np.max(values)))
        values = np.array(self.mon_sensor_delay_ros)
        if len(values) > 0:
            print("Sensor delay (ros): {0:05.2f} - {1:05.2f} - {2:05.2f} - {3:05.2f}"
                  .format(np.mean(values), np.std(values), np.min(values), np.max(values)))
        print("=" * 49)
        return []

if __name__ == '__main__':
    rospy.init_node('simulation_manager', anonymous=True)
    sm = SimulationManager()
    rospy.spin()


from datetime import timedelta

from sql import Literal, Join
from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction
from trytond.model import ModelView, ModelSQL, fields
from trytond.pyson import Eval, Not, Bool, PYSONEncoder, Equal
from trytond.wizard import (Wizard, StateView, StateTransition, Button,
                            StateAction)

from .reports import DailyPatientRegister

__all__ = ['PatientRegisterModel', 'PatientRegisterWizard',
           'PatientRegisterFilterView', 'PatientRegisterFilteredWizard',
           'AppointmentReport', 'OpenAppointmentReportStart',
           'OpenAppointmentReport', 'StartEndDateModel', 'PRFDisease',
           'PRFProcedure']

class StartEndDateModel(ModelView):
    '''Generic ModelView that has start and end date fields. '''
    __name__ = 'healthjm.report.startenddate_generic'

    on_or_after = fields.Date('Start date', required=True)
    on_or_before = fields.Date('End date')
    institution = fields.Many2One('gnuhealth.institution', 'Institution',
                                  required=True, states={'readonly':True})

    @classmethod
    def __setup__(cls):
        super(StartEndDateModel, cls).__setup__()
        cls._error_messages.update({
            'required_institution':'''Institution is required.\n
Your user account is not assigned to an institution.
This assignment is needed before you can use this report.
Please contact your system administrator to have this resolved.'''
            })

    @staticmethod
    def default_institution():
        HealthInst = Pool().get('gnuhealth.institution')
        try:
            institution = HealthInst.get_institution()
        except AttributeError:
            self.raise_user_error('required_institution')
        return institution

class PatientRegisterModel(StartEndDateModel):
    '''Patient Evaluation Register'''
    __name__ = 'healthjm.report.patientregister.start'
    specialty = fields.Selection('get_specialty_list', 'Specialty')

    @fields.depends('institution')
    def get_specialty_list(self):
        if self.institution:
            return [(x.specialty.id, x.specialty.name)
                    for x in self.institution.specialties]
        else:
            return []

class PatientRegisterWizard(Wizard):
    '''Evaluation Register Wizard'''
    __name__ = 'healthjm.report.patientregister.wizard'
    start = StateView('healthjm.report.patientregister.start',
        'health_jamaica.healthjm_form_patientregister_report_start', [
            Button('Cancel', 'end', 'tryton-cancel'),
            Button('Generate Report', 'generate_report', 'tryton-ok',
                    default=True),
        ])
    generate_report = StateAction(
                            'health_jamaica.healthjm_report_patientregister')

    def transition_generate_report(self):
        return 'end'

    def do_generate_report(self, action):
        # specify data that will be passed to .parse on the report object
        data = {'start_date':self.start.on_or_after,
                'end_date':self.start.on_or_after,
                'specialty':None,
                'facility':None,
                'x_extra_criteria': False}

        if self.start.on_or_before:
            data['end_date'] = self.start.on_or_before

        if self.start.specialty:
            data['specialty'] = self.start.specialty

        if self.start.institution:
            data['institution'] = self.start.institution.id
        else:
            self.start.raise_user_error('required_institution')
            return 'start'

        return action, data

def permute_opts(name='diseases'):
    return [
        ('OR', 'Include ANY of the selected %s (OR)' % name),
        ('AND', 'Include ALL of the selected %s (AND)' % name)]
        # ('nor', 'Include None of the selected %s (NOR)' % name)]

class PatientRegisterFilterView(PatientRegisterModel):
    'Patient Evaluation Register (by Disease)'
    __name__ = 'healthjm.report.patientregister_filtered.start'
    dp_perm = fields.Selection(
        [('dp', 'Both Diseases and Procedures'), ('d', 'Diseases Only'),
         ('p', 'Procedures Only'), ('o', 'Either Diseases or Procedures')],
        'Filter by', sort=False)
    diseases = fields.One2Many(
        'healthjm.report.patientregister_filtered.disease_o2m', 'prf',
        'Selected Diseases', states={'readonly': Equal(Eval('dp_perm'), 'p')})
    procedures = fields.One2Many(
        'healthjm.report.patientregister_filtered.procedure_o2m', 'prf',
        'Selected Procedures', states={'readonly': Equal(Eval('dp_perm'), 'd')})

    disease_perm = fields.Selection(permute_opts(), 'Disease option', sort=False)
    procedure_perm = fields.Selection(permute_opts('procedures'),
                                      'Procedure option', sort=False)

    @staticmethod
    def default_disease_perm():
        return 'AND'

    @staticmethod
    def default_procedure_perm():
        return 'AND'

    @staticmethod
    def default_dp_perm():
        return 'o'

class PRFDisease(ModelView):
    'Patient Evaluation Register - Diseases'
    __name__ = 'healthjm.report.patientregister_filtered.disease_o2m'
    prf = fields.Many2One('healthjm.report.patientregister_filtered.start',
                          'PRF', readonly=True)
    pathology = fields.Many2One('gnuhealth.pathology', 'Disease',
                                required=True)
    invert = fields.Boolean('Invert',
                            help='exclude rather than include this one')

class PRFProcedure(ModelView):
    'Patient Evaluation Register - Procedures'
    __name__ = 'healthjm.report.patientregister_filtered.procedure_o2m'
    prf = fields.Many2One('healthjm.report.patientregister_filtered.start',
                          'PRF', readonly=True)
    procedure = fields.Many2One('gnuhealth.procedure', 'Procedure',
                                required=True)
    invert = fields.Boolean('Invert',
                            help='exclude rather than include this one')

class PatientRegisterFilteredWizard(PatientRegisterWizard):
    '''Evaluation Register Wizard'''
    __name__ = 'healthjm.report.patientregister_filtered.wizard'

    start = StateView(
        'healthjm.report.patientregister_filtered.start',
        'health_jamaica.healthjm_form_patientregisterflt_report_start', [
            Button('Cancel', 'end', 'tryton-cancel'),
            Button('Generate Report', 'generate_report', 'tryton-ok',
                   default=True),
        ])
    generate_report = StateAction(
        'health_jamaica.healthjm_report_patientregister_filtered')

    def transition_generate_report(self):
        return 'end'

    def do_generate_report(self, action):
        def make_disease_domain(disease):
            if disease.invert:
                return (['AND', ('diagnosis', '!=', disease.pathology.id),
                        ('secondary_conditions.pathology', '!=',
                         disease.pathology.id)],
                        u'Not(%s [%s])' % (disease.pathology.name,
                                           disease.pathology.code))
            else:
                return (['OR', ('diagnosis', '=', disease.pathology.id),
                        ('secondary_conditions.pathology', '=',
                         disease.pathology.id)],
                        u'%s [%s]' % (disease.pathology.name,
                                      disease.pathology.code))

        def make_procedure_domain(procedure):
            if procedure.invert:
                return (('procedures.procedure', '=', procedure.procedure.id),
                        u'Not(%s [%s])' % (procedure.description,
                                           procedure.name))
            else:
                return (('procedures.procedure', '=', procedure.procedure.id),
                        u'%s [%s]' % (procedure.procedure.description,
                                      procedure.procedure.name))

        bad_action, data = super(
            PatientRegisterFilteredWizard, self).do_generate_report(action)

        search_criteria = {'disease': [], 'procedure': []}
        search_criteria_names = {'disease': [], 'procedure': []}

        if self.start.dp_perm in ('dp', 'd', 'o') and self.start.diseases:
            for disease in self.start.diseases:
                criteria, name = make_disease_domain(disease)
                search_criteria['disease'].append(criteria)
                search_criteria_names['disease'].append(name)
            if len(search_criteria_names['disease']) == 1:
                search_criteria['disease'] = search_criteria['disease'][0]
            else:
                search_criteria['disease'].insert(0, self.start.disease_perm)

        if self.start.dp_perm in ('dp', 'p', 'o') and self.start.procedures:
            for proc in self.start.procedures:
                criteria, name = make_procedure_domain(proc)
                search_criteria['procedure'].append(criteria)
                search_criteria_names['procedure'].append(name)
            if len(search_criteria_names['procedure']) == 1:
                search_criteria['procedure'] = search_criteria['procedure'][0]
            else:
                search_criteria['procedure'].insert(0,
                                                    self.start.procedure_perm)

        data.update(x_extra_criteria=True, x_search_criteria=search_criteria,
                    x_selected=search_criteria_names,
                    x_dp_perm=self.start.dp_perm,
                    x_encounter_fields=['patient.name.du.simple_address',
                    'patient.name.du.address_subdivision.name'],
                    x_selected_count=dict(
                        [(a, len(b))
                         for a, b in search_criteria_names.items()]))

        return action, data

class AppointmentReport(ModelSQL, ModelView):
    'Appointment Report'
    __name__ = 'gnuhealth.appointment.report'
    speciality = fields.Many2One('gnuhealth.specialty', 'Specialty')

    @classmethod
    def table_query(cls):
        pool = Pool()
        xaction = Transaction()
        appointment = pool.get('gnuhealth.appointment').__table__()
        party = pool.get('party.party').__table__()
        patient = pool.get('gnuhealth.patient').__table__()
        join1 = Join(appointment, patient)
        join1.condition = join1.right.id == appointment.patient
        join2 = Join(join1, party)
        join2.condition = join2.right.id == join1.right.name
        where = Literal(True)
        if xaction.context.get('date_start'):
            where &= (appointment.appointment_date >=
                    xaction.context['date_start'])
        if xaction.context.get('date_end'):
            where &= (appointment.appointment_date <
                    xaction.context['date_end'] + timedelta(days=1))
        if xaction.context.get('healthprof'):
            where &= \
                appointment.healthprof == xaction.context['healthprof']

        if xaction.context.get('specialty', False):
            where &= appointment.speciality == xaction.context['specialty']

        return join2.select(
            appointment.id,
            appointment.create_uid,
            appointment.create_date,
            appointment.write_uid,
            appointment.write_date,
            join2.right.ref,
            join1.right.id.as_('patient'),
            join2.right.sex,
            appointment.appointment_date,
            appointment.appointment_date.as_('appointment_date_time'),
            appointment.healthprof,
            appointment.speciality,
            where=where)

class OpenAppointmentReportStart(ModelView):
    'Open Appointment Report'
    __name__ = 'gnuhealth.appointment.report.open.start'
    specialty = fields.Many2One('gnuhealth.specialty', 'Specialty',
                                states={'required':Not(Bool(Eval('healthprof')))})
    healthprof = fields.Many2One('gnuhealth.healthprofessional', 'Health Professional',
        required=False, states={'required':Not(Bool(Eval('specialty')))})

class OpenAppointmentReport(Wizard):
    'Open Appointment Report'
    __name__ = 'gnuhealth.appointment.report.open'

    def do_open_(self, action):
        action_dict = {'date_start': self.start.date_start,
            'date_end': self.start.date_end }
        if self.start.healthprof:
            action_dict['healthprof'] = self.start.healthprof.id
            action['name'] += ' - {}'.format(self.start.healthprof.name.name)

        if self.start.specialty:
            action_dict['specialty'] = self.start.specialty.id
            action['name'] += ' - {}'.format(self.start.specialty.name)

        action['pyson_context'] = PYSONEncoder().encode(action_dict)
        return action, {}


from Tkinter import *
import Leap, sys, time, math, thread
import numpy as np
import gunGraphics
import gameGraphics
import gameElements
import splashScreen
import helpScreen
import pauseScreen
import gunStore
import music

def init(data):
    backGroundMusic = thread(music.play, ('darkAmbient.wav',))
    backGroundMusic.start()
    data.controller = Leap.Controller()
    data.frame = data.controller.frame()
    data.fingerNames = ['Thumb', 'Index', 'Middle', 'Ring', 'Pinky']
    data.boneNames = ['Metacarpal', 'Proximal', 'Intermediate', 'Distal']
    data.fingerPoints = {}
    data.dist = 0
    data.fingerWidth = [0, 0, 0, 0, 0]
    data.trigger = 'white'
    data.intersect = [0, 0]
    data.intersectR = 5
    data.mode = 'Splash'
    data.scalar =  2.83464566929  #root.winfo_fpixels('1m') is how I came to the number, but I can't use this in the constructor
    data.gunCounter = 0
    data.fireAngle = 0
    data.gunsPurchased = [gunGraphics.HandGun(data.width, data.height)]
    data.gun = data.gunsPurchased[0]
    data.walls = []
    data.gunsInStore = [gunGraphics.ShotGun(data.width, data.height), gunGraphics.MachineGun(data.width, data.height), gunGraphics.Revolver(data.width, data.height)]
    data.batEnemies = {}
    gameGraphics.initialized(data)
    data.counter = 0
    data.health = 200
    data.score = 0
    data.gameOver = False
    data.firing = False
    data.fontFill = 'white'
    data.playBox = [(data.width - 140, 15), (data.width - 25, 50)]
    data.helpBox = [(data.width - 140 + 20,  15 + 40), (data.width - 140 + 115, 50 + 40)]
    data.pauseBox = [(data.width - 140, 15), (data.width - 25, 50)]
    data.storeBox = [(data.width - 160 + 25,  15 + 40 + 40), (data.width - 160 + 130, 50 + 40 + 40)]
    data.timeScale = float(data.timerDelay) / 1000
    data.mouseX = 0
    data.mouseY = 0
    data.intersectListX = []
    data.intersectListY = []
    with open('currency.txt', 'rt') as f:
        data.currency =  int(f.read())
def gameOver(data):
    with open('currency.txt', "wt") as f:
        f.write(str(data.currency))
def checkGameOver(data):
    if(data.health < 0):
        gameOver(data)
        data.mode = 'gameOver'
def updateLeapMotionData(data):
    data.frame = data.controller.frame()
def getLeapMotionData(data):
    # Get the most recent frame and report some basic information
    frame = data.frame
    # Get hands
    for hand in frame.hands:
        for finger in [hand.fingers[0], hand.fingers[1]]:
            data.fingerWidth[finger.type] = finger.width
            # Get bones
            for b in range(0, 4):
                bone = finger.bone(b)
                name = data.fingerNames[finger.type] + data.boneNames[bone.type]
                if(name == 'IndexDistal'):
                    data.indexDir = bone.direction
                data.fingerPoints[name] = []
                for joint in [bone.prev_joint, bone.next_joint]:
                    data.fingerPoints[name].extend([joint[0], joint[1], joint[2]])

def getTrigger(data):
    if('ThumbDistal' in data.fingerPoints and 'IndexMetacarpal' in data.fingerPoints):
        a0 = np.array(data.fingerPoints['ThumbDistal'][:3])
        a1 = np.array(data.fingerPoints['ThumbDistal'][3:])
        b0 = np.array(data.fingerPoints['IndexMetacarpal'][:3])
        b1 = np.array(data.fingerPoints['IndexMetacarpal'][3:])
        distA, distB, data.dist = getTriggerDistance(data, a0,a1,b0,b1)
        if(data.dist < data.fingerWidth[0] + data.fingerWidth[1] - 7):
            data.trigger = 'green'
        else:
            data.trigger = 'white'
#Code for plane intersection from: https://stackoverflow.com/questions/5666222/3d-line-plane-intersection
#user who posted it: https://stackoverflow.com/users/4288232/timsc
def getAim(data):
    if('IndexDistal' in data.fingerPoints):
        fingerTip = data.fingerPoints['IndexDistal'][3:]
        fingerDirection = [data.indexDir[0], data.indexDir[1], data.indexDir[2]]
        planePoint =  [0, 0, -212] #hardcoded to my computer width, but could take input later
        planeNormal = [0, 0, 1] #hardcoded to my computer angle, which is 90 deg, but could take input later
        data.intersect = list(planeIntersection(data, planeNormal, planePoint, fingerDirection, fingerTip))
        corner = [-152, 212, -212]
        data.intersect = [data.scalar * abs(corner[0] - data.intersect[0]), \
                          data.scalar * (corner[1] - data.intersect[1])]
        deltaX =  data.intersect[0] - data.width // 2
        deltaY = data.height -data.intersect[1]
        data.fireAngle = math.atan2(deltaY, deltaX)
        if(len(data.intersectListX) < 5):
            data.intersectListX.insert(0, data.intersect[0])
            data.intersectListY.insert(0, data.intersect[1])
        else:
            data.intersectListX.insert(0, data.intersect[0])
            data.intersectListY.insert(0, data.intersect[1])
            data.intersectListX.pop()
            data.intersectListY.pop()
            #data.intersect = [sum(data.intersectListX) // 5, sum(data.intersectListY) // 5]
#got this off of stack overflow from this user: https://stackoverflow.com/users/4288232/timsc
# on this post: #https://stackoverflow.com/questions/5666222/3d-line-plane-intersection
#Based on http://geomalgorithms.com/a05-_intersect-1.html
def planeIntersection(data, planeNormal, planePoint, rayDirection, rayPoint):
    epsilon=1e-6
    planeNormal = np.array(planeNormal)
    planePoint = np.array(planePoint)
    #Define ray
    rayDirection = np.array(rayDirection)
    rayPoint = np.array(rayPoint) #Any point along the ray
    ndotu = planeNormal.dot(rayDirection)

    if abs(ndotu) < epsilon: #line and plane are parallel
        return None
    else:
        w = rayPoint - planePoint
        si = -planeNormal.dot(w) / ndotu
        Psi = w + si * rayDirection + planePoint
        return Psi
#from stack overflow user: https://stackoverflow.com/users/1429402/fnord
#on this post: https://stackoverflow.com/questions/2824478/shortest-distance-between-two-line-segments
def getTriggerDistance(data, a0,a1,b0,b1):
    # Calculate denomitator
    A = a1 - a0
    B = b1 - b0
    magA = np.linalg.norm(A)
    magB = np.linalg.norm(B)

    _A = A / magA
    _B = B / magB

    cross = np.cross(_A, _B);
    denom = np.linalg.norm(cross)**2

    # If lines are parallel (denom=0) test if lines overlap.
    # If they don't overlap then there is a closest point solution.
    # If they do overlap, there are infinite closest positions, but there is a closest distance
    if not denom:
        d0 = np.dot(_A,(b0-a0))
        d1 = np.dot(_A,(b1-a0))
            # Is segment B before A?
        if d0 <= 0 >= d1:
            if np.absolute(d0) < np.absolute(d1):
                return a0,b0,np.linalg.norm(a0-b0)
            return a0,b1,np.linalg.norm(a0-b1)
        # Is segment B after A?
        elif d0 >= magA <= d1:
            if np.absolute(d0) < np.absolute(d1):
                return a1,b0,np.linalg.norm(a1-b0)
            return a1,b1,np.linalg.norm(a1-b1)

        # Segments overlap, return distance between parallel segments
        return None,None,np.linalg.norm(((d0*_A)+a0)-b0)

    # Lines criss-cross: Calculate the projected closest points
    t = (b0 - a0);
    detA = np.linalg.det([t, _B, cross])
    detB = np.linalg.det([t, _A, cross])

    t0 = detA/denom;
    t1 = detB/denom;

    pA = a0 + (_A * t0) # Projected closest point on segment A
    pB = b0 + (_B * t1) # Projected closest point on segment B
    # Clamp projections
    if t0 < 0:
        pA = a0
    elif t0 > magA:
        pA = a1

    if t1 < 0:
        pB = b0
    elif t1 > magB:
        pB = b1

    # Clamp projection A
    if (t0 < 0) or (t0 > magA):
        dot = np.dot(_B,(pA-b0))
        if dot < 0:
            dot = 0
        elif dot > magB:
            dot = magB
        pB = b0 + (_B * dot)

    # Clamp projection B
    if (t1 < 0) or (t1 > magB):
        dot = np.dot(_A,(pB-a0))
        if dot < 0:
            dot = 0
        elif dot > magA:
            dot = magA
        pA = a0 + (_A * dot)
    return list(pA),list(pB),np.linalg.norm(pA-pB)
def keyPressed(event, data):
    if(event.keysym == 'l'):
        data.gameOver = True
        data.mode = 'gameOver'
        gameOver(data)
    elif(event.keysym == 'c'):
        data.currency += 100
    elif(event.keysym == 'g'):
        data.gunsPurchased.extend(data.gunsInStore)
    elif(event.keysym == 'space'):
        data.gunCounter += 1
        data.gun = data.gunsPurchased[data.gunCounter % len(data.gunsPurchased)]
def mousePressed(event, data):
    data.mouseX = event.x
    data.mouseY = event.y
    if(data.mode == 'Splash'):
        splashScreen.changeModes(data)
    if(data.mode == 'Playing'):
        gameElements.changeModes(data)
    elif(data.mode == 'Paused'):
        pauseScreen.changeModes(data)
    elif(data.mode == 'Help'):
        helpScreen.changeModes(data)
    elif(data.mode == 'gunStore'):
        gunStore.changeModes(data)
    elif(data.mode == 'gameOver'):
        gameElements.changeModes(data)
def timerFired(data):
    if(data.mode == 'Splash'):
        pass
    elif(data.mode == 'Paused'):
        pass
    elif(data.mode == 'Help'):
        pass
    elif(data.mode == 'gunStore'):
        gunStore.timerFired(data)
    elif(data.mode == 'gameOver'):
        pass
    elif(data.mode == 'restart'):
        init(data)
    else:
        data.gun.timePassed += 1
        data.counter += 1
        updateLeapMotionData(data)
        getLeapMotionData(data)
        getTrigger(data)
        getAim(data)
        getEnemyHit(data)
        checkGameOver(data)
        if(data.counter % 2 == 0):
            gameGraphics.timerFired(data)

def hitBox(data, enemy):
    for box in enemy.boundingBox:
        if(box[0][0] - data.intersectR < data.intersect[0] < box[1][0] + data.intersectR  and \
            box[0][1] - data.intersectR < data.intersect[1] < box[1][1] + data.intersectR and data.trigger == 'green'):
            return True
    return False
def reloadGun(data):
    data.gun.ammo = data.gun.capacity
    reload = threading.Thread(target=music.play,\
                         args=('handGunReload.wav',))

    reload.start()
def getEnemyHit(data):
    if(data.gun.ammo <= 0):
        reloadGun(data)
    for enemy in [data.batEnemies, data.spiderEnemies]:
        for key, lst in enemy.items():
            for enemy in lst:
                if(hitBox(data, enemy) and data.gun.timePassed * data.timeScale > data.gun.shootGap):
                    data.score += 1
                    data.currency += 1
                    data.gun.timePassed = 0
                    enemy.isDead = True
                    data.hitX = data.intersect[0]
                    data.hitY = data.intersect[1]
                    data.firing = True
                    data.gun.ammo -= 1
                    shot = threading.Thread(target=music.play,\
                         args=(data.gun.noiseList[data.gun.counter % len(data.gun.noiseList)],))
                    shot.start()
                    data.gun.counter += 1

def redrawAll(canvas, data):
    if(data.mode == 'Splash'):
        splashScreen.redrawAll(canvas, data)
    elif(data.mode == 'Playing'):
        gameGraphics.redrawAll(canvas, data)
        gameElements.redrawAll(canvas, data)
        gunGraphics.redrawAll(canvas, data)
    elif(data.mode == 'Paused'):
        pauseScreen.redrawAll(canvas, data)
    elif(data.mode == 'gunStore'):
        gunStore.redrawAll(canvas, data)
    elif(data.mode == 'Help'):
        helpScreen.redrawAll(canvas, data)
    elif(data.mode == 'demo'):
        pass
    elif(data.mode == 'gameOver'):
        gameElements.gameOverScreen(canvas, data)

#CMU Graphics cite: https://gitlab.com/mattzjack/af2
#it's for the specific graphics framework I'm using for python2
#https://www.cs.cmu.edu/~112/notes/cmu_112_graphics.py

def run(width=300, height=300):
    def redrawAllWrapper(canvas, data):
        canvas.delete(ALL)
        canvas.create_rectangle(0, 0, data.width, data.height,
                                fill='white', width=0)
        redrawAll(canvas, data)
        canvas.update()

    def keyPressedWrapper(event, canvas, data):
        keyPressed(event, data)
        redrawAllWrapper(canvas, data)

    def mousePressedWrapper(event, canvas, data):
        mousePressed(event, data)
        redrawAllWrapper(canvas, data)

    def timerFiredWrapper(canvas, data):
        timerFired(data)
        redrawAllWrapper(canvas, data)
        # pause, then call timerFired again
        canvas.after(data.timerDelay, timerFiredWrapper, canvas, data)
    # Set up data and call init
    class Struct(object): pass

    data = Struct()
    data.width = width
    data.height = height
    data.timerDelay = 10 # milliseconds
    # create the root and the canvas
    root = Tk()
    init(data)
    canvas = Canvas(root, width=data.width, height=data.height)
    canvas.pack()

    timerFiredWrapper(canvas, data)
    # set up events
    root.bind("<Button-1>", lambda event:
                            mousePressedWrapper(event, canvas, data))
    root.bind("<Key>", lambda event:
                            keyPressedWrapper(event, canvas, data))
    # and launch the app
    root.mainloop()  # blocks until window is closed
    backGroundMusic.stop()
    print("bye!")
def main():

    run(1450, 750)
main()


from setuptools import setup, find_packages
import os

requirements = [
    'colorama',
]

init_fn = os.path.join(os.path.dirname(__file__), 'pjprobe', '__init__.py')
with open(init_fn) as f:
    for l in f.readlines():
        if '__version__' in l:
            exec(l)
            break

setup(
    name='pjprobe',
    version=__version__,
    install_requires=requirements,
    python_requires='>=3.7',
    packages=find_packages(),
    author="DelinQu",
    author_email="delinqu.cs@gmail.com",
    entry_points={
        'console_scripts': [
            'pjprobe = pjprobe.pjprobe:main',
        ]
    },
)


import math
import gym
from gym import spaces, logger
from gym.utils import seeding
import numpy as np
import random
import xlrd
from datetime import datetime
import os.path
import os
from openpyxl.reader.excel import load_workbook
from tkinter import _flatten

class Environ():

    def __init__(self):

        #设置参数
        self.C = 6     #边缘的最大存储容量
        self.U = 5     #边缘覆盖范围内的用户数量
        self.N = 10    #视频的数量
        self.l = 1.0   #本地到服务器的单位延迟
        self.p = 1.0   #本地到服务器的单位流量成本

        self.alpha = 0.8  #对延迟的关注度

        self.seed()
        self.state = None

        self.min_action = np.zeros(self.N)
        self.max_action = np.ones(self.N)

        self.steps = 0
        self._max_episode_steps = 12  #暂设
        self.steps_beyond_done = None

        self.min_observation = [-1 for _ in range(self.C + self._max_episode_steps * self.U)]
        self.min_observation = np.array(self.min_observation)
        self.min_observation = np.append(self.min_observation, 0)
        self.max_observation = [self.N-1 for _ in range(self.C + self._max_episode_steps * self.U)]
        self.max_observation = np.array(self.max_observation)
        self.max_observation = np.append(self.max_observation, 11)

        self.action_space = spaces.Box(
            low=self.min_action,
            high=self.max_action
        )
        self.observation_space = spaces.Box(
            low=self.min_observation,
            high=self.max_observation
        )

        #choice中用类似队列的形式来记录已存储的视频下标
        self.start = 0
        self.length = 0
        self.choice = [-1 for _ in range(self.C)]

    def seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def step(self, action):

        #判断动作是否符合规范
        assert np.array(action) in self.action_space,"%r (%s) invalid" % (action, type(action))
        sum = 0
        for i in range(len(action)):
            sum = sum + action[i]
        assert sum == 1 , "%r (%s) invalid" % (action, "每次只缓存一个视频")

        uservideo = [[3,3,3,5,5,5,6,6,2,2,9,9],
                 [2,2,0,0,0,4,4,1,1,8,8,8],
                 [7,7,7,4,4,3,3,6,6,6,2,2],
                 [4,4,4,2,2,2,8,8,8,5,5,5],
                 [3,3,3,2,2,6,6,4,4,0,0,0]]
        uservideo = np.array(uservideo)
        uservideoOne = uservideo.flatten()

        done = self.steps >= self._max_episode_steps
        done = bool(done)
        ind = -1  #做的动作，缓存的那个视频，得到其下标
        for i in range(self.N):
            if action[i] == 1:
                ind = i

        if not done:
            #edge缓存的视频没有被缓存过
            if ind not in self.choice:
                if self.length < self.C:
                    self.length += 1
                elif self.length == self.C:
                    self.start = (self.start + 1) % self.C
                else:
                    raise RuntimeError()
                self.choice[(self.start + self.length - 1) % self.C] = ind

            #5个用户的奖赏
            userReward = [0]*self.U
            for i in range(self.U):
                for j in range(self.N):
                    if j in uservideo[i]:
                        if j in self.choice:  #如果用户观看的视频在边缘里的话，奖赏更高，给一个正值奖赏
                            userReward[i] += 5
                        else:  #如果用户观看的视频不在边缘里的话，延迟更高，奖赏更低
                            userReward[i] += -(self.alpha * self.l + (1-self.alpha) * self.p)

            reward = 0.0
            print("self.steps,uservideo,action,self.choice,userReward:",self.steps,uservideo,action,self.choice,userReward)
            for i in range(self.U):
                reward = reward + userReward[i]
            self.steps += 1

        elif self.steps_beyond_done is None:
            # Pole just fell!
            self.steps_beyond_done = 0
            reward = -(self.alpha * self.l + (1-self.alpha) * self.p)
        else:
            if self.steps_beyond_done == 0:
                logger.warn("""
You are calling 'step()' even though this environment has already returned
done = True. You should always call 'reset()' once you receive 'done = True'
Any further steps are undefined behavior.
                """)
            self.steps_beyond_done += 1
            reward = -(self.alpha * self.l + (1-self.alpha) * self.p)

        self.state = np.append(self.choice,uservideoOne)
        #original_time = datetime.now()
        a = random.randint(0, self._max_episode_steps-1)
        self.state = np.append(self.state,a)

        return np.array(self.state), reward, done, {}

    def reset(self):
        #边缘中已经缓存了哪些视频
        self.Choice = [-1 for _ in range(self.C)]
        resetChoiceNum = np.random.randint(self.C+1)    #边缘中已缓存视频的数量
        resetChoiceIndex = random.sample(range(0,self.N),resetChoiceNum)      #边缘中已缓存视频的下标
        for i in range(resetChoiceNum):
            self.Choice[i] = resetChoiceIndex[i]

        #用户观看的视频情况
        resetUservideo = [[random.randint(-1, self.N-1) for j in range(self._max_episode_steps)] for i in range(self.U)]
        resetUservideo = np.array(resetUservideo)
        resetUservideoOne = resetUservideo.flatten()

        self.state = np.append(self.Choice,resetUservideoOne)
        #original_time = datetime.now()
        a = random.randint(0, self._max_episode_steps-1)
        self.state = np.append(self.state,a)

        return np.array(self.state)


def test_migration(write, finalize, assert_model):
    write({"type": "create", "fqid": "motion_state/1", "fields": {"f": 1}})
    write({"type": "update", "fqid": "motion_state/1", "fields": {"f": 2}})
    write({"type": "delete", "fqid": "motion_state/1"})
    write({"type": "restore", "fqid": "motion_state/1"})

    finalize("0003_motion_state_dont_set_identifier")

    assert_model(
        "motion_state/1",
        {
            "dont_set_identifier": False,
            "f": 1,
            "meta_deleted": False,
            "meta_position": 1,
        },
        position=1,
    )
    assert_model(
        "motion_state/1",
        {
            "dont_set_identifier": False,
            "f": 2,
            "meta_deleted": False,
            "meta_position": 2,
        },
        position=2,
    )
    assert_model(
        "motion_state/1",
        {
            "dont_set_identifier": False,
            "f": 2,
            "meta_deleted": True,
            "meta_position": 3,
        },
        position=3,
    )
    assert_model(
        "motion_state/1",
        {
            "dont_set_identifier": False,
            "f": 2,
            "meta_deleted": False,
            "meta_position": 4,
        },
        position=4,
    )


# Store the file path associated with the file (note the backslash may be OS specific)
import os
import csv

#csv_path = 'Resources/budget_data.csv'
csv_path = os.path.join('Resources', 'budget_data.csv')

with open(csv_path) as csv_file:

    # CSV reader specifies delimiter and variable that holds contents
    csv_reader = csv.reader(csv_file, delimiter=',')

    # Skip Header
    csv_header = next(csv_reader)
    total_months = 0
    total_amount = 0
    previous_amount = 0
    current_amount = 0
    changes = {}
    total_change = 0
    average_change = 0
    max_change = 0
    min_change = 0

    print ("Financial Analysis\n------------------")

    for row in csv_reader:
        current_amount = row[1]

        #Calculate change in "Profit/Losses" from a previous period after the first month.
        if total_months > 0:
            changes.update({row[0]: (int(current_amount) - int(previous_amount))})

        # The total number of months included in the dataset
        total_months = total_months + 1

        # The net total amount of "Profit/Losses" over the entire period
        total_amount = total_amount + int(current_amount)

        # Set value for the next iteration
        previous_amount = current_amount

    for (month, change) in changes.items():
        # The total change in "Profit/Losses"
        total_change = total_change + change

    #The average of the changes in "Profit/Losses" over the entire period. Make sure to devide total_change by n-1

    average_change = total_change/(total_months-1)

    # The greatest increase in profits (date and amount) over the entire period
    max_change = max(changes.items(), key=lambda x : x[1])

    # The greatest decrease in losses (date and amount) over the entire period
    min_change = min(changes.items(), key=lambda x : x[1])

    #Print results
    print (f"Total Months: {total_months}")
    print (f"Total: ${total_amount}")
    print (f"Average Change: ${round(average_change,2)}")
    print (f"Greatest Increase in Profits: {max_change[0]} (${max_change[1]})")
    print (f"Greatest Decrease in Profits: {min_change[0]} (${min_change[1]})")

    # In addition, your final script should both print the analysis to the terminal and export a text file with the results.
    with open('results.txt', 'w') as output_file:
        output_file.write ("Financial Analysis\n------------------\n")
        output_file.write (f"Total Months: {total_months}\n")
        output_file.write (f"Total: ${total_amount}\n")
        output_file.write (f"Average Change: ${round(average_change,2)}\n")
        output_file.write (f"Greatest Increase in Profits: {max_change[0]} (${max_change[1]})\n")
        output_file.write (f"Greatest Decrease in Profits: {min_change[0]} (${min_change[1]})")


# leetcode 76 最小覆盖子串，双指针（滑动窗口），附带证明
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(s) == 0 or len(t) == 0 or len(s) < len(t):
            return ""
        target = {}
        for char in t:
            target[char] = target[char]+1 if char in target else 1
        def cover(temp):
            return all(key in temp and temp[key]>=target[key] for key in target)
        l, r, temp= 0, 0, {s[0]:1}
        res = s + '@'
        while r < len(s):
            if cover(temp):
                if len(res) > r-l+1: #左开右闭
                    res = s[l:r+1]
                temp[s[l]] -= 1
                l += 1
            else:
                r += 1
                if r == len(s):
                    break
                temp[s[r]] = temp[s[r]] + 1 if s[r] in temp else 1
        if len(res) > len(s):
            return ""
        return res
# 尝试证明正确性
# 由于连续性 一定存在一个时刻 r == r_T。 此刻l有 （a）l <= l_T 和 （b）l > l_T两种情况，
# 第一种情况(a)继续执行算法即可找到最优解，第二种情况(b)（l, r_T）,还是由于连续性依据，一定是由
# （c）(l_T, r_T)或（d）(l_T, r'<r_T)发育而来，但是根据算法和最小覆盖的条件，(d)会变成（c）,
# （c）不能变成（b）。故（b）不存在，即同时满足连续性和算法的条件下不会生成（b）这种情况。所以一定会演变成
# （a）这种情况然后获得最优解

# leetcode 209 最小区间使之和大于一定值，也是双指针滑动窗口的思路


import random

class Deck:

    def __init__(self):
        self.deck = list()

    def create_deck(self):
        cardSuits = ('Hearts', 'Diamonds', 'Clubs', 'Spades')
        cardRanks = ('Two', 'Three', 'Four', 'Five', 'Six', 'Seven',
                     'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace')
        cardValues = {"Two": 2, "Three": 3, "Four": 4, "Five": 5, "Six": 6, "Seven": 7, "Eight": 8, "Nine": 9, "Ten": 10,
                      "Jack": 10, "Queen": 10, "King": 10, "Ace": 11}

        for suit in cardSuits:
            for rank in cardRanks:
                self.deck.append(suit + ' ' + rank)
        random.shuffle(self.deck)

    # Deals the top card to the player.

    def deal_cards(self, player):
        player.hand.append(self.deck.pop(0))


import glob
import logging
import os.path as op
from datetime import datetime
from os import makedirs, remove
from typing import Optional
from zipfile import ZipFile, BadZipFile

from django.conf import settings

from addcorpus import extract, filters
from addcorpus.corpus import FieldDefinition, XMLCorpusDefinition
from addcorpus.es_mappings import keyword_mapping, main_content_mapping
from addcorpus.es_settings import es_settings

logger = logging.getLogger('indexing')

def rdf_description_extractor(tag, section='xml', **kwargs):
    '''rdf:Description extractor
    There are two rdf:Description tags available in the data:
        - description about the open data enrichment
        - description about the source
    There is only deterministic way to select the right one:
        - check the dcterms:format sibling tag'''
    return extract.XML(
        tag=tag,
        secondary_tag={'tag': 'dcterms:format', 'exact': f'text/{section}'},
        **kwargs
    )

class Rechtspraak(XMLCorpusDefinition):
    title = "Judicial system Netherlands"
    description = "Open data of (anonymised) court rulings of the Dutch judicial system"
    min_date = datetime(year=1900, month=1, day=1)
    max_date = datetime(year=2022, month=12, day=6)
    data_directory = settings.RECHTSPRAAK_DATA
    es_index = getattr(settings, 'RECHTSPRAAK_ES_INDEX', 'rechtspraak')
    image = 'rechtszaal.jpeg'
    description_page = 'rechtspraak.md'
    toplevel_zip_file = 'OpenDataUitspraken.zip'
    languages = ['nl']
    category = 'ruling'

    @property
    def es_settings(self):
        return es_settings(self.languages[:1], stopword_analysis=True, stemming_analysis=True)

    tag_toplevel = 'open-rechtspraak'

    def unpack(self,
               min_year: Optional[int] = None,
               max_year: Optional[int] = None,
               how: str = 'full',
               per_year: int = 5,
               per_archive: int = 5
               ):
        if not min_year:
            min_year = self.min_date.year
        if not max_year:
            max_year = self.max_date.year

        years = range(min_year, max_year+1)

        logger.info(f'Started unpacking with strategy: {how}')
        toplevel_file = op.join(self.data_directory, self.toplevel_zip_file)
        if not op.isfile(toplevel_file):
            logger.error(f'File {toplevel_file} does not exist, aborting.')
            raise FileNotFoundError()

        unpack_dir = op.join(self.data_directory, 'unpacked')
        makedirs(unpack_dir, exist_ok=True)

        # the toplevel archive contains folders per year
        # each containing more archives
        with ZipFile(toplevel_file, 'r') as zf:
            zipnames = zf.namelist()

            # process these per year
            years_archives = {
                year: [zn for zn in zipnames if zn.startswith(f'{year}/')]
                for year in years
            }

            # filter out empty years
            years_archives = {
                year: archives
                for year, archives in years_archives.items()
                if archives
            }

            # unpack a number of nested archives for each year
            # if unpacking a sample, limit to per_year
            for year, archives in years_archives.items():
                if how == 'sample':
                    archives = archives[:min(per_year, len(archives))]
                logger.info(
                    f'Unpacking year {year}, {len(archives)} archives.')
                for arch in archives:
                    # unpack the nested archive
                    if not op.exists(op.join(unpack_dir, arch)):
                        zf.extract(arch, unpack_dir)
                    else:
                        logger.warning(
                            f'Skipped existing {op.join(unpack_dir, arch)}')

                    # finally, unpack the nested archive
                    # containing XML data files
                    # if unpacking a sample, limit to per_archive
                    try:
                        with ZipFile(op.join(unpack_dir, arch)) as nestedz:
                            target_dir = op.join(unpack_dir, str(year))
                            if how == 'sample':
                                members = nestedz.namelist()
                                to_extract = members[:min(
                                    per_archive, len(members))]
                                nestedz.extractall(
                                    target_dir, members=to_extract)
                            else:
                                nestedz.extractall(target_dir)
                            remove(op.join(unpack_dir, arch))
                    except BadZipFile:
                        logger.warning(
                            f'skipping bad file {op.join(unpack_dir, arch)}')

    def sources(self, min_date: Optional[int] = None, max_date: Optional[int] = None):
        if not min_date:
            min_date = self.min_date
        if not max_date:
            max_date = self.max_date

        for year in range(min_date.year, max_date.year+1):
            glob_pattern = f'{self.data_directory}/unpacked/{year}/*.xml'
            files = glob.glob(glob_pattern)
            for f in files:
                yield f, {'year': year}

    fields = [
        FieldDefinition(
            name='id',
            display_name='ID',
            description='',
            es_mapping=keyword_mapping(),
            extractor=rdf_description_extractor('dcterms:identifier'),
            csv_core=True,
        ),
        FieldDefinition(
            name='has_content',
            display_name='Has text content',
            description='Document has available text content.',
            es_mapping={'type': 'boolean'},
            extractor=extract.Backup(
                extract.XML('uitspraak', flatten=True),
                extract.XML('conclusie', flatten=True),
                extract.Constant(False),
                transform=bool
            ),
            search_filter=filters.BooleanFilter(
                true='has content',
                false='does not have content',
                description=(
                    'Accept only articles that have available text content.'
                )
            ),
        ),
        FieldDefinition(
            name='year',
            display_name='Year',
            es_mapping={'type': 'integer'},
            extractor=extract.Metadata('year'),
            search_filter=filters.RangeFilter(min_date.year, max_date.year)
        ),
        FieldDefinition(
            name='date',
            display_name='Date',
            extractor=rdf_description_extractor('dcterms:date'),
            es_mapping={'type': 'date', 'format': 'yyyy-MM-dd'},
            results_overview=True,
            primary_sort=True,
            csv_core=True,
            search_filter=filters.DateFilter(
                min_date,
                max_date,
                description=(
                    'Accept only rulings with date in this range.'
                )
            ),

        ),
        FieldDefinition(
            name='issued',
            display_name='Publication Date',
            extractor=rdf_description_extractor('dcterms:issued'),
            es_mapping={'type': 'date', 'format': 'yyyy-MM-dd'},
            search_filter=filters.DateFilter(
                min_date,
                max_date,
                description=(
                    'Accept only rulings with publication date in this range.'
                )
            ),
        ),
        FieldDefinition(
            name='publisher',
            display_name='Publisher',
            extractor=rdf_description_extractor('dcterms:publisher'),
            es_mapping={'type': 'keyword'}
        ),
        FieldDefinition(
            name='creator',
            display_name='Court',
            extractor=rdf_description_extractor('dcterms:creator'),
            es_mapping={'type': 'keyword'},
            csv_core=True,
            results_overview=True,
            search_filter=filters.MultipleChoiceFilter(
                description='Accept only rulings of selected courts.',
                option_count=9999
            ),
            visualizations=['resultscount', 'termfrequency']
        ),
        FieldDefinition(
            name='zaaknr',
            display_name='Case Number',
            es_mapping=keyword_mapping(),
            extractor=rdf_description_extractor('psi:zaaknummer')
        ),
        FieldDefinition(
            name='type',
            display_name='Type',
            extractor=rdf_description_extractor('dcterms:type'),
            es_mapping={'type': 'keyword'},
            csv_core=True,
            results_overview=True,
            search_filter=filters.MultipleChoiceFilter(
                description='Accept only rulings of selected type.',
                option_count=2
            ),
            visualizations=['resultscount', 'termfrequency']
        ),
        FieldDefinition(
            name='procedure',
            display_name='(type of) Procedure',
            extractor=rdf_description_extractor('psi:procedure'),
            csv_core=True,
            es_mapping={'type': 'keyword'},
            search_filter=filters.MultipleChoiceFilter(
                description='Accept only rulings of selected procedure type.',
                option_count=44
            ),
            visualizations=['resultscount', 'termfrequency']
        ),
        FieldDefinition(
            name='spatial',
            display_name='Location',
            es_mapping=keyword_mapping(),
            extractor=rdf_description_extractor('dcterms:spatial')
        ),
        FieldDefinition(
            name='subject',
            display_name='Area of law',
            extractor=rdf_description_extractor('dcterms:subject'),
            csv_core=True,
            es_mapping={'type': 'keyword'},
            search_filter=filters.MultipleChoiceFilter(
                description='Accept only rulings within this area of law.',
                option_count=32
            ),
            visualizations=['resultscount', 'termfrequency']
        ),
        FieldDefinition(
            name='title',
            display_name='Title',
            extractor=rdf_description_extractor(
                'dcterms:title', section='html'),
            results_overview=True,
            search_field_core=True,
        ),
        FieldDefinition(
            name='abstract',
            display_name='Abstract',
            extractor=extract.XML(tag='inhoudsindicatie', flatten=True),
            results_overview=True,
        ),
        FieldDefinition(
            name='content',
            display_name='Content',
            display_type='text_content',
            es_mapping=main_content_mapping(True, True, True, 'nl'),
            extractor=extract.Backup(
                extract.XML('uitspraak', flatten=True),
                extract.XML('conclusie', flatten=True),
                extract.Constant('Content not available')
            ),
            csv_core=True,
            search_field_core=True,
        ),
        FieldDefinition(
            name='url',
            display_name='URL',
            es_mapping=keyword_mapping(),
            extractor=rdf_description_extractor(
                'dcterms:identifier', section='html')
        )
    ]


# file:         request_validation.py
# description:  Utility functions to verify required API request parameters

from flask import request

def required_query_params(request, parameters):
  """Validate that a set of query parameters are present in a request"""
  for expected_param in parameters:
    received_param = request.args.get(expected_param)
    if received_param is None:
      message = { 'message': 'required query parameter \'{0}\' is missing'.format(expected_param) }
      status_code = 400 # 400 status = bad request, missing parameter
      return message, status_code