from flask import Flask, jsonify, request
from pymongo import MongoClient
from bson import json_util
from datetime import datetime
import sys
import uuid
import json
from flask_cors import CORS
import timedelta
import itertools
from datetime import datetime, timedelta
import openai
from flask_sslify import SSLify

openai.api_key = ""

def generate_quote(event):

    if event["progress"] == 1: #doing
        prompt = f"Generate a creative motivational quote within 13 words for completing the ongoing task '{event['title']}' with the description '{event['description']}'"
        response = openai.Completion.create(
            engine="text-davinci-003" ,
            prompt=prompt,
            max_tokens=1024,
            n=1,
            stop=None,
            temperature=0.8,
            )
        return response.choices[0].text.strip()

    if event["progress"] == 0: #done
        prompt = f"Generate a creative appreciation quote within 13 words for finishing the task '{event['title']}' with the description '{event['description']}'"
        response = openai.Completion.create(
            engine="text-davinci-003" ,
            prompt=prompt,
            max_tokens=1024,
            n=1,
            stop=None,
            temperature=0.5,
            )

        return response.choices[0].text.strip()

    if event["progress"] == 2: #overdue
        prompt = f"Generate a creative motivating quote within 13 words for the overdue task '{event['title']}' with the description '{event['description']}'"
        response = openai.Completion.create(
            engine="text-davinci-003" ,
            prompt=prompt,
            max_tokens=1024,
            n=1,
            stop=None,
            temperature=0.8,
            )
        quote = response.choices[0].text.strip()
        return quote

    if event["progress"] == 3: #upcoming
        prompt = f"Generate a creative motivating quote within 13 words for the upcoming task with title as '{event['title']}' and the description '{event['description']}'"
        response = openai.Completion.create(
            engine="text-davinci-003" ,
            prompt=prompt,
            max_tokens=1024,
            n=1,
            stop=None,
            temperature=0.8,
            )
        quote = response.choices[0].text.strip()
        return quote

def printf(x):
    print(x, file=sys.stderr)
    #app.logger.info(x)
printf("Running!")
def parse_json(data):
    return json.loads(json_util.dumps(data))

app = Flask(__name__)
CORS(app)
sslify = SSLify(app)

client = MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
collection = db["mycollection"]

# with collection.watch() as stream:
#     for change in stream:
#         printf(change)

collection.delete_many({})

unique_id = str(uuid.uuid4())
one = {
        "id": unique_id,
        'title' :  'Gym',
        'description' : 'Hit the Gym',
        'date' : "2023-04-01",
        'duration' : '2',
        'deadline' : "2023-04-01",
        'type' : 'Personal',
        "progress": 0,

}

unique_id = str(uuid.uuid4())
quote1 = generate_quote({'title' :  'Machine Learning Project',
        'description' : 'Implementing exchange rate prediction using different regression models and choosing the best from them',
        "progress": 1})
two = {
        "id": unique_id,
        'title' :  'Machine Learning Project',
        'description' : 'Implementing exchange rate prediction using different regression models and choosing the best from them',
        'date' : "2023-04-01",
        'duration' : '8',
        'deadline' : "2023-04-10",
        'type' : 'Personal',
        "progress": 1,
        "quote": quote1
}

quote2 = generate_quote({        'title' :  'Deep Learning',
        'description' : 'Implementing exchange rate prediction using different regression models and choosing the best from them',
        "progress": 2})
two = {
        "id": unique_id,
        'title' :  'Deep Learning',
        'description' : 'Implementing exchange rate prediction using different regression models and choosing the best from them',
        'date' : "2023-04-01",
        'duration' : '8',
        'deadline' : "2023-04-10",
        'type' : 'Personal',
        "progress": 2,
        "quote": quote2
}
collection.insert_one(one)
collection.insert_one(two)

printf(collection)

def fetch():
    data = []
    printf(collection.find())
    blocks = collection.find()

    data = []
    for block in blocks:
        data.append(block)
    printf(data)
    json_data = parse_json(data)

    # Print the JSON string
    print(json_data)
    return {"data":json_data}

@app.route("/")
def route():
    return "Hello World!"

@app.route("/api/clearall")
def clear():
    collection.delete_many({})
    return "Cleared all"

@app.route("/api/create", methods=["POST", "GET"])
def create():
    data = request.json
    unique_id = str(uuid.uuid4())
    #deadline = datetime.strptime(data["deadline"], "%Y-%m-%d")
    try:
        my_data = {
                        "id": unique_id,
                        "title": data.get('title'),
                        "description": data.get('description'),
                        "duration": data.get('duration'),
                        "date": str("2023-04-01"),
                        "deadline": data.get('deadline'),
                        "type": data.get('type'),
                        "progress": 0
                    }
        quote = generate_quote(my_data)
        my_data = {
                        "id": unique_id,
                        "title": data.get('title'),
                        "description": data.get('description'),
                        "duration": data.get('duration'),
                        #"date": str(datetime.today().replace(microsecond=0)),
                        "date": str("2023-04-01"),
                        "deadline": data.get('deadline'),
                        "type": data.get('type'),
                        "progress": 0,
                        "quote": quote
                    }

        collection.insert_one(my_data)
        x = parse_json({"data": my_data})

        return x

    except Exception as e:
        printf(e)
        return ({"Exception": "ERRROROROROROROROOR" + e})

@app.route("/api/read", methods=["POST", "GET"])
def read():
    data = []
    printf(collection.find())
    blocks = collection.find()

    data = []
    for block in blocks:
        data.append(block)
    printf(data)
    json_data = parse_json(data)

    # Print the JSON string
    print(json_data)
    return {"data":json_data}

@app.route("/api/update", methods=["POST", "GET"])
def update():
    data = request.json
    blocks = collection.find()

    old_data = []
    quote = ""
    for block in blocks:
        old_data.append(block)
    if old_data["progress"] != data["progress"]:
        quote = generate_quote(data)

    my_query = {
        "id": data["id"]}

    new_values = {"$set": {
        "title": data.get('title'),
        "description": data.get("description"),
        "duration": data.get("duration"),
        "date": data.get("date"),
        "deadline": data.get("deadline"),
        "type": data.get("type"),
        "progress": data.get("progress"),
        "quote": quote
    }}
    collection.update_one(my_query, new_values)
    return {"data": new_values}

@app.route("/api/delete", methods=["POST", "GET"])
def delete():
    data = request.json
    my_query = {"id": data["id"]}
    collection.delete_one(my_query)
    return "Data deleted successfully!"

@app.route("/api/optimize")
def optimize():
    d = fetch()
    data = fetch()["data"]
    #printf(type(data))
    events = [
        {"id": 1, "title": "Event A", "duration": 2, "deadline": "2023-04-10"},
        {"id": 2, "title": "Event B", "duration": 3, "deadline": "2023-04-05"},
        {"id": 3, "title": "Event C", "duration": 1, "deadline": "2023-04-07"},
        {"id": 4, "title": "Event D", "duration": 2, "deadline": "2023-04-12"},
        {"id": 5, "title": "Event E", "duration": 1, "deadline": "2023-04-09"}
    ]
    events = []

    for i in data:
        #printf(data)
        events.append(data)
    printf("FUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK\n")
    printf(events)
    # Step 1: Sort the events by deadline
    events_list = list(itertools.chain.from_iterable(events))
    printf(events_list)
    events = sorted(events_list, key=lambda x: x["deadline"])

    # Step 2: Assign priority scores to each event based on deadline
    for i, event in enumerate(events):
        event["priority"] = i

    # Step 3: Initialize the scheduling queue with all events
    scheduling_queue = events.copy()

    # Step 4: Schedule events based on priority score
    current_time = datetime.strptime("2023-04-01", "%Y-%m-%d")  # Set initial time as a datetime object
    while scheduling_queue:
        # Select the event with the highest priority score
        next_event = max(scheduling_queue, key=lambda x: x["priority"])
        # Convert the deadline string to a datetime object
        deadline = datetime.strptime(next_event["deadline"], "%Y-%m-%d")
        # Check if there is enough time to complete the event before the deadline
        if current_time + timedelta(days=int(next_event["duration"])) <= deadline:
            # Assign the event to the current time slot
            next_event["start_time"] = current_time
            current_time += timedelta(days=int(next_event["duration"]))
            # Remove the event from the scheduling queue
            scheduling_queue.remove(next_event)
        else:
            # Remove the event from the scheduling queue if there isn't enough time
            scheduling_queue.remove(next_event)

    # Print the scheduled events
    for event in events:
        print(event)
    return {"sorted data": events}
    return d

if __name__ == "__main__":
    app.run(host="localhost", port=5000, debug=True)


import sys
import inspect
import logging
import numpy as np
import tensorflow as tf
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from model.models import resolve_model
from model.rewards import resolve_reward
from environments.env import test_cases, resolve_env

class NES():
	"""
	Implementation of NES algorithm by OpenAI: https://arxiv.org/pdf/1703.03864.pdf
	"""

	def __init__(self, training_directory, config):
		self.config = config
		self.training_directory = training_directory
		self.env = resolve_env(self.config['environment'])(test_cases[self.config['environment']][self.config['environment_index']], self.training_directory, self.config)
		self.env.pre_processing()
		self.model = resolve_model(self.config['model'])(self.config)
		self.reward = resolve_reward(self.config['reward'])
		self.master_params = self.model.init_master_params()
		self.learning_rate = self.config['learning_rate']
		self.noise_std_dev = self.config['noise_std_dev']
		logging.info("\nReward:")
		logging.info(inspect.getsource(self.reward) + "\n")

	def run_simulation(self, sample_params, model, population, master=False):
		"""
		Black box interaction with environment using model as the action decider given environmental inputs.
		Args:
		    sample_params (tensor): Master parameters jittered with gaussian noise
		    model (tensor): The output layer for a tensorflow model
		Returns:
			reward (float): Fitness function evaluated on the completed trajectory
		"""
		with tf.Session() as sess:
			reward = 0
			valid = False
			for t in range(self.config['n_timesteps_per_trajectory']):
				inputs = np.array(self.env.inputs(t)).reshape((1, self.config['input_size']))
				net_output = sess.run(model, self.model.feed_dict(inputs, sample_params))
				action = net_output
				if self.env.discrete:
					action = np.argmax(net_output)
				valid = self.env.act(action, population, sample_params, master)
			reward += self.reward(self.env.reward_params(valid))
			success = self.env.reached_target()
			self.env.reset()
			return reward, success

	def update(self, noise_samples, rewards, n_individual_target_reached):
		"""
		Update function for the master parameters (weights and biases for neural network)
		Args:
		    noise_samples (float array): List of the noise samples for each individual in the population
		    rewards (float array): List of rewards for each individual in the population
		"""
		normalized_rewards = (rewards - np.mean(rewards))
		if np.std(rewards) != 0.0:
			normalized_rewards = (rewards - np.mean(rewards)) / np.std(rewards)

		learning_decay_rate = 1.0 - (float(n_individual_target_reached)/float(self.config['n_individuals']))
		noise_decay_rate = 1.0 - np.sqrt((float(n_individual_target_reached)/float(self.config['n_individuals'])))
		self.learning_rate *= learning_decay_rate
		self.noise_std_dev *= noise_decay_rate
		logging.info("Learning Rate: {}".format(self.learning_rate))
		logging.info("Noise Std Dev: {}".format(self.noise_std_dev))

		self.master_params += (self.learning_rate / (self.config['n_individuals'] * self.noise_std_dev)) * np.dot(noise_samples.T, normalized_rewards)

	def run(self):
		"""
		Run NES algorithm given parameters from config.
		"""
		model = self.model.model()
		n_reached_target = []
		population_rewards = []
		for p in range(self.config['n_populations']):
			logging.info("Population: {}\n{}".format(p+1, "="*30))
			noise_samples = np.random.randn(self.config['n_individuals'], len(self.master_params))
			rewards = np.zeros(self.config['n_individuals'])
			n_individual_target_reached = 0
			self.run_simulation(self.master_params, model, p, master=True) # Run master params for progress check, not used for training
			for i in range(self.config['n_individuals']):
				logging.info("Individual: {}".format(i+1))
				sample_params = self.master_params + noise_samples[i]
				rewards[i], success = self.run_simulation(sample_params, model, p)
				n_individual_target_reached += success
				logging.info("Individual {} Reward: {}\n".format(i+1, rewards[i]))
			self.update(noise_samples, rewards, n_individual_target_reached)
			n_reached_target.append(n_individual_target_reached)
			population_rewards.append(sum(rewards)/len(rewards))
			self.plot_graphs([range(p+1), range(p+1)], [population_rewards, n_reached_target], ["Average Reward per population", "Number of times target reached per Population"], ["reward.png", "success.png"], ["line", "scatter"])
		self.env.post_processing()
		logging.info("Reached Target {} Total Times".format(sum(n_reached_target)))

	def plot_graphs(self, x_axes, y_axes, titles, filenames, types):
		for i in range(len(x_axes)):
			plt.title(titles[i])
			if types[i] == "line":
				plt.plot(x_axes[i], y_axes[i])
			if types[i] == "scatter":
				plt.scatter(x_axes[i], y_axes[i])
				plt.plot(np.unique(x_axes[i]), np.poly1d(np.polyfit(x_axes[i], y_axes[i], 1))(np.unique(x_axes[i])), 'r--')
			plt.savefig(self.training_directory + filenames[i])
			plt.clf()


from datetime import datetime, timedelta

from django.core.mail import send_mail
from celery import shared_task

from config import settings
from users.models import User

@shared_task
def send_notification_task(course_title, recipient_list):
    """
    Рассылает письма пользователям об обновлении материалов курса при активной подписке.
    """
    send_mail(
        subject=f'Обновления в курсе {course_title}!',
        message=f'В курсе {course_title} произошли обновления, посетите наш сайт.',
        from_email=settings.EMAIL_HOST_USER,
        recipient_list=recipient_list
    )

@shared_task
def check_user_last_login_task():
    """
    Периодическая задача. Проверяет пользователей по дате последнего входа по паролю
    и если пользователь не заходил более месяца, блокирует его.
    """
    for user in User.objects.all():
        if user.last_login:
            delta = datetime.now() - user.last_login.replace(tzinfo=None)
            if delta > timedelta(days=30):
                user.is_active = False
                user.save()


from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

scoresheet = pd.read_csv(Path(__file__).parent / "all_subjects_results.txt", sep="\t")
df = (
    scoresheet.groupby("question_idx")[
        ["gpt4_correct", "gpt4cot_correct", "smartgpt_correct"]
    ]
    .mean()
    .melt()
)
df["value"] *= 100

# Make the plot larger
plt.figure(figsize=(5, 3.5))

# Plotting all the values as dots
sns.stripplot(x="variable", y="value", data=df, jitter=True, color="black")

# Plotting the mean values with error bars
sns.barplot(
    x="variable", y="value", data=df, ci="sd", capsize=0.2, palette="hls", errwidth=1
)

# Add labels
plt.title("Mean scores for 57-subject testing\n(1 question per subject)")
plt.ylabel("Score (% correct)")
plt.xlabel("Model")
plt.xticks(np.arange(3), ["GPT-4", "GPT-4 CoT", "SmartGPT"])

plt.ylim(df.value.min() - 1, df.value.max() + 1)

plt.tight_layout()
plt.savefig(Path(__file__).parent.parent / "assets/all_subjects.png")


#!/usr/bin/env python
import keras_segmentation
from keras_segmentation.predict import model_from_checkpoint_path
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" # Hides the pygame version, welcome msg
from os.path import expanduser
import argparse

parser = argparse.ArgumentParser(description="Run evaluation of model on a set of images and annotations.")
parser.add_argument("--model_path", default = os.path.expanduser('~')+"/Third_Paper/Datasets/pre-trained_weights/segnet_weights/segnet", help = "Prefix of model filename")
parser.add_argument("--train_images_path", default = os.path.expanduser('~')+"/Third_Paper/Datasets/Frogn_Dataset/images_prepped_train/")
parser.add_argument("--train_annotations_path", default = os.path.expanduser('~')+"/Third_Paper/Datasets/Frogn_Dataset/annotations_prepped_train/")
parser.add_argument("--inp_dir_path", default = os.path.expanduser('~')+"/Third_Paper/Datasets/Frogn_Dataset/images_prepped_test/")
parser.add_argument("--out_dir_path", default = os.path.expanduser('~')+"/Third_Paper/Datasets/predicted_outputs_segnet/")
parser.add_argument("--inp_path", default = os.path.expanduser('~')+"/Third_Paper/Datasets/Frogn_Dataset/images_prepped_test/frogn_10000.png")
parser.add_argument("--pre_trained", default = "True", type=bool)
parser.add_argument("--predict_multiple_images", default = "False", type=bool)
args = parser.parse_args()

model = keras_segmentation.models.segnet.segnet(n_classes=4,  input_height=320 , input_width=640)
#pre_trained = True
#predict_multiple_images = False

if args.pre_trained:
    model = model_from_checkpoint_path(args.model_path)

else:
    model.train(
        train_images =  args.train_images_path,
        train_annotations = args.train_annotations_path,
        checkpoints_path = args.model_path, epochs=5
    )

if args.predict_multiple_images:
    out = model.predict_multiple(
          inp_dir = args.inp_dir_path,
          checkpoints_path = args.model_path,
          out_dir = args.out_dir_path
     )

else:
    out = model.predict_segmentation(
        inp= args.inp_path,
        checkpoints_path = args.model_path,
        out_fname=os.path.expanduser('~')+"/out.png"
    )

# import matplotlib.pyplot as plt
# plt.imshow(out)
# plt.show()


from sentence_transformers import SentenceTransformer, util
# from utils.extract_keywords import extract_keywords

st_model = SentenceTransformer('paraphrase-MiniLM-L6-v2', device='cuda')

def transformerSim(statements, question):
    question_embedding = st_model.encode(question, convert_to_tensor=True)

    statement_embeddings = st_model.encode(statements, convert_to_tensor=True)

    cosine_scores = util.pytorch_cos_sim(
        question_embedding, statement_embeddings)

    ranked_statements = sorted(
        zip(statements, cosine_scores.tolist()[0]), key=lambda x: x[1], reverse=True
    )

    return ranked_statements

def rankPTKBS(PTKBs, Text):
    # print(f"Sample Response: {turn['response']}")
    a = transformerSim(PTKBs, Text)
    return a

"""
a = rankPTKBS([
"I drink milk every day",
"I own a Christy Dawn leather shoe",
"I hold a bachelor's degree in sociology",
"I love formula one races",
"I love Rally races.",
"I enjoy riding bikes.",
"I like to shop.",
"I like sightseeing.",
"I own a black Harley-Davidson motorcycle.",
"My children live in Germany.",
"I live in the UK.",

], "I'm looking for a car, can you help me?")
print(a)
"""


# pyright: reportPrivateUsage=false
import json
import time
from pathlib import Path
from types import TracebackType
from typing import Any, Optional, Type, TypeVar

import httpx
from httpx._models import Request, Response

A = TypeVar("A", bound="InterceptTransport")

def json_default(obj: Any):
    if isinstance(obj, (bytes, bytearray)):
        return obj.decode(errors="ignore")
    if isinstance(obj, httpx.URL):
        return str(obj)
    if isinstance(obj, httpx.Headers):
        return dict(obj)
    return str(obj)

class InterceptTransport(httpx.AsyncBaseTransport):
    _client: httpx.AsyncClient
    _original_transport: httpx.AsyncBaseTransport

    def __init__(self, client: httpx.AsyncClient, path: Path):
        self._client = client
        self._path = path.absolute()
        assert self._path.is_dir()
        # Monkey patch the client's transport with this one
        self._original_transport = client._transport
        client._transport = self

    async def __aenter__(self: A) -> A:
        return await self._original_transport.__aenter__() # type: ignore

    async def __aexit__(
        self,
        exc_type: Optional[Type[BaseException]] = None,
        exc_value: Optional[BaseException] = None,
        traceback: Optional[TracebackType] = None,
    ) -> None:
        await self._original_transport.__aexit__(exc_type, exc_value, traceback)

    async def handle_async_request(self, request: Request) -> Response:
        ts = time.monotonic()
        fname = self._path / f"req_{ts}_{request.url.host}.json"
        with fname.open("w") as f:
            data: dict[str, Any] = {'req': {k: v for k, v in vars(request).items() if k not in ('extensions', 'stream')}, 'ts1': ts}
            try:
                response = await self._original_transport.handle_async_request(request)
                await response.aread()
                data['ts2'] = time.monotonic()
                data['resp'] = {k: v for k, v in vars(response).items() if k not in ('stream',)}
            except Exception as exc:
                data['exc'] = exc
                raise exc
            try:
                js = json.dumps(data, indent=2, default=json_default)
            except Exception as exc:
                js = f"{'error': 'Could not serialize request', 'exc': '{exc}'}"
            f.write(js)
        return response

    async def aclose(self) -> None:
        await self._original_transport.aclose()


import os, sys, re, shutil
from xml.etree.ElementTree import Element, SubElement, Comment, ElementTree, tostring

def stripMatch( str ):
	return str.replace("(","").replace(")","").replace("[","").replace("]","")

rootdir = sys.argv[1]
imagedir = sys.argv[2]

spectrumdata = {}

root = Element('gameList')
gameList = ElementTree(root)

if not (os.path.exists(os.path.join(rootdir,'images'))):
	os.mkdir(os.path.join(rootdir,'images'))

files = os.listdir(rootdir)
for file in sorted(files):
	if os.path.isfile(os.path.join(rootdir,file)):
		m = re.match("^(?P<name>[\w\s\-',\.\+\&\!\[\]]+) (?P<year>\(\d{4}\))?(?P<company>\([\w\s\-',\.\+\&\!\[\]]+\))?(?P<aka>\(aka [\w\s\-',\.\+\&\!\[\]]+\))?(?P<lang>\([a-zA-Z]{2,4}\))?(?P<spectrum>\([\s\dkK,\+32]+\))?(?P<meta>.*)\.(?P<extension>\w{3})$",file)
		if m and m.group('name'):
			game = SubElement(root, 'game')
			path = SubElement(game, 'path')
			name = SubElement(game, 'name')
			name.text = m.group('name')
			path.text = './' + file
			imagePath = os.path.join(imagedir, name.text + '.jpg').replace('..','.')
			foundImage = False
			if os.path.isfile(imagePath):
				foundImage = True
			else:
				imagePath = imagePath.replace('III','3').replace('II','2')
				if os.path.isfile(imagePath):
					foundImage = True
				else:
					n = re.match("^(?P<simpleName>[a-zA-Z \.\']+) -.*$",name.text)
					if n and n.group('simpleName'):
						simpleName = n.group('simpleName')
						imagePath = os.path.join(imagedir,simpleName + '.jpg').replace('..','.')
						if os.path.isfile(imagePath):
							foundImage = True
						else:
							imagePath = imagePath.replace('III','3').replace('II','2')
							if os.path.isfile(imagePath):
								foundImage = True
			if foundImage:
				retroPath = './images/' + name.text + '.jpg'
				destPath = os.path.join(rootdir,retroPath)
				if not os.path.isfile(destPath):
					shutil.copy(imagePath,destPath)
				image = SubElement(game,'image')
				image.text = retroPath
			else:
				print("Cannot find image for " + m.group('name') + " using " + imagePath)
			if m.group('year'):
				year = stripMatch(m.group('year'))
				releaseDate = SubElement(game,'releaseDate')
				releaseDate.text = year + '0101T000000'
			if m.group('company'):
				company = stripMatch(m.group('company'))
				publisher = SubElement(game,'publisher')
				publisher.text = company
			if m.group('aka') or m.group('meta'):
				description = SubElement(game,'desc')
				descriptionText = ""
				if m.group('aka'):
					aka = stripMatch(m.group('aka'))
					descriptionText += aka + os.linesep
				if m.group('meta'):
					meta = stripMatch(m.group('meta').replace(")["," ").replace("]["," "))
					descriptionText += meta + os.linesep
				description.text = descriptionText

gameList.write(os.path.join(rootdir,'gamelist.xml.unformatted'),'us-ascii',True)


import logging
import os
from pathlib import Path

import hydra
import nest_asyncio
from hydra.utils import instantiate
from omegaconf import DictConfig

from nuplan.common.actor_state.vehicle_parameters import VehicleParameters
from nuplan.planning.nuboard.nuboard import NuBoard
from nuplan.planning.script.builders.scenario_building_builder import build_scenario_builder
from nuplan.planning.script.builders.utils.utils_config import update_config_for_nuboard
from nuplan.planning.script.utils import set_default_path

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# If set, use the env. variable to overwrite the default dataset and experiment paths
set_default_path()

# If set, use the env. variable to overwrite the Hydra config
CONFIG_PATH = os.getenv('NUPLAN_HYDRA_CONFIG_PATH', 'config/nuboard')

if os.environ.get('NUPLAN_HYDRA_CONFIG_PATH') is not None:
    CONFIG_PATH = os.path.join('../../../../', CONFIG_PATH)

if os.path.basename(CONFIG_PATH) != 'nuboard':
    CONFIG_PATH = os.path.join(CONFIG_PATH, 'nuboard')
CONFIG_NAME = 'default_nuboard'

nest_asyncio.apply()

def initialize_nuboard(cfg: DictConfig) -> NuBoard:
    """
    Sets up dependencies and instantiates a NuBoard object.
    :param cfg: DictConfig. Configuration that is used to run the experiment.
    :return: NuBoard object.
    """
    # Update and override configs for nuboard
    update_config_for_nuboard(cfg=cfg)

    scenario_builder = build_scenario_builder(cfg)

    # Build vehicle parameters
    vehicle_parameters: VehicleParameters = instantiate(cfg.scenario_builder.vehicle_parameters)
    profiler_path = None
    if cfg.profiler_path:
        profiler_path = Path(cfg.profiler_path)

    nuboard = NuBoard(
        profiler_path=profiler_path,
        nuboard_paths=cfg.simulation_path,
        scenario_builder=scenario_builder,
        port_number=cfg.port_number,
        resource_prefix=cfg.resource_prefix,
        vehicle_parameters=vehicle_parameters,
        async_scenario_rendering=cfg.async_scenario_rendering,
        scenario_rendering_frame_rate_cap_hz=cfg.scenario_rendering_frame_rate_cap_hz,
    )

    return nuboard

@hydra.main(config_path=CONFIG_PATH, config_name=CONFIG_NAME)
def main(cfg: DictConfig) -> None:
    """
    Execute all available challenges simultaneously on the same scenario.
    :param cfg: DictConfig. Configuration that is used to run the experiment.
    """
    nuboard = initialize_nuboard(cfg)
    nuboard.run()

if __name__ == '__main__':
    main()


"""Django rest client serializers"""
from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from .models import Customer, CustomerFavoriteProduct

class CustomerBaseSerializer(serializers.ModelSerializer):
    """Serializer for user"""

    class Meta:
        model = Customer
        fields = ("id", "name", "email")

class CustomerCreateSerializer(CustomerBaseSerializer):
    """Serializer for create user"""

    email = serializers.EmailField(
        validators=[
            UniqueValidator(
                queryset=Customer.objects.all(),
                message="There is already an account with this email",
            )
        ]
    )

    class Meta:
        model = Customer
        fields = ("id", "name", "email", "password")

class CustomerUpdateSerializer(CustomerBaseSerializer):
    """Serializer for user"""

    email = serializers.ReadOnlyField()

class CustomerFavoriteProductSerializer(serializers.ModelSerializer):
    """Serializer for customer product favorite"""

    created_at = serializers.ReadOnlyField()

    class Meta:
        model = CustomerFavoriteProduct
        fields = ("product", "price", "created_at",)


# SPDX-License-Identifier: GPL-3.0-or-later
import logging
from typing import Optional

import boto3
from botocore.response import StreamingBody

log = logging.getLogger(__name__)

def get_object_from_s3_bucket(
    s3_key_prefix: str,
    s3_file_name: str,
    bucket_name: str,
) -> Optional[StreamingBody]:
    """
    Get object from AWS S3 bucket.

    :param str s3_key_prefix: the logical location of the file in the S3 bucket
    :param str s3_file_name: the name of the file in S3 bucket
    :param str bucket_name: the name of the S3 bucket to fetch the file from
    :return: the body of the S3 object or None
    :rtype: botocore.response.StreamingBody
    """
    file_name = f'{s3_key_prefix}/{s3_file_name}'
    log.info('getting file from s3 : %s', file_name)
    s3 = boto3.resource(service_name='s3')
    try:
        response = s3.meta.client.get_object(Bucket=bucket_name, Key=file_name)
    except Exception as error:
        log.exception('Unable to fetch object %s from bucket %s: %s', file_name, bucket_name, error)
        return None
    return response['Body']


from accounts.models.City import City
from accounts.api.serializers.CitySerializer import CitySerializer

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import AllowAny

class CitiesOfCountry(APIView):
    permission_classes = (AllowAny,)

    def get(self, request, pk ,  format=None):

        try:

            cities= City.objects.filter(country=pk)

            citiesDeatils = CitySerializer(cities , many=True)
            status_code = status.HTTP_200_OK
            response = { 'cities' : citiesDeatils.data , }
            return Response(response , status_code)

        except Exception as err:
            status_code = status.HTTP_404_NOT_FOUND
            response = {'error' : str (err) ,}
            return Response (response , status_code)

class AllCities(APIView):
    permission_classes = (AllowAny,)

    def get(self, request ,  format=None):

        try:

            cities= City.objects.all()

            citiesDeatils = CitySerializer(cities, many=True)

            status_code = status.HTTP_200_OK
            response = {'cities' : citiesDeatils.data ,}
            return Response(response , status_code)

        except Exception as err:
            status_code = status.HTTP_404_NOT_FOUND
            response = {'error' : str (err) ,}
            return Response (response , status_code)


#!/usr/bin/env python

import sys, os, glob, re, math

import argparse
parser = argparse.ArgumentParser(description='calculate histogram distances between a file with observed PValues and a group of files each containing the same number of P values')
parser.add_argument("--in", dest="infile", help="fisher file with P values", required=True)
parser.add_argument("--out", dest="outfile", help="output file",default="")
parser.add_argument("--comp", dest="comps", help="comparisons to retrieve (eg: \"1:4,2:5,3:6\")",required=True)
args = parser.parse_args()
comps = vars(args)['comps'].split(",")
infile = vars(args)['infile']
outfile = vars(args)['outfile']
if (outfile == ""):
    outfile = re.sub(r'\.\w+$','',infile)+".fishcomp"
inf = open(infile,"r")
f_pos={}
out = open(outfile,"w")
for line in inf:
    line.rstrip()
    fields=line.split()
    if (len(f_pos) == 0):
        for i in range(0,len(fields)):
            for j in comps:
                if (re.match(j+"=",fields[i])):
                    f_pos[j]=i
        diff_xor = set(f_pos) ^ set(comps)
        if (len(diff_xor) > 0):
            sys.exit("Field"+str(diff_xor)+" not found")
        print >>out,"\#"+"\t".join(comps)
        pos=[ f_pos[x] for x in comps]
    out_array=[ fields[x].split("=")[1] for x in pos]
    for i in range(0,len(out_array)):
        if (out_array[i] != "na"):
            out_array[i] = str(10**(-1*float( out_array[i])))
    print >>out,"\t".join(out_array)
inf.close()
out.close()


import os
import argparse
import fcntl
import time
import urllib.request, urllib.parse, urllib.error
import urllib.request, urllib.error, urllib.parse
import logging
from logging.handlers import RotatingFileHandler
import traceback
from tl_tweets import tweet_string, tweet_price
from tl_email import email
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import csv
import json
import datetime
from dateutil import parser
from dateutil.relativedelta import relativedelta
import calendar
import random
from tl_weather import get_daytime_weather_data
import requests
from bs4 import BeautifulSoup
from pythonjsonlogger import jsonlogger

# Wait time for page loads
PAGE_LOAD_TIMEOUT = 240 * 1000

# Where logging output from this tool goes. Modify path as needed
LOGFILE = os.environ.get('SOLAR_LOGFILE')
if not LOGFILE:
    LOGFILE = os.path.expanduser("~/script/logs/solarcity.log")

# Data file containing all the saved state information
DATA_FILE = "solarcity.json"

# Some of the tweets attach pictures. They're randomly chosen from this path
PICTURES_PATH = "images/solar"

# Logging setup
log = logging.getLogger(__name__)
loglevel = logging.INFO
DEF_FRMT = "%(asctime)s : %(levelname)-8s : %(funcName)-25s:%(lineno)-4s: %(message)s"
loghandler1 = RotatingFileHandler(LOGFILE, maxBytes=5 * 1024 * 1024, backupCount=8)
loghandler2 = RotatingFileHandler(LOGFILE + '.json', maxBytes=5 * 1024 * 1024, backupCount=8)
loghandler1.setFormatter(logging.Formatter(DEF_FRMT))
loghandler2.setFormatter(jsonlogger.JsonFormatter())
log.addHandler(loghandler1)
log.addHandler(loghandler2)
log.setLevel(loglevel)

# Get the collection of pictures
SOLAR_IMAGES = []
if os.path.exists(PICTURES_PATH):
    SOLAR_IMAGES = [os.path.join(PICTURES_PATH, f) for f in os.listdir(PICTURES_PATH) if not f.startswith('.')]

# Set to true to disable tweets/data file updates
DEBUG_MODE = False

# Get SolarCity information from environment
if not 'SOLARCITY_USER' in os.environ:
    raise Exception("SOLARCITY_USER missing")
else:
    SOLARCITY_USER = os.environ['SOLARCITY_USER']

# Get SolarCity referral information from environment
if not 'SOLARCITY_REFERRAL' in os.environ:
    SOLARCITY_REFERRAL = ''
else:
    SOLARCITY_REFERRAL = os.environ['SOLARCITY_REFERRAL']

# Get your SITE_ID by logging into https://solarguard.solarcity.com/Kiosk/SolarGuard.aspx and
# extract the SITE_ID from the URL once logged in
if not 'SOLARCITY_SITE_ID' in os.environ:
    raise Exception("SOLARCITY_SITE_ID missing")
else:
    SOLARCITY_SITE_ID = os.environ['SOLARCITY_SITE_ID']

# Main URL to SolarCity
SOLARCITY_URL = 'https://mysolarcity.com/Share/%s#/monitoring/historical/day' % SOLARCITY_SITE_ID

SOLARGUARD_URL = 'https://solarguard.solarcity.com/Kiosk/SolarGuard.aspx' \
                '?ID=&JID=%s' \
                '&GroupID=0' \
                '&AutoDemo=1' \
                '&Timeout=480' \
                '&Share=0' \
                '&RangeType=Day' \
                '&ChartMode=Stack' \
                '&Consumption=1' \
                '&Min=30' \
                '&ExportLifetime=0' % SOLARCITY_SITE_ID

def get_day_data(day=None):
    append = ''
    if day:
        append = '?date=%d-%02d-%02d' % (day.year, day.month, day.day)

    chrome_options = Options()
    chrome_options.add_argument("--headless")
    driver = webdriver.Chrome(options=chrome_options)
    driver.get(SOLARCITY_URL)
    time.sleep(10)
    driver.get(SOLARCITY_URL + append)
    time.sleep(10)
    data = driver.find_element(By.CSS_SELECTOR, "div.consumption-production-panel").text
    if data and len(data.split()) > 0:
        production = float(data.split()[0])
    else:
        production = 0

    if day:
        ts = datetime.datetime.combine(day, datetime.datetime.max.time()).strftime("%s")
    else:
        ts = time.time()
    ts = datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
    w = get_daytime_weather_data(log, ts)
    cloud_cover = w['cloud_cover']
    daylight_hours = w["daylight"]

    # If we get here everything worked, shut down the browser
    driver.quit()

    if os.path.exists("geckodriver.log"):
        os.remove("geckodriver.log")

    return daylight_hours, cloud_cover, production

def get_solarguard_day_data(day=None):
    append = ''
    if day:
        append = '&ChartDate=%d_%d_%d' % (day.month, day.day, day.year)
    r = requests.get(SOLARGUARD_URL + append)
    soup = BeautifulSoup(r.text, features="html.parser")

    daylight_hours = 0
    cloud_cover = 0

    production = float(soup.find(id='ctl00_cphMain_lbProdTotalByChart').text)

    if not day and production == 0 and cloud_cover == 0 and daylight_hours == 0:
        raise Exception("Problem getting current production level: %.1f, %d, %.1f" % (production,
                                                                                cloud_cover, daylight_hours))

    if daylight_hours == 0:
        """
        SolarCity has had outages where they cant provide the cloud cover/weather information.
        If the weather data appears empty here, we'll go get it from another source
        """
        if day:
            ts = datetime.datetime.combine(day, datetime.datetime.max.time()).strftime("%s")
        else:
            ts = time.time()
        ts = datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
        w = get_daytime_weather_data(log, ts)
        cloud_cover = w["cloud_cover"]
        daylight_hours = w["daylight"]

    return daylight_hours, cloud_cover, production

def solar_image():
    if SOLAR_IMAGES:
        return random.choice(SOLAR_IMAGES)

def tweet_production(daylight_hours, cloud_cover, production, special):
    if special == "high":
        extra = "A new high record :) "
    elif special == "low":
        extra = ":( A new low "
    else:
        extra = ""

    if daylight_hours and daylight_hours > 0.0:
        message = "Todays @Tesla Solar Production: %s with %.1f hrs of daylight and it was %s. %s" \
                  "#gosolar #bot %s" % \
                  (show_with_units(production), daylight_hours, cloud_cover, extra, SOLARCITY_REFERRAL)
    else:
        message = "Todays @Tesla Solar Production: %s (daylight/cloud cover not reported) %s" \
                  "#gosolar #bot %s" % \
                  (show_with_units(production), extra, SOLARCITY_REFERRAL)

    if DEBUG_MODE:
        print("Would tweet:\n%s" % message)
        log.info("DEBUG mode, not tweeting: %s", message)
    else:
        media = solar_image()
        log.info("Using media: %s", media)
        tweet_string(message=message, log=log, media=media)

def tweet_down():
    daysdown = (datetime.datetime.now() - datetime.datetime(2019, 8, 27)).days
    message = "@Tesla Solar system (17.6kW) was taken offline by @Tesla on 8/29/19, %d days ago. " \
              "No repair possible for months." % daysdown
    if DEBUG_MODE:
        print("Would tweet:\n%s" % message)
        log.info("DEBUG mode, not tweeting: %s", message)
    else:
        media = random.choice(SOLAR_IMAGES)
        log.info("Using media: %s", media)
        tweet_string(message=message, log=log, media=media)

def tweet_month(data):
    generated_this_week, generated_this_month, generated_this_year, total_generation = compute_generation_data(data)

    message = "This months @Tesla Solar Production was %s. %s generated in the last 365 days. #gosolar #bot %s" % \
              (show_with_units(generated_this_month), show_with_units(generated_this_year), SOLARCITY_REFERRAL)
    if DEBUG_MODE:
        print("Would tweet:\n%s" % message)
        log.info("DEBUG mode, not tweeting: %s", message)
    else:
        tweet_string(message=message, log=log, media=solar_image())

def tweet_year(data):
    generated_this_week, generated_this_month, generated_this_year, total_generation = compute_generation_data(data)

    message = "This years @Tesla Solar Production was %s! %s generated since install :) #gosolar #bot %s" % \
              (show_with_units(generated_this_year), show_with_units(total_generation), SOLARCITY_REFERRAL)
    if DEBUG_MODE:
        print("Would tweet:\n%s" % message)
        log.info("DEBUG mode, not tweeting: %s", message)
    else:
        tweet_string(message=message, log=log, media=random.choice(SOLAR_IMAGES))

def load_data():
    if os.path.exists(DATA_FILE):
        log.debug("Loading existing Solarcity database")
        data = json.load(open(DATA_FILE, "r"))
        log.debug("   %d entries loaded", len(data['data']))
        if 'config' not in data:
            data['config'] = {'lastdailytweet': '20010101'}
        # Manual insertion if needed
        #data['data']['20150620'] = {'production': 61.5, 'cloud': 68, 'daylight': 15.3}

    else:
        log.debug("No existing Solarcity database found")
        data = {'config': {'lastdailytweet': '20010101'}, 'data': {}}
    return data

def load_historical_data(data):
    """
    This lets you export historical data from SolarCity.com and import it into this tool to
    combine old data with current data.

    Go to your mySolarCity page and download the PowerGuide data and put it in historical.csv
    """
    if len(data['data']) < 5 and os.path.exists('historical.csv'):
        # Only need to load it once
        log.debug("Loading historical data")
        with open('historical.csv') as csvfile:
            reader = csv.DictReader(csvfile)
            for row in reader:
                if row['Energy In Interval (kWh)'] == 'NULL':
                    continue
                process_date = "%s%s%s" % (row['Timestamp'][0:4], row['Timestamp'][5:7], row['Timestamp'][8:10])
                if process_date in data['data']:
                    if 'cloud' not in data['data'][process_date]:
                        data['data'][process_date]['production'] += float(row['Energy In Interval (kWh)'])
                else:
                    data['data'][process_date] = {'production': float(row['Energy In Interval (kWh)'])}
    else:
        log.debug("Skipping load of historical data")
    return data

def populate_missing_data(data):
    today = datetime.datetime.now().date()
    first = None
    last = None
    data_changed = False
    for d in data['data']:
        t = parser.parse(d).date()
        if not first:
            first = t
        last = t
    while last < today - datetime.timedelta(days=1):
        last = last + datetime.timedelta(days=1)
        current_day = last.strftime("%Y%m%d")
        if current_day in data['data']:
            log.info("Skipping %s" % current_day)
            continue
        try:
            daylight_hours, cloud_cover, production = get_day_data(last)
        except:
            print("Error fetching %s" % last)
            continue
        log_str = "populating missing: %s: daylight: %s cloud cover: %s production: %s" % \
                  (last, daylight_hours, cloud_cover, production)
        print(log_str)
        log.info(log_str)
        data['data'][current_day] = {'daylight': daylight_hours, 'cloud': cloud_cover, 'production': production}
        data_changed = True
        save_data(data)
        upload_to_pvoutput(data, current_day)
        time.sleep(20)
    return data_changed

def analyze_data(data):
    production_max = 0
    production_max_day = None
    production_min = 999999
    production_min_day = None
    total_generation = 0

    for day in data['data']:
        d = data['data'][day]
        # Special handling here where SolarCity provided data thats not credible
        if day in ('20150610',):
            # Bad data days
            continue
        total_generation += d['production']
        if d['production'] > production_max:
            production_max = d['production']
            production_max_day = day
        if d['production'] < production_min:
            production_min = d['production']
            production_min_day = day

    log.info("Max: %s on %s, Min: %s on %s." % (show_with_units(production_max), production_max_day,
                                                 show_with_units(production_min), production_min_day))
    log.info("Total: %s" % show_with_units(total_generation))
    return production_max_day, production_min_day, total_generation

def analyze_weather(data):
    """
    SolarCity has had outages where they cant provide the cloud cover/weather information.
    This compares SolarCity reported weather data with other weather data.
    """
    print("Apple killed Dark Sky, weather not available")
    return
    # for day in sorted(data['data']):
    #     d = data['data'][day]
    #     if "weather_api" not in d:
    #         time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
    #         w = get_daytime_weather_data(log, time_value)
    #         cloud_cover = w["cloud_cover"]
    #         daylight_hours = w["daylight"]
    #         if 'cloud' in d:
    #             ss_cloud = d['cloud']
    #         else:
    #             ss_cloud = 0
    #         if 'daylight' in d:
    #             ss_daylight = d['daylight']
    #         else:
    #             ss_daylight = 0
    #
    #         print("%s Cloud: %d%% Daylight: %.1f (API Cloud: %d%%, Daylight: %.1f)" % (day, ss_cloud,
    #                                                                                ss_daylight, cloud_cover,
    #                                                                                daylight_hours))
    #     else:
    #         if 'cloud' in d:
    #             cloud_cover = d['cloud']
    #         else:
    #             cloud_cover = 0
    #         if 'daylight' in d:
    #             daylight_hours = d['daylight']
    #         else:
    #             daylight_hours = 0
    #         print("%s API Cloud: %d%% API Daylight: %.1f" % (day, cloud_cover, daylight_hours))

def save_data(data):
    log.debug("Save Solarcity database")
    if not DEBUG_MODE:
        json.dump(data, open(DATA_FILE + ".tmp", "w"))
        if os.path.exists(DATA_FILE):
            os.remove(DATA_FILE)
        os.rename(DATA_FILE + ".tmp", DATA_FILE)
    else:
        log.debug("   Skipped saving due to debug mode")
        print(data)

def show_with_units(generation):
    for units in ('kWh', 'MWh', 'GWh'):
        if generation < 1000:
            break
        generation /= 1000
    message = "{:,.1f}".format(generation)
    message += " " + units
    return message

def compute_generation_data(data):
    w = datetime.date.today() - datetime.timedelta(days=7)
    this_week = int(w.strftime("%Y%m%d"))

    m = datetime.date.today() - datetime.timedelta(days=30)
    this_month = int(m.strftime("%Y%m%d"))

    y = datetime.date.today() - datetime.timedelta(days=365)
    this_year = int(y.strftime("%Y%m%d"))

    generated_this_week = 0
    generated_this_month = 0
    generated_this_year = 0
    total_generation = 0

    log.info("   This week: %d, last month: %d, last year: %d", this_week, this_month, this_year)

    for a in data['data']:
        production = data['data'][a]['production']
        total_generation += production

        if int(a) > this_week:
            generated_this_week += production
        if int(a) > this_month:
            generated_this_month += production
        if int(a) > this_year:
            generated_this_year += production

    return generated_this_week, generated_this_month, generated_this_year, total_generation

def solarcity_report(data, no_email=False, no_tweet=False):
    log.info("Report on SolarCity Generation")
    generated_this_week, generated_this_month, generated_this_year, total_generation = compute_generation_data(data)

    message = "Hi there, below is the weekly SolarCity generation report:\n\n"
    message += "Total production this week: %s\n" % show_with_units(generated_this_week)
    message += "Total production in the last 30 days: %s\n" % show_with_units(generated_this_month)

    message += "Total production in the last 365 days: %s\n" % show_with_units(generated_this_year)

    message += "\nLifetime generation is %s.\n" % show_with_units(total_generation)
    message += "\nRegards,\n"
    message += "Teslaliving\nhttp://teslaliving.net"

    if no_email or DEBUG_MODE:
        print("Would email message:\n%s" % message)
    else:
        log.info("   email report")
        email(email=SOLARCITY_USER, message=message, subject="Weekly SolarCity Report")

    if not no_tweet:
        tweet_message = "%s generated last week with @Tesla Solar. " % show_with_units(generated_this_week)
        tweet_message += "%s generated in the last 30 days. #GoSolar #bot %s" % \
                         (show_with_units(generated_this_month), SOLARCITY_REFERRAL)
        if DEBUG_MODE:
            print("Would Tweet string:\n%s" % tweet_message)
        else:
            tweet_string(message=tweet_message, log=log, media=solar_image())

def upload_to_pvoutput(data, day):
    # Get pvoutput.org login information from environment
    if 'PVOUTPUT_ID' not in os.environ:
        raise Exception("PVOUTPUT_ID missing")
    else:
        pvoutput_id = os.environ['PVOUTPUT_ID']
    if 'PVOUTPUT_KEY' not in os.environ:
        raise Exception("PVOUTPUT_KEY missing")
    else:
        pvoutput_key = os.environ['PVOUTPUT_KEY']

    log.info("Report weather info to pvoutput.org for %s", day)

    time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
    time_value = datetime.datetime.fromtimestamp(time_value).strftime("%Y-%m-%d")
    w = get_daytime_weather_data(log, time_value)

    short_description = w["description"]
    # if "partly cloudy" in w["description"].lower():
    #     short_description = "Partly Cloudy"
    # if "mostly cloudy" in w["description"].lower():
    #     short_description = "Mostly Cloudy"
    # elif "snow" in w["description"].lower():
    #     short_description = "Snow"
    # elif "rain" in w["description"].lower():
    #     short_description = "Showers"
    # elif "clear" in w["description"].lower():
    #     short_description = "Fine"

    pvdata = {}
    pvdata["d"] = day
    pvdata["g"] = data["data"][day]["production"] * 1000
    pvdata["cd"] = short_description
    pvdata["tm"] = "%.1f" % ((w["low_temp"] - 32) * 5.0 / 9.0)
    pvdata["tx"] = "%.1f" % ((w["high_temp"] - 32) * 5.0 / 9.0)
    # pvdata["cm"] = "Daylight hours: %.1f, Cloud cover: %d%%" % (data["data"][day]["daylight"],
    #                                                             data["data"][day]["cloud"])
    pvdata["cm"] = "Daylight hours: %.1f" % (data["data"][day]["daylight"])
    data = urllib.parse.urlencode(pvdata)

    headers = {}
    headers["X-Pvoutput-Apikey"] = pvoutput_key
    headers["X-Pvoutput-SystemId"] = pvoutput_id

    req = urllib.request.Request("http://pvoutput.org/service/r2/addoutput.jsp", data.encode('utf-8'), headers)
    response = urllib.request.urlopen(req)
    output = response.read()
    log.info("   Upload response: %s", output)

def main():
    parser = argparse.ArgumentParser(description='SolarCity Reporting')
    parser.add_argument('--no_email', help='Dont send emails', required=False, action='store_true')
    parser.add_argument('--force', help='Force update', required=False, action='store_true')
    parser.add_argument('--details', help='Output detailed blog output', required=False, action='store_true')
    parser.add_argument('--no_tweet', help='Dont post tweets', required=False, action='store_true')
    parser.add_argument('--report', help='Generate report', required=False, action='store_true')
    parser.add_argument('--blog', help='Generate html report page', required=False, action='store_true')
    parser.add_argument('--daily', help='Report on daily generation', required=False, action='store_true')
    parser.add_argument('--monthly', help='Report on monthly generation', required=False, action='store_true')
    parser.add_argument('--yearly', help='Report on yearly generation', required=False, action='store_true')
    parser.add_argument('--weather', help='Report weather for given date (YYYYMMDD)', required=False, type=str)
    parser.add_argument('--pvoutput', help="Send data for date (YYYYMMDD) to PVOutput.org", required=False, type=str)
    parser.add_argument('--down', help="Tweet system down", required=False, action='store_true')
    parser.add_argument('--missing', help="Fill in missing data", required=False, action='store_true')
    args = parser.parse_args()

    # Make sure we only run one instance at a time
    if not args.blog:
        fp = open('/tmp/solarcity.lock', 'w')
        try:
            fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
        except:
            log.debug("Sorry, someone else is running this tool right now. Please try again later")
            return -1

    log.debug("--- solarcity.py start ---")

    data = load_data()
    data_changed = False

    data = load_historical_data(data)
    production_max, production_min, total_generation = analyze_data(data)

    if args.missing:
        data_changed = populate_missing_data(data)

    if args.down:
        tweet_down()

    if args.monthly:
        # First check if its last day of the month
        log.info("Check for monthly update")
        now = datetime.datetime.now()
        dow, last_day = calendar.monthrange(now.year, now.month)
        log.info("Last day of month: %d. Current day: %d", last_day, now.day)
        if last_day == now.day:
            log.info("   Last day of month.")
            current_month = time.strftime("%Y%m")
            if 'lastmonthlytweet' not in data['config'] or data['config']['lastmonthlytweet'] != current_month:
                tweet_month(data)
                data['config']['lastmonthlytweet'] = current_month
                data_changed = True
        else:
            log.info("   Not last day of month, skipping. ")

    if args.yearly:
        # First check if its last day of the year
        log.info("Check for annual update")
        now = datetime.datetime.now()
        if now.month == 12:
            dow, last_day = calendar.monthrange(now.year, now.month)
            log.info("Last day of month: %d. Current day: %d", last_day, now.day)
            if last_day == now.day:
                log.info("   Last day of year.")
                current_month = time.strftime("%Y%m")
                if 'lastyearlytweet' not in data['config'] or data['config']['lastyearlytweet'] != current_month:
                    tweet_year(data)
                    data['config']['lastyearlytweet'] = current_month
                    data_changed = True
            else:
                log.info("   Not last day of year, skipping. ")

    if args.weather is not None:
        log.info("Check weather data")
        if int(args.weather) == 0:
            int(time.time())
        else:
            time_value = time.mktime(time.strptime("%s2100" % args.weather, "%Y%m%d%H%M"))
        time_value = datetime.datetime.fromtimestamp(time_value).strftime("%Y-%m-%d")
        w = get_daytime_weather_data(log, time_value)
        print("Weather as of %s:" % datetime.datetime.fromtimestamp(time_value))
        print("   Average temperature: %.1fF" % w["avg_temp"])
        print("   Low temperature: %.1fF" % w["low_temp"])
        print("   Conditions: %s" % w["cloud_cover"])
        print("   Daylight hours: %.1f" % w["daylight"])
        print("   Description: %s" % w["description"])
        # print("   Precipitation type: %s" % w["precip_type"])
        # print("   Precipitation Chance: %d%%" % w["precip_probability"])
        analyze_weather(data)

    if args.daily:
        log.info("Check for daily update")
        current_day = time.strftime("%Y%m%d")
        if data['config']['lastdailytweet'] != current_day or DEBUG_MODE or args.force:
            daylight_hours, cloud_cover, production = get_day_data()
            data['data'][current_day] = {'daylight': daylight_hours, 'cloud': cloud_cover, 'production': production}
            special = None
            if production_max is None or production > data['data'][production_max]['production']:
                special = "high"
            elif production_min is None or production < data['data'][production_min]['production']:
                special = "low"
            if not args.no_tweet:
                tweet_production(daylight_hours, cloud_cover, production, special)
                data['config']['lastdailytweet'] = current_day
            data_changed = True
            if args.pvoutput is not None:
                # Now upload to pvoutput
                upload_to_pvoutput(data, current_day)

    elif args.pvoutput is not None:
        if int(args.pvoutput) == 0:
            print("Uploading historical data to pvoutput.org")
            for d in data["data"]:
                if int(d) < 20150224:
                    continue
                print("   Processing date %s" % d)
                try:
                    upload_to_pvoutput(data, d)
                except:
                    print("      problem with date %s" % d)
                print("      Sleeping")
                # You'll need longer sleeps if you didnt donate, try 120
                time.sleep(120)
        else:
            today = datetime.datetime.now().date()
            last = datetime.datetime.strptime(args.pvoutput, '%Y%m%d').date()
            while True:
                if last >= today - datetime.timedelta(days=1):
                    break
                current_day = last.strftime("%Y%m%d")
                error = False
                if current_day not in data["data"]:
                    try:
                        daylight_hours, cloud_cover, production = get_day_data(last)
                    except:
                        print("Error fetching %s" % last)
                        log.debug("Error fetching %s" % last)
                        error = True
                    if not error:
                        log_str = "populating missing: %s: daylight: %s cloud cover: %s production: %s" % \
                                  (last, daylight_hours, cloud_cover, production)
                        print(log_str)
                        log.info(log_str)
                        data['data'][current_day] = {'daylight': daylight_hours, 'cloud': cloud_cover, 'production': production}
                        data_changed = True
                        save_data(data)
                if not error and current_day in data["data"]:
                    log.debug("would upload to pvoutput %s" % last)
                    #upload_to_pvoutput(data, args.pvoutput)
                    #time.sleep(10)
                last = last + datetime.timedelta(days=1)

    if args.report:
        # Send/Run weekly solarcity summary report
        solarcity_report(data, args.no_email, args.no_tweet)

    if args.blog:
        # Export all entries found for posting to static page on blog: teslaliving.net/solarcity
        log.info("Reporting on SolarCity generation for blog")
        print('<a href="http://ts.la/rob6663">@Tesla Solar</a> Solar Installation')
        print('<h3>System Results</h3>')
        print("<b>%s total power generated via @Tesla Solar as of %s</b>" % (show_with_units(total_generation),
                                                                    time.strftime("%Y%m%d")))
        print("%s day max on %s" % (show_with_units(data['data'][production_max]['production']), production_max))
        print("%s day min on %s" % (show_with_units(data['data'][production_min]['production']), production_min))
        print("<b>%s daily average production</b>" % (show_with_units(total_generation / len(data['data']))))
        print('<h3>System Details</h3>')
        print("System size is 69 panels at 255W each = %.1fkW" % (69 * .255))
        r = relativedelta(datetime.datetime.now(), datetime.datetime.strptime("2015-02-23", '%Y-%m-%d'))
        elapsed_months = r.years * 12 + r.months
        print("System was turned on February 23, 2015 (%d months ago)" % elapsed_months)
        print("Panel info: ")
        print("* Size: 1638 x 982 x 40mm (64.5 x 38.7 x 1.57in)")
        print("* Vendor: <a href='http://www.canadiansolar.com/solar-panels/cs6p-p.html'>CanadianSolar CS6P-P</a>")
        print("Inverter info: ")
        print("* <a href='http://www.solaredge.com/sites/default/files/se-single-phase-us-inverter-datasheet.pdf'>SolarEdge SE6000A</a>")
        print(" ")
        print('Sign up for <a href="http://ts.la/rob6663">Tesla Solar</a> and save on electric!')

        print('<h3>Chart via <a href="http://pvoutput.org/list.jsp?id=48753&sid=44393">PVOutput</a></h3>[hoops name="pvoutput"]')
        if args.details:
            print('<h3>Daily Log:</h3>')
            print("%s%s%s  %s  %s" % ("Date", " " * 11, "Production", "Daylight", "Cloud Cover"))
            d = data['data']
            for e in sorted(d, reverse=True):
                production = d[e]['production']
                if 'daylight' in d[e] and d[e]['daylight'] > 0:
                    daylight = d[e]['daylight']
                    if 'cloud' in d[e]:
                        cloud = d[e]['cloud']
                    else:
                        cloud = 0
                else:
                    pass
                    # w = get_daytime_weather_data(log, time.mktime(time.strptime("%s2100" % e, "%Y%m%d%H%M")))
                    # d[e]['daylight'] = w['daylight']
                    # daylight = w['daylight']
                    # d[e]['weather_api'] = True
                    # d[e]['cloud'] = w['cloud_cover']
                    # cloud = w['cloud_cover']
                    # d[e]['weather_api'] = True
                    # data_changed = True

                if production is not None and daylight is not None and cloud is not None:
                    print('%s' % e, '    %s %.1f hrs %d%%' % \
                                    (show_with_units(production), daylight, cloud))
                else:
                    print('%s' % e, '    %s' % show_with_units(production))

            print('\nSign up for <a href="http://ts.la/rob6663">Tesla Solar</a> and save on electric!')
        print('\nFollow <a href="https://twitter.com/teslaliving">@TeslaLiving</a>.')
        print('\n<ul>')
        print('<li><i>Note 1: Detailed generation tracking started 20150612.</i></li>')
        print('<li><i>Note 2: Cloud/Daylight data <a href="http://forecast.io">Powered by Forecast</a> when ' \
              'Tesla Solar data missing.</i></li>')
        print('<li><i>Note 3: System was degraded from 20170530 to 20170726. Up to 30 panels offline.</i></li>')
        print('<li><i>Note 4: System was degraded from 20190828 to 201909. All panels offline.</i></li>')
        print('</ul>')

    if data_changed:
        save_data(data)

    log.debug("--- solarcity.py end ---")

if __name__ == '__main__':
    try:
        main()
    except SystemExit:
        pass
    except:
        log.exception("Exception encountered")
        message = "There was a problem during solarcity updates:\n\n"
        message += traceback.format_exc()
        message += "\nPlease investigate."
        if DEBUG_MODE:
            raise
        else:
            email(email=SOLARCITY_USER, message=message, subject="Solarcity Poll Error")


import numpy as np
import matplotlib.pyplot as plt
import math

print("Neutron Energy Distribution")

def func1(x):
    return 0.4865 * np.sqrt(2 * 6 * pow(10, 16) / 939.9) * np.sqrt(x) * np.sinh(np.sqrt(2 * x)) * pow(np.e, -x)

def func(x):
    return 0.4865 * np.sinh(np.sqrt(2 * x)) * pow(np.e, -x)

def integral(x):
    """
    cumulative probability distribution for the energy spectrum of u235 + n -> u236
    Source: https://indico.cern.ch/event/145296/contributions/1381141/attachments/136909/194258/lecture24.pdf
    :param x:
    :return:
    """
    first = -pow(np.e, - np.sqrt(2) * np.sqrt(x) - x) * (-1 + pow(np.e, 2 * np.sqrt(2) * np.sqrt(x)))
    second = np.sqrt(np.e * np.pi / 2) * math.erf(1 / np.sqrt(2) - np.sqrt(x))
    third = np.sqrt(np.e * np.pi / 2) * math.erf(1 / np.sqrt(2) + np.sqrt(x))
    return 0.24325 * (first - second + third)

xs = np.linspace(0, 10, 1000)
ys = []
for x in xs:
    ys.append(integral(x))
# ys = integral(xs)

plt.title("cumulative probability distribution")
plt.plot(xs, ys)

plt.show()

Nuclear Fision Reactor Simulation/NeutronEnergyDistribution.py


import sys
import os
#add in auto add to sys path

#print(os.path.isdir("/home/pi/programs/p4/lib/python3.9/site-packages"))
#sys.path.append("/home/pi/programs/p4/lib/python3.9/site-packages")

print(os.listdir("/dev/serial/by-id")[0])
arduino_id="/dev/serial/by-id/"+os.listdir("/dev/serial/by-id")[0]
print(os.path.exists(arduino_id))
working_dir=os.getcwd()
packages_path=working_dir+"/lib/python3.9/site-packages"
sys.path.append(packages_path)
sys.path.append("/usr/lib/python3/dist-packages")
import socket
import select
import cv2
import time
import multiprocessing
from multiprocessing import Process, Value
from multiprocessing.sharedctypes import (
	Synchronized,
)
import numpy as np
import serial
import pygame
from pygame import mixer
import subprocess as sp
import RPi.GPIO as GPIO

def sound_handler(channel_num, volume,sound_effect):
	global sound_names
	if channel_num>2: #channels 0-2
		channel_num=0
	else:
		channel_num+=1

	if sound_effect==sound_names["reload"]:
		channel_num=2
	if (sound_effect==sound_names["kill"]) or (sound_effect==sound_names["dead"]):
		channel_num=3

	mixer.Channel(channel_num).set_volume(volume)
	mixer.Channel(channel_num).play(mixer.Sound(sound_effect))
	print(channel_num, sound_effect)
	return(channel_num)

def serial_process(serial_arr: Synchronized) :#serial function
		#arduino_file=open("arduino_id.txt",'r')
		#arduino_id=arduino_file.readline().split('\n')[0]

		serial_obj=serial.Serial(arduino_id,115200)

		print("starting serial")
		prev_av=0
		changed_from=0
		prev_state=False

		#serial arr[0] is for trigger serial arr[1] is for health serial arr[2] is for reload
		while True:
			s_bytes=serial_obj.readline()
			if (serial_arr[1]!=prev_av):
				changed_from=prev_av
				prev_av=serial_arr[1]
				print("health change:" ,serial_arr[1],prev_av)
			elif(changed_from!=serial_arr[1]):
				encoded_v=str(serial_arr[1]).encode("utf-8")
				serial_obj.write(encoded_v)
			if len(s_bytes)>2:
				if s_bytes[3]==49: #trigger logic
					serial_arr[0]=1
					if not prev_state:
						print("SHOOTING-----")
					prev_state=True
				else:
					serial_arr[0]=0
					prev_state=False

				if s_bytes[2]==49: #reload logic
					print("RELOADING")
					serial_arr[2]=1
				else:
					serial_arr[2]=0

def trigger_handler(switch_state,firing_mode, fire_rate):
	a=time.time()
	global prev_switch_state
	global shot_counter
	global last_shot_time
	return_v=False
	if (1/fire_rate)<=(time.time()-last_shot_time):#fire rate handler
		if firing_mode=='a':#full auto
			if switch_state:
				return_v=True
			else:
				return_v=False
		elif firing_mode=='s':#single fire
			if not prev_switch_state and switch_state:
				return_v=True
			else:
				return_v=False
		elif firing_mode=='b':#burst
			if (not prev_switch_state and switch_state):
				shot_counter=0
			if shot_counter<3:
				shot_counter+=1
				return_v=True
			else:
				return_v=False
		return(return_v)
	return(False) #if nothing return false

def update_crop(camera_index,zoom,x,y):#handles zoom and gets offset from file
	ts=time.time()
	offsetX=0
	offsetY=0
	with open ("campos.txt",'r') as posfile:
		data=posfile.readline().split()
		data+=posfile.readline().split()

		if camera_index==0:
			offsetX=int(data[0])
			offsetY=int(data[1])
		else:
			offsetX=int(data[2])
			offsetY=int(data[3])
	X_MIN=int(x*(1-1/zoom)/2)+offsetX
	Y_MIN=int(y*(1-1/zoom)/2)+offsetY
	X_MAX=X_MIN+int(x/zoom)
	Y_MAX=Y_MIN+int(y/zoom)
	return(X_MIN,X_MAX,Y_MIN,Y_MAX)

def capture_frames(camera_index, window_name,shared_frame):	#opencv image capture method
	cap=cv2.VideoCapture(camera_index)#,cv2.CAP_DSHOW)
	cap.set(cv2.CAP_PROP_BUFFERSIZE,1)
	cap.set(cv2.CAP_PROP_FPS,30)
	X_DIM=640
	Y_DIM=480
	ZOOM_M=2.0
	if camera_index==2:
		ZOOM_M=2.0
		X_DIM=int(640)
		Y_DIM=int(480)
		cap.set(cv2.CAP_PROP_FRAME_WIDTH,X_DIM)
		cap.set(cv2.CAP_PROP_FRAME_HEIGHT,Y_DIM)
	#if camera_index==0:
	#	ZOOM_M=10.0
	#	X_DIM=int(640)
	#	Y_DIM=int(480)
	#	cap.set(cv2.CAP_PROP_FRAME_WIDTH,X_DIM)
	#	cap.set(cv2.CAP_PROP_FRAME_HEIGHT,Y_DIM)
	offsetX=0
	offsetY=0
	with open ("campos.txt",'r') as posfile:
		data=posfile.readline().split()
		data+=posfile.readline().split()
		if camera_index==0:
			offsetX=int(data[0])
			offsetY=int(data[1])
		else:
			offsetX=int(data[2])
			offsetY=int(data[3])
	X_MIN=int(X_DIM*(1-1/ZOOM_M)/2)+offsetX
	Y_MIN=int(Y_DIM*(1-1/ZOOM_M)/2)+offsetY
	X_MAX=X_MIN+int(X_DIM/ZOOM_M)
	Y_MAX=Y_MIN+int(Y_DIM/ZOOM_M)
	X_MIN=160
	X_MAX=480
	Y_MIN=120
	Y_MAX=360
	t1s=time.time()
	X_MIN,X_MAX,Y_MIN,Y_MAX=update_crop(camera_index,ZOOM_M,X_DIM,Y_DIM)
	X_MIN2,X_MAX2,Y_MIN2,Y_MAX2=update_crop(camera_index,10,X_DIM,Y_DIM)
	t_l=time.time()
	while True:
		if (time.time()-t1s)>1:
			t1s=time.time()
			X_MIN,X_MAX,Y_MIN,Y_MAX=update_crop(camera_index,ZOOM_M,X_DIM,Y_DIM)
			X_MIN2,X_MAX2,Y_MIN2,Y_MAX2=update_crop(camera_index,10,X_DIM,Y_DIM)
		t1=time.time()
		ret= cap.grab()
		ret, frame = cap.retrieve()
		if ret:
			dim_frame=frame.shape
			frame_r=frame
			frame=frame[Y_MIN:Y_MAX,X_MIN:X_MAX]
			frame2=frame_r[Y_MIN2:Y_MAX2,X_MIN2:X_MAX2]
			#if camera_index==2:
			frame=cv2.resize(frame,(320,240))
			frame2=cv2.resize(frame2,(320,240))
			shared_frame["im2"]=frame2
			#if camera_index==0:
			#	frame=cv2.resize(frame,(320,240))
			#	shared_frame["im2"]=frame2
			shared_frame["im"]=frame
		#time.sleep(0.01)
		if (time.time()-t_l)>2:
			print(camera_index, ": ",1/(time.time()-t1))
			t_l=time.time()
	cap.release()

def ffmpeg_capture(camera_index, window_name,shared_frame):
	command = [# Start the ffmpeg process
			'ffmpeg',
			# Input device
			'-loglevel','error',
			'-input_format','mjpeg',
			'-video_size','640x480',
			'-i', f'/dev/video{camera_index}',
			'-vf', 'fps=30', #'30',  # Filter for 1 frame per second
			'-pix_fmt', 'bgr24',  # Pixel format for OpenCV
			'-f','rawvideo','-',
			#'-vcodec', 'rawvideo', '-an', '-',  # Output encoding and destination
	]

	size=[480,640]#set paramters for crop
	X_DIM=size[1]
	Y_DIM=size[0]
	ZOOM_M=2.0

	time_update_crop=time.time()
	print_time=time.time()
	t_loop=time.time()

	X_MIN,X_MAX,Y_MIN,Y_MAX=update_crop(camera_index,ZOOM_M,X_DIM,Y_DIM)#set crop
	global using_double
	if using_double:
		ZOOM_M2=10.0
		X_MIN2,X_MAX2,Y_MIN2,Y_MAX2=update_crop(camera_index,ZOOM_M2,X_DIM,Y_DIM)

	with sp.Popen(command, stdout=sp.PIPE, bufsize=10**5) as pipe:
		while True:
			if (time.time()-time_update_crop)>1:#update crop values each second
				X_MIN,X_MAX,Y_MIN,Y_MAX=update_crop(camera_index,ZOOM_M,X_DIM,Y_DIM)
				if using_double:
					X_MIN2,X_MAX2,Y_MIN2,Y_MAX2=update_crop(camera_index,ZOOM_M2,X_DIM,Y_DIM)
				time_update_crop=time.time()

			raw_image = pipe.stdout.read(size[0]*size[1]*3)# Read one frame's worth of data\
			pipe.stdout.flush()# Clear the buffer to prevent overflow

			frame =  np.frombuffer(raw_image, dtype='uint8')#turn image from bytes to array
			frame_o = frame.reshape((size[0],size[1], 3))	#reshape image

			frame=frame_o[Y_MIN:Y_MAX,X_MIN:X_MAX]	#crop the image
			shared_frame["im"]=cv2.resize(frame,(320,240))
			if using_double:
				frame2=frame_o[Y_MIN2:Y_MAX2,X_MIN2:X_MAX2]
				shared_frame["im2"]=cv2.resize(frame2,(320,240))

			if (time.time()-print_time)>2:#print frame rate
				print(camera_index, ": ",1/(time.time()-t_loop))
				print_time=time.time()
			t_loop=time.time()

if __name__=="__main__":
	sound_select=0
	sound_names={}
	sound_names["shoot"]="sounds/shoot/"+str(os.listdir("sounds/shoot")[sound_select])
	sound_names["hit"]="sounds/hit/"+str(os.listdir("sounds/hit")[sound_select])
	sound_names["reload"]="sounds/reload/"+str(os.listdir("sounds/reload")[sound_select])
	sound_names["kill"]="sounds/kill/"+str(os.listdir("sounds/kill")[sound_select])
	sound_names["dead"]="sounds/dead/"+str(os.listdir("sounds/dead")[sound_select])
	print(sound_names["kill"],"\n")
	pygame.init()#setup sound
	mixer.init()
	mixer.Channel(3).set_volume(1.0)
	mixer.Channel(3).play(mixer.Sound(sound_names["dead"]))
	chan_num=0 #keeps track of what channel is being used on mixer
	time.sleep(1)
	GPIO.setmode(GPIO.BOARD)
	GPIO.setup(38,GPIO.IN,pull_up_down=GPIO.PUD_UP)

	run_arduino=True#arduino thread
	if run_arduino:
		serial_arr=multiprocessing.Array("i",5)
		cam_arr=multiprocessing.Array("i",5)
		switch_on=False
		prev_switch_state=switch_on
		a_p=Process(target=serial_process, args=(serial_arr,))
		a_p.start()

	a=time.time()	#pre while
	run_main_loop=True
	print_time_m=time.time()
	send_time=time.time()

	failed_conn=False	#start socket
	s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	print("attempting connection to .23")
	s.connect(("192.168.1.3",2345))
	print("connected to",s)

	health=100	#initialize player stats
	prev_health=health
	dead=False
	dead_time=time.time()
	mag_size=10 #shots = + 1
	fire_rate=11
	firing_mode='a' #define firing mode
	mag_count=mag_size
	shot_counter=3	#to initialize burst
	reload_dur=3.7
	reload_time=time.time()
	reload_playing=False
	reload_sound_playing=False
	last_shot_time=time.time()
	shoot_override=False

	manager=multiprocessing.Manager()	#make sharing dicts for iamges
	shared_1=manager.dict()
	shared_2=manager.dict()
	shared_1["im"]=[]
	shared_1["im2"]=[]
	shared_2["im"]=[]
	shared_2["im2"]=[]

	cam_setttings_file_name="camsettings.txt"
	cam_setttings_file=open(cam_setttings_file_name,"r")
	cam_settings=cam_setttings_file.readline()
	print("CAM SETTINGS: ",cam_settings)
	cam_setttings_file.close()
	cam2_on=True
	cam1_on=True
	using_double=False
	if cam_settings[0]=='f':
		using_double=True
		cam2_on=False
		pass
	elif cam_settings[0]=='c':
		pass
	elif cam_settings[0]=='b':
		pass
	cam2_thread=multiprocessing.Process(target=capture_frames, args=(2,"cam2",shared_2,))
    #cam1_thread=multiprocessing.Process(target=capture_frames, args=(0,"cam1",shared_1,))
	cam1_ffthread=multiprocessing.Process(target=ffmpeg_capture,args=(0,"cam1",shared_1,))

	if cam2_on:
		cam2_thread.start()	#start cameras
		print("cam_thread2 started")
		time.sleep(2)
	if cam1_on:
		cam1_ffthread.start()
		print("cam_thread1 started")
		time.sleep(1)

	print("starting main")
	while (run_main_loop):
		if (time.time()-print_time_m)>1:#print out player info
			print("health: ",health,"loop: ",time.time()-a,"send: ",send_time) #" image capture time: ",t3-t2,t4-t2)	#time printing
			try:
				print("T: ",t_bottom_while_loop-t_before_player_logic,t_before_recieve-t_before_player_logic,t_before_send-t_before_recieve,t_bottom_while_loop-t_before_send)
			except:
				pass
			print_time_m=time.time()

		t_before_player_logic=time.time()
		if health<=0:#check if dead
			dead=True
			mag_count=mag_size
		else:
			dead=False
		prev_switch_state=switch_on
		if (not (GPIO.input(38)))or(serial_arr[0]==1):	#switch on or off
			switch_on=True
		else:
			switch_on=False
		t2=time.time()
		if not dead:
			shoot_or_no=(trigger_handler(switch_on,firing_mode,fire_rate))	#transfer block and firing mode handler
			if shoot_or_no:
				if mag_count>0:
					last_shot_time=time.time()
					sound_handler(chan_num,1.5,sound_names["shoot"])

			if shoot_override:	#if remote shooting
				shoot_or_no=True
				shoot_override=False
			if mag_count>0:#check if mag empty
				if shoot_or_no:
					mag_count-=1
			else: #blanks
				reload_playing=True
				shoot_or_no=0

			if serial_arr[2]:	#if reload start reloading
				reload_playing=True
				serial_arr[2]=0

			if not reload_playing:	#reload control logic
				reload_time=time.time()
			else:
				if not reload_sound_playing and (time.time()-reload_time)>0.4:
					sound_handler(7,1.3,sound_names["reload"])
					reload_sound_playing=True
				shoot_or_no=False
				if((time.time()-reload_time)>reload_dur):
					mag_count=mag_size
					reload_playing=False
					reload_sound_playing=False
		else:#if dead dont shoot
			shoot_or_no=False

		t_before_recieve=time.time()
		ready=select.select([s],[],[],0.005)	#recieve data start
		if ready[0]:
			in_data=s.recv(1024).decode("utf-8")	#get data
			index_s=0
			string_arr=in_data.split(',')	#turn data to array
			try:
				if string_arr[0]=='1':#got a hit
					sound_handler(chan_num+3,1,sound_names["hit"])
				if string_arr[0]=='2':#got a kill
					sound_handler(chan_num+3,1,sound_names["hit"])
					sound_handler(8,1,sound_names["kill"])
				if string_arr[0]=='3':#remote shoot
					shoot_override=True
				if len(string_arr)>1:
					health=int(string_arr[1])#update health
					if health>101:
						health=100
					serial_arr[1]=health#send health to arduino
					if (health<=0) and not dead:
						sound_handler(8,1,sound_names["dead"])#play sound if dead
				if len(string_arr)>2:
					fire_rate=int(string_arr[2])#get fire rate paramter
				if len(string_arr)>3:
					mag_size=int(string_arr[3])#get mag size
					if mag_count>mag_size:
						mag_count=mag_size
				if len(string_arr)>4:
					firing_mode=string_arr[4]#get firing mode
			except:
				pass

		t_before_send=time.time()
		if shoot_or_no:	#send shot logic
			if cam_settings[0]=='f':
				frame=np.concatenate((shared_1["im"],shared_1["im2"]),axis=0)
			else:
				frame=np.concatenate((shared_1["im"],shared_2["im"]),axis=0)	#concatinate frames
			cv2.imwrite("dimg.jpg",frame)
			im_file=open("dimg.jpg",'rb')
			data=im_file.read(1024*5)#read in first packet to be sent
			print("sending data")
			try:
				send_time=time.time()
				while data:#send data for length of image file
					s.send(data)
					data=im_file.read(1024*5)
				im_file.close()
				s.send(b"next")#send b'next' as cutoff term when all data has been sent
				send_time=time.time()-send_time

			except:#if sending fails then try to restart connection
				failed_conn=True
				while failed_conn:
					try:
						s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
						s.connect(("192.168.1.3",2345))
						print("connected to",s)
						failed_conn=False
					except:
						time.sleep(0.5)
						print("conn failed retrying")
						failed_conn=True
				try:
					im_file.close()
				except:
					print("error closing file")
		t_bottom_while_loop=time.time()

	a_p.join()#join arduino after while is finished


import customtkinter
import tkinter
from chatsection import ChatSection
import threading
import sys
from client import Client

HOST = '10.57.33.117'  #IP address server machine
PORT = 3042

class Clientui(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        self.geometry("500x700")
        self.title("Chatbot d'avril")
        self.minsize(500, 700)
        self.maxsize(500, 700)
        self._set_appearance_mode("dark")

        self._pseudo = None
        self._user = Client(HOST,PORT)

        # color
        self.primary_color = "#242424"

        # Font parameter
        self.send_button_font = customtkinter.CTkFont(family="Arial", size=18, weight="bold")
        self.chat_text_font = customtkinter.CTkFont(family="Arial", size=18, weight="normal")

        self.create_menu()

        self._reload_pseudo = False

        self.label_error = tkinter.Label(master=self,text= "Test", font=self.chat_text_font)
    def create_chatpage(self):
        """
            Crée une page de chat et l'affiche.
        """
        chat_page = tkinter.Frame(self, bg=self.primary_color)
        chat_page.pack(side="top")
        chat_section = ChatSection(chat_page, self.send_button_font, self.chat_text_font, self, self._user)
        threading.Thread(target=chat_section.display_messages).start()

    def create_menu(self):
        """
            Crée une page de menu avec des boutons pour rejoindre le salon de discussion ou quitter l'application.
        """
        page = tkinter.Frame(self, bg=self.primary_color, width=500, height=700,pady=275)
        page.pack(side="top")

        chat = customtkinter.CTkButton(master=page, text="Rejoindre le salon", command =lambda: self.go_pseudo(page))
        chat.pack(side="top")

        quit = customtkinter.CTkButton(master=page, text="Quitter", command =lambda: sys.exit()) # Remplacer par la fonction déconnecte
        quit.pack(side= "top")

    def create_pseudo_menu(self):
        """
            Crée un formulaire permettant à l'utilisateur d'entrer son pseudo pour se connecter au salon de discussion.

        """
        page = tkinter.Frame(self, bg=self.primary_color, width=500, height=700,pady=275)
        page.pack(side="top")

        label_pseudo = customtkinter.CTkLabel(master=page, text="Entrez votre pseudo", font=self.chat_text_font, text_color="#ffffff")
        label_pseudo.pack(side="top")

        input_pseudo = customtkinter.CTkEntry(master=page, placeholder_text="Pseudo...") # On entre le pseudo
        input_pseudo.pack(side="top")

        chat = customtkinter.CTkButton(master=page, text="Rejoindre le salon", command =lambda: self.check_pseudo(input_pseudo.get(), page)) # Quand on clique on va vers le chat
        chat.pack(side="top")

    def check_pseudo(self, pseudo, page):
        """
            Vérifie si le pseudo fourni est valide et tente de se connecter au serveur avec le pseudo fourni.

            Parameter:
                pseudo (str): Le pseudo fourni par l'utilisateur.
                page (tkinter.Frame): La page parent du bouton.

            Returns:
                None

        """
        if(len(pseudo)>20 or len(pseudo) <= 0 or " " in pseudo): # Verif côté client
            self.generate_error("Pas d'espace et pas plus de 20 caractères")
        else:
            if (self._user.connect(pseudo,self._reload_pseudo)): # Verif côté sersveur
                if self.label_error.winfo_ismapped():
                    self.label_error.destroy()
                self.go_chat(page)
            else:
                self.generate_error("Pseudo déjà pris :(")
                self._reload_pseudo = True

    def generate_error(self, message):
        """
            Affiche un message d'erreur sur l'interface graphique.

            Parameter:
                message (str): Le message d'erreur à afficher.

            Returns:
                None
        """
        if self.label_error.winfo_ismapped():
            self.label_error.destroy()
        self.label_error = tkinter.Label(master=self,text= message, font=self.chat_text_font)
        self.label_error.pack(side="top")

    def go_chat(self, old_page):
        """
            Détruit la page actuelle et crée la page de chat où l'utilisateur pourra rejoindre le salon de discussion.

            Parameter:
                old_page (tkinter.Frame): La page actuelle qui doit être détruite.

            Returns:
                None
        """
        old_page.destroy()
        self.create_chatpage()

    def go_pseudo(self, old_page):
        """
            Détruit la page actuelle et crée la page de connexion où l'utilisateur pourra entrer son pseudo.

            Parameter:
                old_page (tkinter.Frame): La page actuelle qui doit être détruite.

            Returns:
                None
        """
        old_page.destroy()
        self.create_pseudo_menu()

    def on_closing(self):
        """
           Déconnecte l'utilisateur et ferme le script python
        """
        if tkinter.messagebox.askokcancel("Quit", "Voulez-vous vous déconnecter ?"):
            self._user.disconnect()
            app.destroy()
            sys.exit()

if __name__ == "__main__":
    app = Clientui()
    app.protocol("WM_DELETE_WINDOW", app.on_closing) #Execute function on_closing() when tkinter window is closed
    app.mainloop()


from torch import conv_transpose1d
from util.homo_transform import warpPerspectivePts
from stag_decode.fine_grid_matcher import FineGridMatcher
from stag_decode.keypoints import *
import cv2
import time

class StagDecoder:
    def __init__(self, predictor, unit_tag_template, marker_dict, cameraMatrix= None, distCoeffs = None, sigma_keypoints = 5, min_grid_match_ratio = 0.8, batch_size = 8, border_ratio = 0.15, image_rect_size = (256,256), iter_num = 1):

        self.predictor = predictor
        self.features = None
        self.sigma_keypoints = sigma_keypoints
        self.cameraMatrix = cameraMatrix
        self.distCoeffs =distCoeffs
        self.unit_tag_template = unit_tag_template
        self.min_grid_match_ratio = min_grid_match_ratio
        self.batch_size = batch_size
        self.image_rect_size = image_rect_size
        self.roi_in_crop = get_crop_ordered_corners(image_rect_size[0], image_rect_size[1], border_ratio)
        self.iter_num = iter_num
        self.marker_dict = marker_dict

    def detect_tags(self, image, rois):

        batch_size = self.batch_size
        iter_num = self.iter_num
        self.cnn_timing_list = []
        self.prediction_timing_list = []
        self.postprocess_timing_list = []

        rois_curr = rois
        valid_ids = None

        # iteration by updating ROIs
        decoded_tags = [{'is_valid': False} for _ in range(len(rois))]
        t0 = time.time()
        for iter_i in range(iter_num):

            print('>iter #%d'% iter_i)
            crops, H_list, valid_ids = rectify_crops(image, rois_curr, self.roi_in_crop, self.image_rect_size)

            # # visualize crops
            # for ii, crop in enumerate(crops):
            #     cv2.imshow('crop_%d_%d'%(iter_i, ii), crop)
            # cv2.waitKey(0)

            # CNN prediction
            features_pred_list = []
            batch_id = 0
            while batch_id * batch_size < len(crops):
                t1 = time.time()
                features_pred_list += self.predictor.predict(crops[batch_id *batch_size:(batch_id+1)*batch_size])
                self.cnn_timing_list.append(self.predictor.cnn_timing)
                self.prediction_timing_list.append(time.time()-t1)
                batch_id +=1

            # decode from CNN outputs
            for features_pred, H, roi_idx in zip(features_pred_list, H_list, valid_ids):
                # print('--ROI #%d--'% (roi_idx))
                t2 = time.time()
                decoded_tag, roi_updated = self.decode_one_tag(features_pred, H)
                decoded_tag['image_size_crop'] =  self.image_rect_size
                rois_curr[roi_idx] = roi_updated # update roi
                decoded_tags[roi_idx] = decoded_tag # update result
                self.postprocess_timing_list.append(time.time()-t2)
                # print('Valid tag.' if decoded_tag['is_valid'] else 'Invalid.')

        self.total_timing = time.time() -t0
        return decoded_tags

    def decode_one_tag(self, features_pred, H):
        cameraMatrix = self.cameraMatrix
        distCoeffs = self.distCoeffs
        unit_tag_template = self.unit_tag_template
        sigma_keypoints = self.sigma_keypoints
        min_grid_match_ratio = self.min_grid_match_ratio
        marker_dict = self.marker_dict

        confidences_pred_np, grid_pred_np = features_pred['grid_pred'][:2]
        corners_pred_np = features_pred['corners_pred'][1]

        ordered_corners = [corners_pred_np.tolist()[idx] for idx in [0,1,3,2]]

        # detect fine_grid_points from cnn outputs
        fine_grid_points_with_ids_candidates, scores_candidates = detect_keypoints_with_hms(confidences_pred_np, grid_pred_np, sigma3_nms = sigma_keypoints)

        # match fine_grid_points with unit_tag_templates
        fine_grid_matcher = FineGridMatcher(ordered_corners, ordered_corners_in_crop_set = [], cameraMatrix=cameraMatrix, distCoeffs=distCoeffs)
        match_ratio, ordered_fine_grid_points_ids = unit_tag_template.match_fine_grid(fine_grid_points_with_ids_candidates, H, [fine_grid_matcher])

        # refine and get ids
        roi_updated = None
        if match_ratio > min_grid_match_ratio:
            # get id if missing
            ordered_fine_grid_points_ids = fill_empty_ids(ordered_fine_grid_points_ids, fine_grid_points_with_ids_candidates)

            # update roi
            roi_updated = unit_tag_template.update_corners_in_image(ordered_fine_grid_points_ids, H, valid_flag_list= None, cameraMatrix = cameraMatrix, distCoeffs = distCoeffs)

            # get main_idx and reorder
            # _, ordered_kpts_with_ids = unit_tag_template.reorder_points_with_main_idx(ordered_fine_grid_points_ids, 0)
            main_idx, decimal_id = marker_dict.get_main_idx([kpt[2] for kpt in ordered_fine_grid_points_ids])
            if decimal_id < 0:
                main_idx, decimal_id = unit_tag_template.get_main_idx([kpt[2] for kpt in ordered_fine_grid_points_ids])
            ordered_fine_grid_points_ids, ordered_kpts_with_ids = unit_tag_template.reorder_points_with_main_idx(ordered_fine_grid_points_ids, main_idx)
            binary_ids = [kpt[2] for kpt in ordered_kpts_with_ids]

            # get score
            tag_score = sum(scores_candidates)/len(scores_candidates)

            # get unit_tag
            unit_tag = unit_tag_template.get_unit_tag(ordered_fine_grid_points_ids)

            # unwarp keypoints
            H_inv = np.linalg.inv(H)
            ordered_fine_grid_points_in_image = warpPerspectivePts(H_inv, [kpt[:2] for kpt in ordered_fine_grid_points_ids])

            # save results
            decoded_tag = {'is_valid': True,
                        'H_crop': H,
                        'tag_id': decimal_id,
                        'binary_ids': binary_ids,
                        'keypoints_with_ids': ordered_fine_grid_points_ids,
                        'keypoints_in_images': ordered_fine_grid_points_in_image,
                        'score': tag_score,
                        'unit_tag': unit_tag,
                        'main_idx': main_idx,
                        'rotation_idx': 0
                        }

        else:

            decoded_tag = {'is_valid': False}
            roi_updated = None

        return decoded_tag, roi_updated

def rectify_crops(image, rois, roi_in_crop, image_rect_size):

    crops = []
    H_list = []
    valid_ids = []
    th, tw = image_rect_size

    for ii, roi in enumerate(rois):
        if roi is not None:
            H, _ = cv2.findHomography(np.float32(roi), np.float32(roi_in_crop))
            image_rect = cv2.warpPerspective(image, H, (tw,th))
            crops.append(image_rect)
            H_list.append(H)
            valid_ids.append(ii)

    return crops, H_list, valid_ids

def get_crop_ordered_corners(h, w, border_ratio):
    # border_ratio is in [0,0.3]
    bw = max(h,w) * border_ratio
    ordered_corners_in_crop = [[bw-0.5, bw-0.5], [w-bw-0.5, bw-0.5], [w-bw-0.5, h-bw-0.5], [bw-0.5, h-bw-0.5] ]
    return ordered_corners_in_crop