import math
from ast import literal_eval

# from keras.layers import *
# from keras.layers.advanced_activations import LeakyReLU
# from keras.models import Model
import os
import time
from PIL import Image
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
import matplotlib.pyplot as plt

#from ds_utils import image_processing

def conv(filters, kernel_size=5, strides=2, leaky_relu=False):
    def block(x):
        x = Conv2D(filters, kernel_size=kernel_size, strides=strides,
                   padding='same')(x)
        x = BatchNormalization()(x)
        if leaky_relu:
            x = LeakyReLU(0.2)(x)
        else:
            x = Activation("relu")(x)
        return x
    return block

def res_block(filters, kernel_size=3):
    def block(input_tensor):
        x = conv(filters, kernel_size=kernel_size, strides=1, leaky_relu=True)(input_tensor)
        x = conv(filters, kernel_size=kernel_size, strides=1, leaky_relu=True)(input_tensor)
        x = Add()([x, input_tensor])
        x = LeakyReLU(alpha=0.2)(x)
        return x
    return block

def upscale(filters, kernel_size=3):
    def block(x):
        x = UpSampling2D()(x)
        x = Conv2D(filters, kernel_size=kernel_size, padding='same')(x)
        x = LeakyReLU(0.1)(x)
        return x
    return block

def get_upsampling_model(input_shape, upscale_factor=2):
    # get number of upscale blocks needed based on given factor
    # (2^upscale_blocks = upscale_factor)
    upscale_blocks = int(math.log(upscale_factor, 2))

    model_input = Input(shape=input_shape)
    x = model_input

    res_input_0 = conv(64, 3, 1)(x)

    x = res_block(64)(res_input_0)

    nb_residual = 5
    for i in range(nb_residual):
        x = res_block(64)(x)

    x = Add()([x, res_input_0])

    # if more should get input for Nth conv block and add for Nth res block
    for i in range(upscale_blocks):
        x = upscale(64, 3)(x)
        # first res_input is just model_input
        # x = Add()([x, res_inputs[i+2]])

    outp = Conv2D(3, 3, activation='linear', padding='same')(x)

    return model_input, outp

def get_SRResNet(cfg):
    models_path = cfg.get('models_path', None)
    LR_IMG_SHAPE = literal_eval(cfg.get('LR_IMG_SHAPE'))

    upsampled_inp, upsampled_output = get_upsampling_model(LR_IMG_SHAPE, 2)

    sr_model = Model(upsampled_inp, upsampled_output)
    #adam = Adam(lr=1e-3)
    #sr_model.compile(optimizer=adam, loss=loss_wrapper(vgg_hr, vgg_upsamples), metrics=[PSNRLoss])

    if models_path:
        print("Loading Super Resolution Models...")
        sr_model.load_weights(models_path + '/sr_model.h5')
        print("Super Resolution Models Loaded")

    return sr_model

################
# Training Utils
################
def train_generator(imgs_filepaths, img_size=None, batch_size=64, apply_fun=None):
    while True:
        imgs_paths_sample = np.random.choice(imgs_filepaths, batch_size)
        original_data = image_processing.load_data(imgs_paths_sample, img_size)
        original_data = original_data / 255.0
        if apply_fun:
            data = apply_fun(original_data)
        else:
            data = original_data
        yield data, original_data

def preprocess_image(image_path):
  """ Loads image from path and preprocesses to make it model ready
      Args:
        image_path: Path to the image file
  """
  hr_image = tf.image.decode_image(tf.io.read_file(image_path))
  # If PNG, remove the alpha channel. The model only supports
  # images with 3 color channels.
  if hr_image.shape[-1] == 4:
    hr_image = hr_image[...,:-1]
  hr_size = (tf.convert_to_tensor(hr_image.shape[:-1]) // 4) * 4
  hr_image = tf.image.crop_to_bounding_box(hr_image, 0, 0, hr_size[0], hr_size[1])
  hr_image = tf.cast(hr_image, tf.float32)
  return tf.expand_dims(hr_image, 0)

hr_image = preprocess_image("C:/Users/User/Documents/generated_data/sr/test/1.png")
SAVED_MODEL_PATH = "https://tfhub.dev/captain-pool/esrgan-tf2/1"
model = hub.load(SAVED_MODEL_PATH)
fake_image = model(hr_image)
image = tf.squeeze(fake_image)
if not isinstance(image, Image.Image):
    image = tf.clip_by_value(image, 0, 255)
    image = Image.fromarray(tf.cast(image, tf.uint8).numpy())
image.save("C:/Users/User/Documents/generated_data/sr/out.png")


# -*- coding: utf-8 -*-
"""
Created on Sat Oct  8 16:49:36 2022

@author: DELL
"""

#Deep learning_gradient decent techniques..

import pandas as pd
df=pd.read_csv("pima-indians-diabetes.csv",delimiter=",")

x=df.iloc[:,0:8]
y=df.iloc[:,8]
#pip install tensorflow
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Sequential

# create model
import numpy as np
model = Sequential()
model.add(Dense(12, input_dim=8,  activation='relu'))
model.add(Dense(1, activation='sigmoid'))

# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Fit the model
history = model.fit(x, y, validation_split=0.30, epochs=250, batch_size=100)

# evaluate the model
scores = model.evaluate(x, y)
print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
history.history.keys()
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()


from urllib.request import urlopen
from bs4 import BeautifulSoup
import json
import datetime
import pprint
import sys
pp = pprint.PrettyPrinter(indent=4)

def main(): # Main function
	current_year = int(datetime.datetime.now().year)
	for year in range(1898, current_year+1):
		sys.stdout = open('DataSets//IMDB_Top_50_' + str(year) + '.json', 'w')
		url = "http://www.imdb.com/search/title?release_date=" + str(year) + "," + str(year) + "&title_type=feature"
		html = urlopen(url)
		soup = BeautifulSoup(html.read(), features="html.parser")
		dataset_top50 = {}
		id = 1
		movies_list = soup.findAll('div', attrs={'class': 'lister-item-content'})
		for each in movies_list:

			# Prototype of each movie item
			movie_item = {
				'name': '',
				'certificate': '',
				'runtime': '',
				'genre': '',
				'description': '',
				'director': '',
				'stars': []
				# 'votes': '',
				# 'gross': ''
			}

			if each.find('h3', attrs={'class': 'lister-item-header'}).find('a').text:
				name_value = each.find('h3', attrs={'class': 'lister-item-header'}).find('a').text.strip()
				movie_item['name'] = name_value

			p_list = each.findAll('p')

			if p_list[0]:
				if p_list[0].find('span', attrs={'class': 'certificate'}):
					certificate_value = p_list[0].find('span', attrs={'class': 'certificate'}).text.strip()
					movie_item['certificate'] = certificate_value

				if p_list[0].find('span', attrs={'class': 'runtime'}):
					runtime_value = p_list[0].find('span', attrs={'class': 'runtime'}).text.strip()
					movie_item['runtime'] = runtime_value

				if p_list[0].find('span', attrs={'class': 'genre'}):
					genre_value = p_list[0].find('span', attrs={'class': 'genre'}).text.strip()
					movie_item['genre'] = genre_value

			if p_list[1]:
				description_value = p_list[1].text.strip()
				movie_item['description'] = description_value

			# if p_list[2]:
			# 	director_value = p_list[2].findAll('a')[0].text.strip()
			# 	movie_item['director'] = director_value
			# 	stars_list = p_list[2].findAll('a')[1:]
			# 	stars_value = []
			# 	for each in stars_list:
			# 		stars_value += [each.text.strip()]

			# 	movie_item['stars'] = stars_value

			# if len(p_list) == 4:
			# 	votes_value = p_list[3].findAll('span', attrs={'name': 'nv'})[0].text.strip()
			# 	movie_item['votes'] = votes_value
			# 	gross_value = p_list[3].findAll('span', attrs={'name': 'nv'})[1].text.strip()
			# 	movie_item['gross'] = gross_value

			dataset_top50[id] = movie_item
			id += 1

		pp.pprint(dataset_top50)
		print(json.dumps(dataset_top50, indent=4))

	# End of the main function

main() # Call of the main function


# -*- coding: utf-8 -*-
"""Collection of utility functions for the prisoner's dilemma."""
from typing import Dict, Tuple

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

from prisoners_dilemma.env import PrisonersDilemmaEnv

def vis_action_matrix(indiv_action_seq: np.ndarray, num_agents: int = 2) -> np.ndarray:
    """Get a matrix with the combined actions of both agents

    Args:
        indiv_action_seq (ndarray): action taken for each episode
        num_agents (int): number of agents in the game, defaults to 2

    Returns:
        ndarray: action matrix of size (num_agents * num_actions, num_episodes)
    """

    act_matrix = np.zeros(
        (indiv_action_seq.shape[0], indiv_action_seq.shape[1] * num_agents)
    )
    for i in range(indiv_action_seq.shape[0]):
        # (D, D)
        if indiv_action_seq[i, 0] == 0 and indiv_action_seq[i, 1] == 0:
            act_matrix[i, 0] = 1
        # (D, C)
        elif indiv_action_seq[i, 0] == 0 and indiv_action_seq[i, 1] == 1:
            act_matrix[i, 1] = 1
        # (C, D)
        elif indiv_action_seq[i, 0] == 1 and indiv_action_seq[i, 1] == 0:
            act_matrix[i, 2] = 1
        # (C, C)
        elif indiv_action_seq[i, 0] == 1 and indiv_action_seq[i, 1] == 1:
            act_matrix[i, 3] = 1

    return act_matrix.T

def init_q_tables(init_type: str, env: PrisonersDilemmaEnv) -> np.ndarray:
    """Initialize the Q-tables.

    Args:
        init_type (str): initialization version
        env (PrisonersDilemmaEnv): prisoner's dilemme environment

    Returns:
        ndarray: table of Q-values for the players
    """
    if init_type == "zeros":
        return np.zeros(env.action_space.n), np.zeros(env.action_space.n)
    # TODO: add more ways to initialize the Q-tables

    raise NotImplementedError("Initialization method not known.")

def run_standard_ipd_exp(
    config: Dict,
) -> Tuple[np.array, np.array, np.array, np.array]:
    """
    Run a number of in the standard IPD.

    Note: There is only one state and agents cannote observe the others' actions.

    Args:
        config (Dict): game configurations

    Returns:
        ndarray: q-value trajectory of player one
        ndarray: q-value trajectory of player two
        ndarray: sequence of rewards obtained by the players
        ndarray: sequence of actions played by the players
    """
    game_env = PrisonersDilemmaEnv(
        config["payoffs"]["reward_payoff"],
        config["payoffs"]["tempta_payoff"],
        config["payoffs"]["sucker_payoff"],
        config["payoffs"]["punish_payoff"],
    )

    # Initialize Q-tables
    q_table_one, q_table_two = init_q_tables(
        init_type=config["init_type"], env=game_env
    )
    q_traj_one = np.zeros((config["num_episodes"], game_env.action_space.n))
    q_traj_two = np.zeros((config["num_episodes"], game_env.action_space.n))
    rewards_seq = np.zeros((config["num_episodes"], config["num_agents"]))
    action_seq = np.zeros((config["num_episodes"], config["num_agents"]))

    for episode_i in range(config["num_episodes"]):
        if config["verbose"]:
            print(f"Episode: {episode_i}")

        # Player one: take random action
        if np.random.random() < config["params"]["eps"][0]:
            act_play_one = np.array([game_env.action_space.sample()])
        else:  # Exploit
            act_play_one = np.random.choice(
                a=np.argwhere((q_table_one == q_table_one.max())).flatten(),
                size=(1,),
            )
        # Player two: take random action
        if np.random.random() < config["params"]["eps"][1]:
            act_play_two = np.array([game_env.action_space.sample()])
        else:  # Exploit
            act_play_two = np.random.choice(
                a=np.argwhere((q_table_two == q_table_two.max())).flatten(),
                size=(1,),
            )
        # Take a step
        actions = np.concatenate([act_play_one, act_play_two])
        _, rewards, _, _, _ = game_env.step(action=actions)

        # Update Q-values
        q_table_one[act_play_one] = q_table_one[act_play_one] + config["params"][
            "alpha"
        ][0] * (
            rewards[0]
            + config["params"]["gamma"][0] * np.max(q_table_one)
            - q_table_one[act_play_one]
        )

        q_table_two[act_play_two] = q_table_two[act_play_two] + config["params"][
            "alpha"
        ][1] * (
            rewards[1]
            + config["params"]["gamma"][1] * np.max(q_table_two)
            - q_table_two[act_play_two]
        )

        # Store trajectory
        rewards_seq[episode_i, :] = rewards
        action_seq[episode_i, :] = actions
        # episode x actions x players
        q_traj_one[episode_i] = q_table_one
        q_traj_two[episode_i] = q_table_two

    return (
        q_traj_one,
        q_traj_two,
        rewards_seq,
        action_seq,
    )

def run_extended_ipd_exp(config: Dict) -> Tuple[np.array, np.array, np.array, np.array]:
    """
    Allow agent two to see the action of agent one.
    """

    game_env = PrisonersDilemmaEnv(
        config["payoffs"]["reward_payoff"],
        config["payoffs"]["tempta_payoff"],
        config["payoffs"]["sucker_payoff"],
        config["payoffs"]["punish_payoff"],
    )

    q_table_one = np.zeros((game_env.action_space.n))
    # Initialize Q-tables (own act x other play act)
    q_table_two = np.zeros((game_env.action_space.n, game_env.action_space.n))

    q_traj_one = np.zeros((config["num_episodes"], game_env.action_space.n))
    q_traj_two = np.zeros(
        (config["num_episodes"], game_env.action_space.n, game_env.action_space.n)
    )
    rewards_seq = np.zeros((config["num_episodes"], config["num_agents"]))
    action_seq = np.zeros((config["num_episodes"], config["num_agents"]), dtype=int)

    # Condition the action of one agent on the action of the other
    for episode_i in range(config["num_episodes"]):
        # # # # Select action player one # # # #
        if np.random.random() < config["params"]["eps"][0]:
            act_play_one = np.array([game_env.action_space.sample()])
        else:  # Exploit
            act_play_one = np.random.choice(
                a=np.argwhere((q_table_one == q_table_one.max())).flatten(), size=(1,)
            )
        # # # # Select action player two | Condition on the action of player one # # # #
        if np.random.random() < config["params"]["eps"][1]:
            act_play_two = np.array([game_env.action_space.sample()])
        else:  # Exploit: choose the action associated with the highest q-value,
            # condition on the action of agent one
            act_play_two = np.random.choice(
                a=np.argwhere(
                    (q_table_two[:, act_play_one] == q_table_two[:, act_play_one].max())
                ).flatten(),
                size=(1,),
            )

        # # # # Take a step # # # #
        actions = np.concatenate([act_play_one, act_play_two])
        _, rewards, _, _, _ = game_env.step(action=actions)

        # # # # Update Q-values # # # #
        q_table_one[act_play_one] = q_table_one[act_play_one] + config["params"][
            "alpha"
        ][0] * (
            rewards[0]
            + config["params"]["gamma"][0] * np.max(q_table_one)
            - q_table_one[act_play_one]
        )

        q_table_two[act_play_two, act_play_one] = q_table_two[
            act_play_two, act_play_one
        ] + config["params"]["alpha"][1] * (
            rewards[1]
            + config["params"]["gamma"][1] * np.max(q_table_two[:, act_play_one])
            - q_table_two[act_play_two, act_play_one]
        )

        # Store trajectory
        rewards_seq[episode_i, :] = rewards
        action_seq[episode_i, :] = actions
        # episode x actions x players
        q_traj_one[episode_i, :] = q_table_one
        q_traj_two[episode_i, :, :] = q_table_two

    return (
        q_traj_one,
        q_traj_two,
        rewards_seq,
        action_seq,
    )

def make_q_vals_fig_standard(
    action_seq: np.ndarray,
    config: Dict,
    q_traj_one: np.ndarray,
    q_traj_two: np.ndarray,
    input_axs: None | np.ndarray = None,
) -> None:
    """
    Visualize the Q-values and actions over training episodes.

    Args:
        action_seq (ndarray): sequence of actions played by the players
        config (Dict): configurations of the game
        q_traj_one (ndarray): Q-value trajectory of player one
        q_traj_two (ndarray): Q-value trajectory of player two
        input_axs (ndarray): axes to use for the figures or None to create a new figure,
            default to `None`
    """
    if input_axs is None:  # Make a single figure
        _, axs = plt.subplots(2, 1, gridspec_kw={"height_ratios": [2, 1]})
        axs[0].set_title(
            f'ϵ=({config["params"]["eps"][0]}, {config["params"]["eps"][1]}),'
            f' γ=({config["params"]["gamma"][0]}, {config["params"]["gamma"][1]})'
        )
        axs[0].set_xlabel("Episode")
        axs[0].set_ylabel("Q-value")

    # Agent one
    agent_one_labels = ["$p_1: Q_D$", "$p_1: Q_C$"]
    agent_one_colors = ["b", "g"]
    for action_i in range(config["num_actions"]):
        axs[0].plot(
            q_traj_one[:, action_i],
            color=agent_one_colors[action_i],
            alpha=0.8,
        )
        axs[0].text(
            q_traj_one.shape[0],
            q_traj_one[-1, action_i],
            agent_one_labels[action_i],
            color=agent_one_colors[action_i],
            fontsize=15,
            weight="bold",
            va="bottom",
        )

    # Agent two
    agent_two_labels = ["$p_2: Q_D$", "$p_2: Q_C$"]
    agent_two_colors = ["r", "orange"]
    for action_i in range(config["num_actions"]):
        axs[0].plot(
            q_traj_two[:, action_i],
            color=agent_two_colors[action_i],
            alpha=0.8,
        )
        axs[0].text(
            q_traj_two.shape[0],
            q_traj_two[-1, action_i],
            agent_two_labels[action_i],
            color=agent_two_colors[action_i],
            fontsize=15,
            weight="bold",
            va="top",
        )

    # Add lines between episodes for if few episodes, otherwise leave out
    line_widths = 0.15 if config["num_episodes"] < 200 else 0

    # Obtain combined action matrix
    comb_act = vis_action_matrix(action_seq)

    sns.heatmap(
        comb_act,
        annot=False,
        cbar=False,
        cmap=["w", "darkgreen"],
        vmin=0,
        vmax=1,
        yticklabels=["(D, D)", "(D, C)", "(C, D)", "(C, C)"],
        xticklabels=[],
        linewidths=line_widths,
        linecolor="k",
        ax=axs[1],
    )
    axs[1].set_title("Actions")
    axs[1].set_xlabel("Episode")
    sns.despine()

    if input_axs is None:
        plt.tight_layout()
        plt.show()


from .basehandler import BaseHandler
from ppmessage.api.error import API_ERR

from ppmessage.core.constant import API_LEVEL
from ppmessage.core.constant import REDIS_PPKEFU_ONLINE_KEY

import traceback
import datetime
import logging
import json
import redis

class PPConsoleGetRealTimeServiceNumber(BaseHandler):

    def _get(self):
        _request = json.loads(self.request.body)
        _app_uuid = _request.get("app_uuid")

        if _app_uuid == None:
            logging.error("not enough parameter provided.")
            self.setErrorCode(API_ERR.NO_PARA)
            return

        _redis = self.application.redis
        _number = []
        _today = datetime.datetime.now().strftime("%Y-%m-%d")

        for _i in range(24):
            _agents = set()
            _data = {}
            _key = REDIS_PPKEFU_ONLINE_KEY + ".app_uuid." + _app_uuid + ".day." + _today + ".hour." + str(_i)
            _devices = _redis.smembers(_key)
            for _device in _devices:
                _agents.add(_device.split(".")[0])
            _data[str(_i)] = len(_agents)
            _number.append(_data)
        _r = self.getReturnData()
        _r["number"] = _number
        return

    def initialize(self):
        self.addPermission(app_uuid=True)
        self.addPermission(api_level=API_LEVEL.PPCONSOLE)
        return

    def _Task(self):
        self._get()


from functools import wraps
from contextlib import contextmanager
import sys
import logging

import rq
import rq.job
from rq.utils import ColorizingStreamHandler
from rq.contrib.sentry import register_sentry

from cubicweb.cwconfig import CubicWebConfiguration

from cubicweb_francearchives import admincnx as orig_admincnx, init_bfss

@contextmanager
def admincnx(appid_or_cnx, loglevel=None):
    if isinstance(appid_or_cnx, str):
        with orig_admincnx(appid_or_cnx, loglevel) as cnx:
            yield cnx
    else:
        assert (
            appid_or_cnx.vreg.config.mode == "test"
        ), "expected to be a connection only in test mode"
        yield appid_or_cnx

def rqjob(task):
    @wraps(task)
    def task_wrapper(appid, *args, **kwargs):
        job = rq.get_current_job()
        with admincnx(appid, loglevel="warning") as cnx:
            init_bfss(cnx.repo)
            rqtask = cnx.find("RqTask", eid=int(job.id)).one()
            irqjob = rqtask.cw_adapt_to("IRqJob")
            try:
                result = task(cnx, *args, **kwargs)
            except Exception:
                logging.getLogger("rq.task").exception("An error has occurred.")
                cnx.rollback()
                irqjob.handle_failure(*sys.exc_info())
                cnx.commit()
                raise
            else:
                irqjob.handle_finished()
                cnx.commit()
        return result

    return task_wrapper

class RedisHandler(logging.Handler):
    def emit(self, record):
        job = rq.get_current_job()
        if job is not None:
            key = "rq:job:{0}:log".format(job.id)
            pipe = job.connection.pipeline()
            msg = self.format(record)
            if isinstance(msg, str):
                msg = msg.encode("utf-8")
            pipe.append(key, msg)
            # keep RQ logs 24h in case of non-default timeout
            pipe.expire(key, 86400)
            pipe.execute()

def update_progress(job, progress_value):
    job.meta["progress"] = progress_value
    job.save_meta()
    return progress_value

def config_from_appid(appid_or_cnx):
    if isinstance(appid_or_cnx, str):
        return CubicWebConfiguration.config_for(appid_or_cnx)
    assert appid_or_cnx.vreg.config.mode == "test", "expected to be a connection only in test mode"
    return appid_or_cnx.vreg.config

def work(appid, burst=False, worker_class=rq.Worker):
    logger = logging.getLogger("rq.worker")
    if not logger.handlers:
        logger.setLevel(logging.INFO)
        formatter = logging.Formatter(fmt="%(asctime)s %(message)s", datefmt="%H:%M:%S")
        handler = ColorizingStreamHandler()
        handler.setFormatter(formatter)
        logger.addHandler(handler)
    task_logger = logging.getLogger("rq.task")
    task_logger.setLevel(logging.DEBUG)
    handler = RedisHandler()
    handler.setFormatter(
        logging.Formatter(fmt="%(levelname)s %(asctime)s %(module)s %(process)d %(message)s\n")
    )
    task_logger.addHandler(handler)

    class Job(rq.job.Job):
        @property
        def args(self):
            return (appid,) + super(Job, self).args

    cwconfig = config_from_appid(appid)
    worker = worker_class("default", job_class=Job)
    sentry_dsn = cwconfig.get("sentry-dsn")
    if sentry_dsn:
        register_sentry(sentry_dsn)
    worker.work(burst=burst)


from utils.Error import NoneError
from logs.log import module_log
from dataclasses import dataclass
from utils.Tools import is_none

'''
        this module has guardian class that will contain
        all the guardian information that related to the
        student information.
'''

@dataclass
class guardian:

    ##################################[initialising]#####################################################
    def __init__(self,*args):

        if is_none(args): raise NoneError(f'Guardian.py : function - __init__')

        # create the log
        self.__logger:module_log = module_log(log_name = 'guardian.log',disable_log = False)
        # log the creation
        self.__logger.log.debug(f'__init__ <- {args}')

        #initialize
        self.__name:str
        self.__role:str
        self.__contact:str

        #declaration
        self.__name, self.__role, self.__contact = args
        self.__data:dict = {'name':self.__name, 'contact-no':self.__contact, 'role':self.__role}

    ##################################[guardian properties]#####################################################

    @property
    def name(self) -> str:
        self.__logger.log.info( f'property.getter - name -> {self.__name}')
        return self.__name

    @property
    def contact(self) -> str:
        self.__logger.log.info( f'property.getter - contact -> {self.__contact}')
        return self.__contact

    @property
    def role(self) -> str:
        self.__logger.log.info( f'property.getter - role -> {self.__role}')
        return self.__role

    ##################################[guardian information]#####################################################
    @property
    def data(self) -> dict:
        self.__logger.log.info( f'property.getter - data -> {self.__data}')
        return self.__data

    @data.setter
    def data(self,value: dict) -> None:
        if is_none(value): raise NoneError(f'Guardian.py : property.setter - data')
        self.__name,self.__contact,self.__role = value
        self.__data = value

    def __rpr__(self):
        return f'guardian[ {self.__data} ]'

    def __str__(self):
        return f'guardian[ {self.__data} ]'


import socket
import pygame

# Define client parameters
HOST = '192.168.1.4'  # Server IP address
PORT = 5000  # Port number

# Set up the client socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

# Initialize Pygame
pygame.init()
WIDTH, HEIGHT = 800, 600
win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Car Racing Game")

# Load track image
track_image = pygame.image.load(r'C:\Users\mebra\OneDrive\Desktop\Car Race\img\track.png')  # Replace 'track.png' with the actual image path

# Load car image
car_image = pygame.image.load(r'C:\Users\mebra\OneDrive\Desktop\Car Race\img\Car.png')  # Replace 'car.png' with the actual image path

chat_input = ''

# Game loop
running = True
clock = pygame.time.Clock()
while running:
    clock.tick(60)  # Limit to 60 FPS

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN:
                if chat_input:
                    try:
                        client_socket.sendall(f"CHAT:{chat_input}".encode())
                        chat_input = ''
                    except Exception as e:
                        print(f"Error occurred while sending chat message: {e}")
            elif event.key == pygame.K_BACKSPACE:
                chat_input = chat_input[:-1]
            else:
                chat_input += event.unicode

    keys = pygame.key.get_pressed()
    if keys[pygame.K_UP]:
        player_input = 'UP'
    elif keys[pygame.K_DOWN]:
        player_input = 'DOWN'
    elif keys[pygame.K_LEFT]:
        player_input = 'LEFT'
    elif keys[pygame.K_RIGHT]:
        player_input = 'RIGHT'
    else:
        player_input = ''

    if player_input:
        client_socket.sendall(player_input.encode())

    # Receive game updates from the server
    try:
        game_state = client_socket.recv(1024).decode()

        # Process game state updates
        game_state_data = game_state.split(';')
        player_positions = [tuple(map(int, pos.split(','))) for pos in game_state_data[0].split(':')[1].split(',')]
        player_scores = [int(score) for score in game_state_data[1].split(':')[1].split(',')]

        # Update the game window with the new positions and scores
        win.fill((255, 255, 255))  # Clear the screen

        # Draw the track
        win.blit(track_image, (0, 0))

        # Draw player cars
        for i, pos in enumerate(player_positions):
            # Draw the car image at the player's position
            car_rect = car_image.get_rect(center=pos)
            win.blit(car_image, car_rect)

        # Display player scores
        font = pygame.font.SysFont(None, 24)
        text1 = font.render(f"Player 1 Score: {player_scores[0]}", True, (0, 0, 0))
        text2 = font.render(f"Player 2 Score: {player_scores[1]}", True, (0, 0, 0))
        win.blit(text1, (10, 10))
        win.blit(text2, (10, 40))

        # Display chat input box
        pygame.draw.rect(win, (255, 255, 255), (10, 550, 780, 40))
        pygame.draw.rect(win, (0, 0, 0), (10, 550, 780, 40), 2)
        font = pygame.font.SysFont(None, 24)
        text = font.render(chat_input, True, (0, 0, 0))
        win.blit(text, (20, 560))

        pygame.display.update()
    except ConnectionResetError:
        print("The server has closed the connection.")
        running = False

    except Exception as e:
        print(f"Error occurred during receiving game state: {e}")
        running = False

# Clean up resources
pygame.quit()
client_socket.close()


import uuid
from typing import Dict

import pytest
from temporalio import workflow
from temporalio.client import Client
from temporalio.worker import Replayer, Worker

from hello.hello_failure import SayHelloParams, SayHelloWorkflow, say_hello

async def test_replayer_workflow_complete(client: Client) -> None:
    task_queue_name = str(uuid.uuid4())

    async with Worker(
        client,
        task_queue=task_queue_name,
        workflows=[SayHelloWorkflow],
        activities=[say_hello],
    ):
        async with new_say_hello_worker(client) as worker:
            handle = await client.start_workflow(
                SayHelloWorkflow.run,
                SayHelloParams(name="Temporal"),
                id=f"workflow-{uuid.uuid4()}",
                task_queue=worker.task_queue,
            )
            assert "Hello, Temporal!" == await handle.result()

        await Replayer(workflows=[SayHelloWorkflow]).replay_workflow(
            await handle.fetch_history()
        )

async def test_replayer_workflow_nondeterministic(client: Client) -> None:
    # Run workflow to completion
    async with new_say_hello_worker(client) as worker:
        handle = await client.start_workflow(
            SayHelloWorkflow.run,
            SayHelloParams(name="Temporal", should_cause_nondeterminism=True),
            id=f"workflow-{uuid.uuid4()}",
            task_queue=worker.task_queue,
        )
        await handle.result()
    with pytest.raises(workflow.NondeterminismError):
        await Replayer(workflows=[SayHelloWorkflow]).replay_workflow(
            await handle.fetch_history()
        )

@workflow.defn
class SayHelloWorkflowDifferent:
    @workflow.run
    async def run(self) -> None:
        pass

def new_say_hello_worker(client: Client) -> Worker:
    return Worker(
        client,
        task_queue=str(uuid.uuid4()),
        workflows=[SayHelloWorkflow],
        activities=[say_hello],
    )


"""
Ported to Python3.

Futz with files like a pro.
"""

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from future.utils import PY2
if PY2:
    # open is not here because we want to use native strings on Py2
    from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, pow, round, super, bytes, dict, list, object, range, str, max, min  # noqa: F401

import sys, os, stat, tempfile, time, binascii
import six
from collections import namedtuple
from errno import ENOENT

if sys.platform == "win32":
    from ctypes import WINFUNCTYPE, WinError, windll, POINTER, byref, c_ulonglong, \
        create_unicode_buffer, get_last_error
    from ctypes.wintypes import BOOL, DWORD, LPCWSTR, LPWSTR, LPVOID

from twisted.python import log

from allmydata.crypto import aes
from allmydata.util.assertutil import _assert

def rename(src, dst, tries=4, basedelay=0.1):
    """ Here is a superkludge to workaround the fact that occasionally on
    Windows some other process (e.g. an anti-virus scanner, a local search
    engine, etc.) is looking at your file when you want to delete or move it,
    and hence you can't.  The horrible workaround is to sit and spin, trying
    to delete it, for a short time and then give up.

    With the default values of tries and basedelay this can block for less
    than a second.

    @param tries: number of tries -- each time after the first we wait twice
    as long as the previous wait
    @param basedelay: how long to wait before the second try
    """
    for i in range(tries-1):
        try:
            return os.rename(src, dst)
        except EnvironmentError as le:
            # XXX Tighten this to check if this is a permission denied error (possibly due to another Windows process having the file open and execute the superkludge only in this case.
            log.msg("XXX KLUDGE Attempting to move file %s => %s; got %s; sleeping %s seconds" % (src, dst, le, basedelay,))
            time.sleep(basedelay)
            basedelay *= 2
    return os.rename(src, dst) # The last try.

def remove(f, tries=4, basedelay=0.1):
    """ Here is a superkludge to workaround the fact that occasionally on
    Windows some other process (e.g. an anti-virus scanner, a local search
    engine, etc.) is looking at your file when you want to delete or move it,
    and hence you can't.  The horrible workaround is to sit and spin, trying
    to delete it, for a short time and then give up.

    With the default values of tries and basedelay this can block for less
    than a second.

    @param tries: number of tries -- each time after the first we wait twice
    as long as the previous wait
    @param basedelay: how long to wait before the second try
    """
    try:
        os.chmod(f, stat.S_IWRITE | stat.S_IEXEC | stat.S_IREAD)
    except:
        pass
    for i in range(tries-1):
        try:
            return os.remove(f)
        except EnvironmentError as le:
            # XXX Tighten this to check if this is a permission denied error (possibly due to another Windows process having the file open and execute the superkludge only in this case.
            if not os.path.exists(f):
                return
            log.msg("XXX KLUDGE Attempting to remove file %s; got %s; sleeping %s seconds" % (f, le, basedelay,))
            time.sleep(basedelay)
            basedelay *= 2
    return os.remove(f) # The last try.

class ReopenableNamedTemporaryFile(object):
    """
    This uses tempfile.mkstemp() to generate a secure temp file.  It then closes
    the file, leaving a zero-length file as a placeholder.  You can get the
    filename with ReopenableNamedTemporaryFile.name.  When the
    ReopenableNamedTemporaryFile instance is garbage collected or its shutdown()
    method is called, it deletes the file.
    """
    def __init__(self, *args, **kwargs):
        fd, self.name = tempfile.mkstemp(*args, **kwargs)
        os.close(fd)

    def __repr__(self):
        return "<%s instance at %x %s>" % (self.__class__.__name__, id(self), self.name)

    def __str__(self):
        return self.__repr__()

    def __del__(self):
        self.shutdown()

    def shutdown(self):
        remove(self.name)

class EncryptedTemporaryFile(object):
    # not implemented: next, readline, readlines, xreadlines, writelines

    def __init__(self):
        self.file = tempfile.TemporaryFile()
        self.key = os.urandom(16)  # AES-128

    def _crypt(self, offset, data):
        offset_big = offset // 16
        offset_small = offset % 16
        iv = binascii.unhexlify("%032x" % offset_big)
        cipher = aes.create_encryptor(self.key, iv)
        # this is just to advance the counter
        aes.encrypt_data(cipher, b"\x00" * offset_small)
        return aes.encrypt_data(cipher, data)

    def close(self):
        self.file.close()

    def flush(self):
        self.file.flush()

    def seek(self, offset, whence=0):  # 0 = SEEK_SET
        self.file.seek(offset, whence)

    def tell(self):
        offset = self.file.tell()
        return offset

    def read(self, size=-1):
        """A read must not follow a write, or vice-versa, without an intervening seek."""
        index = self.file.tell()
        ciphertext = self.file.read(size)
        plaintext = self._crypt(index, ciphertext)
        return plaintext

    def write(self, plaintext):
        """A read must not follow a write, or vice-versa, without an intervening seek.
        If seeking and then writing causes a 'hole' in the file, the contents of the
        hole are unspecified."""
        index = self.file.tell()
        ciphertext = self._crypt(index, plaintext)
        self.file.write(ciphertext)

    def truncate(self, newsize):
        """Truncate or extend the file to 'newsize'. If it is extended, the contents after the
        old end-of-file are unspecified. The file position after this operation is unspecified."""
        self.file.truncate(newsize)

def make_dirs_with_absolute_mode(parent, dirname, mode):
    """
    Make directory `dirname` and chmod it to `mode` afterwards.
    We chmod all parent directories of `dirname` until we reach
    `parent`.
    """
    precondition_abspath(parent)
    precondition_abspath(dirname)
    if not is_ancestor_path(parent, dirname):
        raise AssertionError("dirname must be a descendant of parent")

    make_dirs(dirname)
    while dirname != parent:
        os.chmod(dirname, mode)
        # FIXME: doesn't seem to work on Windows for long paths
        old_dirname, dirname = dirname, os.path.dirname(dirname)
        _assert(len(dirname) < len(old_dirname), dirname=dirname, old_dirname=old_dirname)

def is_ancestor_path(parent, dirname):
    while dirname != parent:
        # FIXME: doesn't seem to work on Windows for long paths
        old_dirname, dirname = dirname, os.path.dirname(dirname)
        if len(dirname) >= len(old_dirname):
            return False
    return True

def make_dirs(dirname, mode=0o777):
    """
    An idempotent version of os.makedirs().  If the dir already exists, do
    nothing and return without raising an exception.  If this call creates the
    dir, return without raising an exception.  If there is an error that
    prevents creation or if the directory gets deleted after make_dirs() creates
    it and before make_dirs() checks that it exists, raise an exception.
    """
    tx = None
    try:
        os.makedirs(dirname, mode)
    except OSError as x:
        tx = x

    if not os.path.isdir(dirname):
        if tx:
            raise tx
        raise IOError("unknown error prevented creation of directory, or deleted the directory immediately after creation: %s" % dirname) # careful not to construct an IOError with a 2-tuple, as that has a special meaning...

def rm_dir(dirname):
    """
    A threadsafe and idempotent version of shutil.rmtree().  If the dir is
    already gone, do nothing and return without raising an exception.  If this
    call removes the dir, return without raising an exception.  If there is an
    error that prevents deletion or if the directory gets created again after
    rm_dir() deletes it and before rm_dir() checks that it is gone, raise an
    exception.
    """
    excs = []
    try:
        os.chmod(dirname, stat.S_IWRITE | stat.S_IEXEC | stat.S_IREAD)
        for f in os.listdir(dirname):
            fullname = os.path.join(dirname, f)
            if os.path.isdir(fullname):
                rm_dir(fullname)
            else:
                remove(fullname)
        os.rmdir(dirname)
    except Exception as le:
        # Ignore "No such file or directory"
        if (not isinstance(le, OSError)) or le.args[0] != 2:
            excs.append(le)

    # Okay, now we've recursively removed everything, ignoring any "No
    # such file or directory" errors, and collecting any other errors.

    if os.path.exists(dirname):
        if len(excs) == 1:
            raise excs[0]
        if len(excs) == 0:
            raise OSError("Failed to remove dir for unknown reason.")
        raise OSError(excs)

def remove_if_possible(f):
    try:
        remove(f)
    except:
        pass

def du(basedir):
    size = 0

    for root, dirs, files in os.walk(basedir):
        for f in files:
            fn = os.path.join(root, f)
            size += os.path.getsize(fn)

    return size

def move_into_place(source, dest):
    """Atomically replace a file, or as near to it as the platform allows.
    The dest file may or may not exist."""
    if "win32" in sys.platform.lower() and os.path.exists(source):
        # we check for source existing since we don't want to nuke the
        # dest unless we'll succeed at moving the target into place
        remove_if_possible(dest)
    os.rename(source, dest)

def write_atomically(target, contents, mode="b"):
    assert (
        isinstance(contents, bytes) and "b" in mode or
        isinstance(contents, str) and "t" in mode or mode == ""), (type(contents), mode)
    with open(target+".tmp", "w"+mode) as f:
        f.write(contents)
    move_into_place(target+".tmp", target)

def write(path, data, mode="wb"):
    if "b" in mode and isinstance(data, str):
        data = data.encode("utf-8")
    with open(path, mode) as f:
        f.write(data)

def read(path, mode="rb"):
    with open(path, mode) as rf:
        return rf.read()

def put_file(path, inf):
    precondition_abspath(path)

    # TODO: create temporary file and move into place?
    with open(path, "wb") as outf:
        while True:
            data = inf.read(32768)
            if not data:
                break
            outf.write(data)

def precondition_abspath(path):
    if not isinstance(path, str):
        raise AssertionError("an abspath must be a Unicode string")

    if sys.platform == "win32":
        # This intentionally doesn't view absolute paths starting with a drive specification, or
        # paths relative to the current drive, as acceptable.
        if not path.startswith("\\\\"):
            raise AssertionError("an abspath should be normalized using abspath_expanduser_unicode")
    else:
        # This intentionally doesn't view the path '~' or paths starting with '~/' as acceptable.
        if not os.path.isabs(path):
            raise AssertionError("an abspath should be normalized using abspath_expanduser_unicode")

# Work around <http://bugs.python.org/issue3426>. This code is adapted from
# <http://svn.python.org/view/python/trunk/Lib/ntpath.py?revision=78247&view=markup>
# with some simplifications.

_getfullpathname = None
try:
    from nt import _getfullpathname  # type: ignore
except ImportError:
    pass

def abspath_expanduser_unicode(path, base=None, long_path=True):
    """
    Return the absolute version of a path. If 'base' is given and 'path' is relative,
    the path will be expanded relative to 'base'.
    'path' must be a Unicode string. 'base', if given, must be a Unicode string
    corresponding to an absolute path as returned by a previous call to
    abspath_expanduser_unicode.
    On Windows, the result will be a long path unless long_path is given as False.
    """
    if not isinstance(path, str):
        raise AssertionError("paths must be Unicode strings")
    if base is not None and long_path:
        precondition_abspath(base)

    path = expanduser(path)

    if _getfullpathname:
        # On Windows, os.path.isabs will incorrectly return True
        # for paths without a drive letter (that are not UNC paths),
        # e.g. "\\". See <http://bugs.python.org/issue1669539>.
        try:
            if base is None:
                path = _getfullpathname(path or u".")
            else:
                path = _getfullpathname(os.path.join(base, path))
        except OSError:
            pass

    if not os.path.isabs(path):
        if base is None:
            cwd = os.getcwd()
            if PY2:
                cwd = cwd.decode('utf8')
            path = os.path.join(cwd, path)
        else:
            path = os.path.join(base, path)

    # We won't hit <http://bugs.python.org/issue5827> because
    # there is always at least one Unicode path component.
    path = os.path.normpath(path)

    if sys.platform == "win32" and long_path:
        path = to_windows_long_path(path)

    return path

def to_windows_long_path(path):
    # '/' is normally a perfectly valid path component separator in Windows.
    # However, when using the "\\?\" syntax it is not recognized, so we
    # replace it with '\' here.
    path = path.replace(u"/", u"\\")

    # Note that other normalizations such as removing '.' and '..' should
    # be done outside this function.

    if path.startswith(u"\\\\?\\") or path.startswith(u"\\\\.\\"):
        return path
    elif path.startswith(u"\\\\"):
        return u"\\\\?\\UNC\\" + path[2 :]
    else:
        return u"\\\\?\\" + path

have_GetDiskFreeSpaceExW = False
if sys.platform == "win32":
    # <http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188%28v=vs.85%29.aspx>
    GetEnvironmentVariableW = WINFUNCTYPE(
        DWORD,  LPCWSTR, LPWSTR, DWORD,
        use_last_error=True
    )(("GetEnvironmentVariableW", windll.kernel32))

    try:
        # <http://msdn.microsoft.com/en-us/library/aa383742%28v=VS.85%29.aspx>
        PULARGE_INTEGER = POINTER(c_ulonglong)

        # <http://msdn.microsoft.com/en-us/library/aa364937%28VS.85%29.aspx>
        GetDiskFreeSpaceExW = WINFUNCTYPE(
            BOOL,  LPCWSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER,
            use_last_error=True
        )(("GetDiskFreeSpaceExW", windll.kernel32))

        have_GetDiskFreeSpaceExW = True
    except Exception:
        import traceback
        traceback.print_exc()

def expanduser(path):
    # os.path.expanduser is hopelessly broken for Unicode paths on Windows (ticket #1674).
    if sys.platform == "win32":
        return windows_expanduser(path)
    else:
        return os.path.expanduser(path)

def windows_expanduser(path):
    if not path.startswith('~'):
        return path

    home_dir = windows_getenv(u'USERPROFILE')
    if home_dir is None:
        home_drive = windows_getenv(u'HOMEDRIVE')
        home_path = windows_getenv(u'HOMEPATH')
        if home_drive is None or home_path is None:
            raise OSError("Could not find home directory: neither %USERPROFILE% nor (%HOMEDRIVE% and %HOMEPATH%) are set.")
        home_dir = os.path.join(home_drive, home_path)

    if path == '~':
        return home_dir
    elif path.startswith('~/') or path.startswith('~\\'):
        return os.path.join(home_dir, path[2 :])
    else:
        return path

# <https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx>
ERROR_ENVVAR_NOT_FOUND = 203

def windows_getenv(name):
    # Based on <http://stackoverflow.com/questions/2608200/problems-with-umlauts-in-python-appdata-environvent-variable/2608368#2608368>,
    # with improved error handling. Returns None if there is no enivronment variable of the given name.
    if not isinstance(name, str):
        raise AssertionError("name must be Unicode")

    n = GetEnvironmentVariableW(name, None, 0)
    # GetEnvironmentVariableW returns DWORD, so n cannot be negative.
    if n == 0:
        err = get_last_error()
        if err == ERROR_ENVVAR_NOT_FOUND:
            return None
        raise OSError("WinError: %s\n attempting to read size of environment variable %r"
                      % (WinError(err), name))
    if n == 1:
        # Avoid an ambiguity between a zero-length string and an error in the return value of the
        # call to GetEnvironmentVariableW below.
        return u""

    buf = create_unicode_buffer(u'\0'*n)
    retval = GetEnvironmentVariableW(name, buf, n)
    if retval == 0:
        err = get_last_error()
        if err == ERROR_ENVVAR_NOT_FOUND:
            return None
        raise OSError("WinError: %s\n attempting to read environment variable %r"
                      % (WinError(err), name))
    if retval >= n:
        raise OSError("Unexpected result %d (expected less than %d) from GetEnvironmentVariableW attempting to read environment variable %r"
                      % (retval, n, name))

    return buf.value

def get_disk_stats(whichdir, reserved_space=0):
    """Return disk statistics for the storage disk, in the form of a dict
    with the following fields.
      total:            total bytes on disk
      free_for_root:    bytes actually free on disk
      free_for_nonroot: bytes free for "a non-privileged user" [Unix] or
                          the current user [Windows]; might take into
                          account quotas depending on platform
      used:             bytes used on disk
      avail:            bytes available excluding reserved space
    An AttributeError can occur if the OS has no API to get disk information.
    An EnvironmentError can occur if the OS call fails.

    whichdir is a directory on the filesystem in question -- the
    answer is about the filesystem, not about the directory, so the
    directory is used only to specify which filesystem.

    reserved_space is how many bytes to subtract from the answer, so
    you can pass how many bytes you would like to leave unused on this
    filesystem as reserved_space.
    """

    if have_GetDiskFreeSpaceExW:
        # If this is a Windows system and GetDiskFreeSpaceExW is available, use it.
        # (This might put up an error dialog unless
        # SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX) has been called,
        # which we do in allmydata.windows.fixups.initialize().)

        n_free_for_nonroot = c_ulonglong(0)
        n_total            = c_ulonglong(0)
        n_free_for_root    = c_ulonglong(0)
        retval = GetDiskFreeSpaceExW(whichdir, byref(n_free_for_nonroot),
                                               byref(n_total),
                                               byref(n_free_for_root))
        if retval == 0:
            raise OSError("WinError: %s\n attempting to get disk statistics for %r"
                          % (WinError(get_last_error()), whichdir))
        free_for_nonroot = n_free_for_nonroot.value
        total            = n_total.value
        free_for_root    = n_free_for_root.value
    else:
        # For Unix-like systems.
        # <http://docs.python.org/library/os.html#os.statvfs>
        # <http://opengroup.org/onlinepubs/7990989799/xsh/fstatvfs.html>
        # <http://opengroup.org/onlinepubs/7990989799/xsh/sysstatvfs.h.html>
        s = os.statvfs(whichdir)

        # on my mac laptop:
        #  statvfs(2) is a wrapper around statfs(2).
        #    statvfs.f_frsize = statfs.f_bsize :
        #     "minimum unit of allocation" (statvfs)
        #     "fundamental file system block size" (statfs)
        #    statvfs.f_bsize = statfs.f_iosize = stat.st_blocks : preferred IO size
        # on an encrypted home directory ("FileVault"), it gets f_blocks
        # wrong, and s.f_blocks*s.f_frsize is twice the size of my disk,
        # but s.f_bavail*s.f_frsize is correct

        total = s.f_frsize * s.f_blocks
        free_for_root = s.f_frsize * s.f_bfree
        free_for_nonroot = s.f_frsize * s.f_bavail

    # valid for all platforms:
    used = total - free_for_root
    avail = max(free_for_nonroot - reserved_space, 0)

    return { 'total': total,
             'free_for_root': free_for_root,
             'free_for_nonroot': free_for_nonroot,
             'used': used,
             'avail': avail,
           }

def get_available_space(whichdir, reserved_space):
    """Returns available space for share storage in bytes, or None if no
    API to get this information is available.

    whichdir is a directory on the filesystem in question -- the
    answer is about the filesystem, not about the directory, so the
    directory is used only to specify which filesystem.

    reserved_space is how many bytes to subtract from the answer, so
    you can pass how many bytes you would like to leave unused on this
    filesystem as reserved_space.
    """
    try:
        return get_disk_stats(whichdir, reserved_space)['avail']
    except AttributeError:
        return None
    except EnvironmentError:
        log.msg("OS call to get disk statistics failed")
        return 0

class ConflictError(Exception):
    pass

class UnableToUnlinkReplacementError(Exception):
    pass

def reraise(wrapper):
    cls, exc, tb = sys.exc_info()
    wrapper_exc = wrapper("%s: %s" % (cls.__name__, exc))
    six.reraise(wrapper, wrapper_exc, tb)

if sys.platform == "win32":
    # <https://msdn.microsoft.com/en-us/library/windows/desktop/aa365512%28v=vs.85%29.aspx>
    ReplaceFileW = WINFUNCTYPE(
        BOOL,  LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID,
        use_last_error=True
    )(("ReplaceFileW", windll.kernel32))

    REPLACEFILE_IGNORE_MERGE_ERRORS = 0x00000002

    # <https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx>
    ERROR_FILE_NOT_FOUND = 2

    def rename_no_overwrite(source_path, dest_path):
        os.rename(source_path, dest_path)

    def replace_file(replaced_path, replacement_path):
        precondition_abspath(replaced_path)
        precondition_abspath(replacement_path)

        # no "backup" path (the first None) because we don't want to
        # create a backup file
        r = ReplaceFileW(replaced_path, replacement_path, None,
                         REPLACEFILE_IGNORE_MERGE_ERRORS, None, None)
        if r == 0:
            # The UnableToUnlinkReplacementError case does not happen on Windows;
            # all errors should be treated as signalling a conflict.
            err = get_last_error()
            if err != ERROR_FILE_NOT_FOUND:
                raise ConflictError("WinError: %s" % (WinError(err),))

            try:
                move_into_place(replacement_path, replaced_path)
            except EnvironmentError:
                reraise(ConflictError)
else:
    def rename_no_overwrite(source_path, dest_path):
        # link will fail with EEXIST if there is already something at dest_path.
        os.link(source_path, dest_path)
        try:
            os.unlink(source_path)
        except EnvironmentError:
            reraise(UnableToUnlinkReplacementError)

    def replace_file(replaced_path, replacement_path):
        precondition_abspath(replaced_path)
        precondition_abspath(replacement_path)

        if not os.path.exists(replacement_path):
            raise ConflictError("Replacement file not found: %r" % (replacement_path,))

        try:
            move_into_place(replacement_path, replaced_path)
        except OSError as e:
            if e.errno != ENOENT:
                raise
        except EnvironmentError:
            reraise(ConflictError)

PathInfo = namedtuple('PathInfo', 'isdir isfile islink exists size mtime_ns ctime_ns')

def seconds_to_ns(t):
    return int(t * 1000000000)

def get_pathinfo(path_u, now_ns=None):
    try:
        statinfo = os.lstat(path_u)
        mode = statinfo.st_mode
        return PathInfo(isdir   =stat.S_ISDIR(mode),
                        isfile  =stat.S_ISREG(mode),
                        islink  =stat.S_ISLNK(mode),
                        exists  =True,
                        size    =statinfo.st_size,
                        mtime_ns=seconds_to_ns(statinfo.st_mtime),
                        ctime_ns=seconds_to_ns(statinfo.st_ctime),
                       )
    except OSError as e:
        if e.errno == ENOENT:
            if now_ns is None:
                now_ns = seconds_to_ns(time.time())
            return PathInfo(isdir   =False,
                            isfile  =False,
                            islink  =False,
                            exists  =False,
                            size    =None,
                            mtime_ns=now_ns,
                            ctime_ns=now_ns,
                           )
        raise


# 处理用户的常用词及从用词的出现次数

from collections import Counter
import pymongo
from append_userArticle.jieba_cut import articles_common_words

def user_commWords_weight(user_homepage=None, limit=500, skip=0):
    """
    根据输入的 user_homepage 对用户的文章,利用 jieba库 进行分词，并统计出用户每篇文章常用词、用户前100常用词；
    对应前100常用词的出现次数存入 commonWords_v5 集合
    :param user_homepage:
    :return:
    """

    # 连接 mongoDB数据库
    client = pymongo.MongoClient("mongodb://127.0.0.1:27017/")
    # jianshu_huaxiang 数据库名
    db = client['jianshu_huaxiang']
    # site 集合表名 存放用户文章
    collection_UA = db['site']

    # 常用词 集合表名 存放用户常用词及常用词权重
    collection_CW_v5 = db['commonWords_v5']

    if user_homepage:
        res = collection_UA.find({'user_homepage': user_homepage})
    else:
        res = collection_UA.find().limit(limit).skip(skip)

    # 遍历得到用户对象
    for user in res:
        print(user['nickname'])
        # 作者常用词列表
        user_commonWords = []
        # print(user['user_homepage'])
        # 将数据库当前前用户的 nickname 、user_homepage 拼接成字典类型
        user_infro = {}
        user_infro['nickname'] = user['nickname']
        user_infro['user_homepage'] = user['user_homepage']
        user_infro['gender'] = user['gender']
        # 为处理 文章分词开辟新的 列表空间
        user_infro['article_commonWords'] = []

        # 以用户常用词作为 key, 用户常用词出现的次数作为 value
        user_infro['user_commonWords'] = []

        # 用户信息数据提交数据库，新增至 commonWords 集合
        collection_CW_v5.insert_one(user_infro)

        user_article = user['user_article']
        # 每篇文章的常用词
        top_words = 50
        for piece in range(len(user_article)):
            # 一篇文章的常用词
            user_article_first = user_article[piece]['content']  # 文章内容
            title = user_article[piece]['title']  # 文章标题

            if piece % 10 == 0:
                print("第{piece}篇:".format(piece=piece + 1))
            top_word_list = articles_common_words(user_article_first, top_words)
            article_commonWords = []
            # 遍历 top_word_list列表 整合为str类型对象
            for j in range(len(top_word_list)):
                # print(str(top_word_list[j][0]), end=',')
                article_commonWords.append(top_word_list[j][0])

                # 作者常用词
                user_commonWords.append(top_word_list[j][0])

            # print(' '.join(article_uselyWords))
            # 提交保存当前用户文章的常用词
            article = {}
            article['title'] = title
            # article['common_words'] = str(article_commonWords)
            article['common_words'] = ','.join(article_commonWords)
            user_homepage = user_infro['user_homepage']
            collection_CW_v5.update_one({"user_homepage": user_homepage},
                                        {"$addToSet": {"article_commonWords": {"$each": [article]}}})

        counter = Counter(user_commonWords)
        list_words = counter.most_common()
        # print(list_words[:100])
        user_commonWords_dict = {}
        # list_words 列表套元组 100项中每一项 转为字典对象 存入commonWords_v4 集合表
        for item in list_words[:100]:
            commWord = {}
            # 以用户常用词作为 key, 用户常用词出现的次数作为 value
            commWord[item[0]] = item[1]
            collection_CW_v5.update_one({"user_homepage": user_homepage},
                                        {"$addToSet": {"user_commonWords": {"$each": [commWord]}}})

            user_commonWords_dict[item[0]] = item[1]

        # print(user_commonWords_dict)

        # 把 user_commonWords_dict 更新至 commonWords_v5 集合
        collection_CW_v5.update_one({"user_homepage": user_homepage}, {"$set": {"user_commonWords_dict": user_commonWords_dict}})

if __name__ == '__main__':
    user_homepage = 'https://www.jianshu.com/u/b8f58ffc3272'
    user_commWords_weight(user_homepage)


import argparse
import os
import random
import sys

import numpy as np
import torch
from guacamol.distribution_learning_benchmark import ValidityBenchmark, UniquenessBenchmark, KLDivBenchmark
from torch.nn.utils import clip_grad_norm_

# guacamol stuff
from ar_mock_generator import ARMockGenerator, generate_smiles
from src.data.loader import load_smiles_data
from src.logger import create_logger
from src.model.transformer import TransformerModel
from src.utils import bool_flag, set_seed, get_optimizer

def get_parser():
    """
    Generate a parameters parser.
    """
    # parse parameters
    parser = argparse.ArgumentParser(description="Language transfer")

    # main parameters
    parser.add_argument("--dump_path", type=str, default='dumped/', help="Experiment dump path")
    parser.add_argument("--multi_gpu", type=bool_flag, default=False,
                        help="Train model on multiple gpus")
    parser.add_argument("--exp_name", type=str, default="",
                        help="Experiment name")
    parser.add_argument("--exp_id", type=str, default="",
                        help="Experiment ID")
    parser.add_argument("--data_path", type=str, default="",
                        help="Data path for QM9, train data path for ChEMBL")
    parser.add_argument("--val_data_path", type=str, default="",
                        help="Validation data path for ChEMBL")
    parser.add_argument("--load_path", type=str, default=None,
                        help="Path for loading checkpoint")
    parser.add_argument("--seed", type=int, default=0,
                        help="random seed")
    parser.add_argument("--graph_type", default=None)
    parser.add_argument("--data_type", choices=['QM9', 'ChEMBL'], default='ChEMBL')
    parser.add_argument("--num_node_types", type=int, default=None)
    parser.add_argument("--num_edge_types", type=int, default=None)
    parser.add_argument("--max_nodes", type=int, default=None)
    parser.add_argument("--use_smiles", action='store_true', help='Use smiles representation of the molecules')
    parser.add_argument("--targets", action='store_true')
    parser.add_argument("--max_vocab", type=int, default=-1,
                        help="Maximum vocabulary size (-1 to disable)")
    parser.add_argument("--min_count", type=int, default=0,
                        help="Minimum vocabulary count")
    # model parameters
    parser.add_argument("--emb_dim", type=int, default=512,
                        help="Embedding layer size")
    parser.add_argument("--n_layers", type=int, default=4,
                        help="Number of Transformer layers")
    parser.add_argument("--n_heads", type=int, default=8,
                        help="Number of Transformer heads")
    parser.add_argument("--dropout", type=float, default=0,
                        help="Dropout")
    parser.add_argument("--attention_dropout", type=float, default=0,
                        help="Dropout in the attention layer")
    parser.add_argument("--gelu_activation", type=bool_flag, default=False,
                        help="Use a GELU activation instead of ReLU")
    parser.add_argument("--share_inout_emb", type=bool_flag, default=True,
                        help="Share input and output embeddings")
    parser.add_argument("--sinusoidal_embeddings", type=bool_flag, default=False,
                        help="Use sinusoidal embeddings")

    # adaptive softmax
    parser.add_argument("--asm", type=bool_flag, default=False,
                        help="Use adaptive softmax")
    if parser.parse_known_args()[0].asm:
        parser.add_argument("--asm_cutoffs", type=str, default="8000,20000",
                            help="Adaptive softmax cutoffs")
        parser.add_argument("--asm_div_value", type=float, default=4,
                            help="Adaptive softmax cluster sizes ratio")

    # optimizer parameters
    parser.add_argument("--split_data", type=bool_flag, default=False,
                        help="Split data across workers of a same node")
    parser.add_argument("--optimizer", type=str, default="adam,beta1=0.9,beta2=0.98,lr=0.0003",
                        help="Optimizer (SGD / RMSprop / Adam, etc.)")
    parser.add_argument("--clip_grad_norm", type=float, default=5.0)

    # batch parameters
    parser.add_argument("--batch_size", type=int, default=32,
                        help="Number of sentences per batch")
    parser.add_argument("--bptt", type=int, default=1024,
                        help="Sequence length")
    parser.add_argument("--max_len", type=int, default=300,
                        help="Maximum length of sentences (after splitting into chars)")
    parser.add_argument("--tokens_per_batch", type=int, default=-1,
                        help="Number of tokens per batch")
    parser.add_argument("--max_batch_size", type=int, default=0,
                        help="Maximum number of sentences per batch (used in combination with tokens_per_batch, 0 to disable)")

    # beam search (for MT only)
    parser.add_argument("--beam_size", type=int, default=1,
                        help="Beam size, default = 1 (greedy decoding)")
    parser.add_argument("--length_penalty", type=float, default=1,
                        help="Length penalty, values < 1.0 favor shorter sentences, while values > 1.0 favor longer ones.")
    parser.add_argument("--early_stopping", type=bool_flag, default=False,
                        help="Early stopping, stop as soon as we have `beam_size` hypotheses, although longer ones may have better scores.")

    # evaluation
    parser.add_argument("--eval_only", type=bool_flag, default=False,
                        help="Only run evaluations")
    parser.add_argument("--epoch_size", type=int, default=100000,
                        help="Epoch size / evaluation frequency (-1 for parallel data size)")
    parser.add_argument("--print_after", type=int, default=5,
                        help="Print after certain number of iters")

    # refinement steps (for MT encoder model only)
    parser.add_argument("--refinement_steps", type=int, default=1,
                        help="Number of refinement steps for L->R decoding of encoder_only (TLM) model")

    # debug
    parser.add_argument('--local_cpu', action='store_true')
    parser.add_argument("--debug_train", type=bool_flag, default=False,
                        help="Use valid sets for train sets (faster loading)")
    parser.add_argument("--debug_slurm", type=bool_flag, default=False,
                        help="Debug multi-GPU / multi-node within a SLURM job")
    # debug params
    parser.add_argument('--debug_small', action='store_true', help='Debug on a very small version of full dataset')
    parser.add_argument('--debug_fixed', action='store_true', help='Debug by masking out fixed nodes and edges corresponding to index 0')
    parser.add_argument('--tensorboard', action='store_true', help='Use tensorboard')
    parser.add_argument('--log_train_steps', default=200, help='train steps to log')
    parser.add_argument('--val_after', default=1000, type=int, help='validate after how many steps')
    parser.add_argument('--max_steps', default=10e6, type=int, help='total number of steps')

    return parser

if 'post' not in torch.__version__:
    version = [int(i) for i in torch.__version__.split('.')]
else:
    version = [int(i) for i in torch.__version__.split('.')[:-1]]
if version[0] >= 1 and version[1] >= 2:
    index_method = 'bool'
else:
    index_method = 'byte'

def calculate_loss(model, batch, params, get_scores=False):
    # process data
    x, len = batch
    if params.local_cpu is False:
        x = x.cuda()
        len = len.cuda()

    # feedforward through model
    hid = model('fwd', x=x, lengths=len, causal=True)

    # target indixes to predict (depending on length)
    alen = torch.arange(len.max(), dtype=torch.long, device=len.device)
    pred_mask = alen[:, None] < len[None] - 1  # do not predict anything given the last target word
    y = x[1:].masked_select(pred_mask[:-1])
    assert y.shape[0] == (len - 1).sum().item()

    # loss
    if get_scores:
        scores, loss = model('predict', tensor=hid, pred_mask=pred_mask, y=y, get_scores=True)
        return scores, loss, y
    else:
        _, loss = model('predict', tensor=hid, pred_mask=pred_mask, y=y, get_scores=False)
        return loss

def save_model(params, data, model, opt, dico, logger, name, epoch, total_iter, scores):
    """
    Save the model.
    """
    path = os.path.join(params.dump_path, params.exp_name, '%s.pth' % name)
    logger.info('Saving models to %s ...' % path)
    data = {}
    # save actual model
    if params.multi_gpu:
        data['model'] = model.module.state_dict()
    else:
        data['model'] = model.state_dict()
    data['optimizer'] = opt.state_dict()
    # save optimizer parameters as well
    data['dico_id2word'] = dico.id2word
    data['dico_word2id'] = dico.word2id
    data['dico_counts'] = dico.counts
    data['params'] = {k: v for k, v in params.__dict__.items()}
    data['epoch'] = epoch
    data['total_iter'] = total_iter
    data['scores'] = scores

    torch.save(data, path)

def load_model(params, model, opt, logger):
    logger.info('Reloading models from %s ...' % params.load_path)
    data = torch.load(params.load_path, map_location=lambda storage, loc: storage.cuda(-1))

    model.load_state_dict(data['model'])
    opt.load_state_dict(data['optimizer'])
    logger.info('Done reloading model')
    return data['total_iter'], data['scores']

def main(params):
    # setup random seeds
    set_seed(params.seed)
    params.ar = True

    exp_path = os.path.join(params.dump_path, params.exp_name)
    # create exp path if it doesn't exist
    if not os.path.exists(exp_path):
        os.makedirs(exp_path)
    # create logger
    logger = create_logger(os.path.join(exp_path, 'train.log'), 0)
    logger.info("============ Initialized logger ============")
    logger.info("Random seed is {}".format(params.seed))
    logger.info("\n".join("%s: %s" % (k, str(v))
                          for k, v in sorted(dict(vars(params)).items())))
    logger.info("The experiment will be stored in %s\n" % exp_path)
    logger.info("Running command: %s" % 'python ' + ' '.join(sys.argv))
    logger.info("")
    # load data
    data, loader = load_smiles_data(params)
    if params.data_type == 'ChEMBL':
        all_smiles_mols = open(os.path.join(params.data_path, 'guacamol_v1_all.smiles'), 'r').readlines()
    else:
        all_smiles_mols = open(os.path.join(params.data_path, 'QM9_all.smiles'), 'r').readlines()
    train_data, val_data = data['train'], data['valid']
    dico = data['dico']
    logger.info ('train_data len is {}'.format(len(train_data)))
    logger.info ('val_data len is {}'.format(len(val_data)))

    # keep cycling through train_loader forever
    # stop when max iters is reached
    def rcycle(iterable):
        saved = []                 # In-memory cache
        for element in iterable:
            yield element
            saved.append(element)
        while saved:
            random.shuffle(saved)  # Shuffle every batch
            for element in saved:
                  yield element
    train_loader = rcycle(train_data.get_iterator(shuffle=True, group_by_size=True, n_sentences=-1))

    # extra param names for transformermodel
    params.n_langs = 1
    # build Transformer model
    model = TransformerModel(params, is_encoder=False, with_output=True)

    if params.local_cpu is False:
        model = model.cuda()
    opt = get_optimizer(model.parameters(), params.optimizer)
    scores = {'ppl': np.float('inf'), 'acc': 0}

    if params.load_path:
        reloaded_iter, scores = load_model(params, model, opt, logger)

    for total_iter, train_batch in enumerate(train_loader):
        if params.load_path is not None:
            total_iter += reloaded_iter + 1

        epoch = total_iter // params.epoch_size
        if total_iter == params.max_steps:
            logger.info("============ Done training ... ============")
            break
        elif total_iter % params.epoch_size == 0:
            logger.info("============ Starting epoch %i ... ============" % epoch)
        model.train()
        opt.zero_grad()
        train_loss = calculate_loss(model, train_batch, params)
        train_loss.backward()
        if params.clip_grad_norm > 0:
            clip_grad_norm_(model.parameters(), params.clip_grad_norm)
        opt.step()
        if total_iter % params.print_after == 0:
            logger.info("Step {} ; Loss = {}".format(total_iter, train_loss))

        if total_iter > 0 and total_iter % params.epoch_size == (params.epoch_size - 1):
            # run eval step (calculate validation loss)
            model.eval()
            n_chars = 0
            xe_loss = 0
            n_valid = 0
            logger.info("============ Evaluating ... ============")
            val_loader = val_data.get_iterator(shuffle=True)
            for val_iter, val_batch in enumerate(val_loader):
                with torch.no_grad():
                    val_scores, val_loss, val_y = calculate_loss(model, val_batch, params, get_scores=True)
                # update stats
                n_chars += val_y.size(0)
                xe_loss += val_loss.item() * len(val_y)
                n_valid += (val_scores.max(1)[1] == val_y).sum().item()

            ppl = np.exp(xe_loss / n_chars)
            acc = 100. * n_valid / n_chars
            logger.info("Acc={}, PPL={}".format(acc, ppl))
            if acc > scores['acc']:
                scores['acc'] = acc
                scores['ppl'] = ppl
                save_model(params, data, model, opt, dico, logger, 'best_model', epoch, total_iter, scores)
                logger.info('Saving new best_model {}'.format(epoch))
                logger.info("Best Acc={}, PPL={}".format(scores['acc'], scores['ppl']))

            logger.info("============ Generating ... ============")
            number_samples = 100
            gen_smiles = generate_smiles(params, model, dico, number_samples)
            generator = ARMockGenerator(gen_smiles)

            try:
                benchmark = ValidityBenchmark(number_samples=number_samples)
                validity_score = benchmark.assess_model(generator).score
            except:
                validity_score = -1
            try:
                benchmark = UniquenessBenchmark(number_samples=number_samples)
                uniqueness_score = benchmark.assess_model(generator).score
            except:
                uniqueness_score = -1

            try:
                benchmark = KLDivBenchmark(number_samples=number_samples, training_set=all_smiles_mols)
                kldiv_score = benchmark.assess_model(generator).score
            except:
                kldiv_score = -1
            logger.info('Validity Score={}, Uniqueness Score={}, KlDiv Score={}'.format(validity_score, uniqueness_score, kldiv_score))
            save_model(params, data, model, opt, dico, logger, 'model', epoch, total_iter, {'ppl': ppl, 'acc': acc})
if __name__ == '__main__':

    # generate parser / parse parameters
    parser = get_parser()
    params = parser.parse_args()

    # run experiment
    main(params)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
qcorr simple

Based on Claude's suggestion, recalculate the
stochastic forcing amplitude based on a simpler approach using
T', Qnet, and Lambda'

For Qnet
- Removes mean
- Removes seasonal cycle

Created on Thu Feb 10 08:43:38 2022

@author: gliu
"""

import numpy as np
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import sys
import cmocean
from tqdm import tqdm
import xarray as xr

#%% Set Paths, Import Custom Modules
stormtrack = 0

if stormtrack == 0:
    projpath   = "/Users/gliu/Downloads/02_Research/01_Projects/01_AMV/02_stochmod/"
    datpath     = projpath + '01_Data/model_output/'
    rawpath     = projpath + '01_Data/model_input/'
    outpathdat  = datpath + '/proc/'
    figpath     = projpath + "02_Figures/20220519/"

    sys.path.append("/Users/gliu/Downloads/02_Research/01_Projects/01_AMV/02_stochmod/03_Scripts/stochmod/model/")
    sys.path.append("/Users/gliu/Downloads/02_Research/01_Projects/01_AMV/00_Commons/03_Scripts/")

elif stormtrack == 1:
    datpath     = "/stormtrack/data3/glliu/01_Data/02_AMV_Project/02_stochmod/Model_Data/model_output/"
    rawpath     = "/stormtrack/data3/glliu/01_Data/02_AMV_Project/02_stochmod/Model_Data/model_input/"
    outpathdat  = datpath + '/proc/'

    sys.path.append("/home/glliu/00_Scripts/01_Projects/00_Commons/")
    sys.path.append("/home/glliu/00_Scripts/01_Projects/01_AMV/02_stochmod/stochmod/model/")

from amv import proc,viz
import scm
import tbx

proc.makedir(figpath)
#%% Used Edits

lonf       = -30
latf       = 50

mconfig    = "FULL"
frcname    = "flxeof_090pct_FULL-PIC_eofcorr2"
input_path = rawpath

debug   = True
netcdf  = True # Load netCDFs saved from Investigate_Forcing.ipynb. False only supports FULL
"""
#%% Next Few Sections, Load in the Data...
"""

flip360=True # change longitude back to degrees east for final output

# Lag in T for damping term
# 0   = lbd*T(t)
# 1   = lbd*T(t-1)
# 0.5 = lbd*[T(t-1)+T(t)]/2
rolln    = 0
mconfigs = ("SLAB","FULL")

for mconfig in mconfigs:
    #%% Load in the Temperature Anomalies
    # [lon x lat x time]

    # Load in from dataset
    ds      = xr.open_dataset(datpath+"../CESM_proc/TS_anom_PIC_%s.nc" % (mconfig))
    T        = ds.TS.values
    lon360   = ds.lon.values
    ds.close()

    # Transpose dimensions
    T        = T.transpose(2,1,0) # [time x lat x lon] --> [lon x lat x time]
    lon180,T = proc.lon360to180(lon360,T)

    # Get dimension lengths
    nlon,nlat,ntime = T.shape
    nyrs            = int(ntime/12)

    #%% Load in Qnet

    # Load in from NumPY (Need to update this)
    if netcdf:
        ds = xr.open_dataset(datpath+"../CESM_proc/NHFLX_PIC_%s.nc" % mconfig)
        Q = ds.NHFLX.values
    else:
        Q   = np.load(datpath+"../NHFLX_PIC_Full.npy") # [year x month x lat x lon]
    Q   = Q.reshape(ntime,nlat,nlon) # [time x lat x lon]
    Q   = Q.transpose(2,1,0) # [lon x lat x time]

    # Flip to lon 180
    _,Q = proc.lon360to180(lon360,Q)

    # Remove Time Mean
    Q   = Q - Q.mean(2)[:,:,None]

    # Remove Scycle
    Qseas,Q = proc.calc_clim(Q,2,returnts=1)
    Q       = Q - Qseas[:,:,None,:]
    Q = Q.reshape(nlon,nlat,ntime)

    #%% Use the function used for sm_rewrite.py, load in lambda
    # [lon x lat x month]
    inputs = scm.load_inputs('SLAB_PIC',frcname,input_path,load_both=True)
    lon,lat,h,kprevall,dampingslab,dampingfull,alpha,alpha_full = inputs
    if mconfig == 'SLAB':
        lbd = dampingslab
    elif mconfig == 'FULL':
        lbd = dampingfull

    # Tile Lambda
    lbd = np.tile(lbd,nyrs)

    # ($$) Run up to here to visualize different lags evlow
    #%% Compute Stochastic Forcing
    """
    Qnet = -lambda*T + F'

    F' = Qnet + lambda*T

    """
    # Test the phase
    fig,ax =plt.subplots(1,1)
    test = np.arange(0,12,1)
    ax.plot(test,label='normal',color='k')
    ax.plot(np.roll(test,-1),label="-1",color='b')
    ax.plot(np.roll(test,1),label="1",color='r')
    ax.legend()
    ax.grid(True)
    ax.set_xlim([0,3])

    # Uh oh what lag of lambda to use? (Jump below to $$)

    if rolln == 0.5: # ([T(t) + T(t-1)]/2)
        dampterm = (np.roll(T,1,axis=2)+T)/2 * lbd
    else:
        dampterm = np.roll(T,rolln,axis=2) * lbd
    Fprime = Q + dampterm

    # Plot some test plots
    if debug:
        plt.pcolormesh(Fprime[...,0].T,vmin=-400,vmax=400),plt.colorbar()
        plt.show()
        plt.pcolormesh(Q[...,0].T,vmin=-400,vmax=400),plt.colorbar()
        plt.show()
        plt.pcolormesh(dampterm[...,0].T,vmin=-50,vmax=50),plt.colorbar()
        plt.show()

    #%% Do some Exploratory Analysis
    normspec = False
    labels    = ("$Q_{net}$","F'","$\lambda T$","-$\lambda T$ + F'")
    klon,klat = proc.find_latlon(lonf,latf,lon180,lat)
    locstring = "Lon %.f, Lat %.f" % (lon180[klon],lat[klat])
    ecolors   = ("mediumblue","firebrick","magenta","cyan")

    # 1) Compute the power spectra
    nsmooth = 100
    pct     = 0.00
    dtplot  = 3600*24*365
    xtks    = [1/100,1/50,1/20,1/10,1/2,1/1]
    xper    = [int(1/x) for x in xtks]
    xlm     = [xtks[0],xtks[-1]]

    inflx     = [Q[klon,klat,:],Fprime[klon,klat,:],dampterm[klon,klat,:],Fprime[klon,klat,:]-dampterm[klon,klat,:]]
    specs,freqs,CCs,dofs,r1s = scm.quick_spectrum(inflx,nsmooth,pct)
    if normspec:
        ylm = [0,3]
        specs = [specs[i]/np.var(inflx[i]) for i in range(len(inflx))]
    else:
        ylm = [0,1000]

    fig,ax = plt.subplots(1,1,figsize=(8,3))
    for i in range(len(inflx)-1):
        if i == (len(inflx)-1):
            ls = 'dashed'
        else:
            ls = 'solid'
        ax.plot(freqs[i]*dtplot,specs[i]/dtplot,label=labels[i],lw=3,ls=ls,color=ecolors[i])

    plotspec = specs[1] + specs[2]
    #ax.plot(freqs[i]*dtplot,plotspec/dtplot,label=labels[i] + "(Add Spectra)",lw=3,ls=ls)
    ax.legend()
    ax.set_xticks(xtks)
    ax.set_xticklabels(xper,rotation=45)
    ax.set_xlim(xlm)
    ax.set_ylim(ylm)
    ax.set_title("Power Spectra @ %s  \n CESM1-%s" % (locstring,mconfig) )
    ax.set_xlabel("Period (Years)")
    ax.set_ylabel("Power ($W/m^{2}/cpy$)")
    ax.grid(True,ls='dotted')
    plt.savefig("%sQnet_Power_Spectra_CESM1-%s.png"% (figpath,mconfig),dpi=150)

    #%% Save the updated forcing for the EOF Analysis

    """
    Fprime is [lon x lat x time]

    """
    # Flip back to lon 360
    if flip360:
        lon360,Fprime = proc.lon180to360(lon180,Fprime)
        lonsave = lon360
    else:
        lonsave = lon180

    #
    Fprime = proc.flipdims(Fprime) #  Flip to [time x lat x lon]
    times   = xr.cftime_range(start="0400-01-01",periods=Fprime.shape[0],freq="MS")

    # Save as a netCDF
    savename = "%s../Fprime_PIC_%s_rolln%s.nc" % (datpath,mconfig,str(rolln))
    proc.numpy_to_da(Fprime,times,lat,lonsave,'Fprime',savenetcdf=savename)

# ---------------------------------------------------------------------------
#%% Test different lags. Run up to the symbol ($$) above (loaded in all data)
# ---------------------------------------------------------------------------

rollns = (0,0.5,1) #
labels = ("T(t)","T(t-1/2)","T(t-1)")

dampterms = []
Fprimes   = []

for n in tqdm(range(len(rollns))):
    rolln = rollns[n]

    if rolln == 0.5: # ([T(t) + T(t-1)]/2)
        dampterm = (np.roll(T,1,axis=2)+T)/2 * lbd
    else:
        dampterm = np.roll(T,rolln,axis=2) * lbd
    Fprime = Q + dampterm

    Fprimes.append(Fprime)
    dampterms.append(dampterm)

#%% Make spectra for each one

klon,klat = proc.find_latlon(lonf,latf,lon180,lat)
locstring = "Lon %.f, Lat %.f" % (lon180[klon],lat[klat])
ecolors   = ("magenta","orange","cornflowerblue")
vnames    = ("F'","Damping_Term")
invars    = [Fprimes,dampterms]

# 1) Compute the power spectra
nsmooth = 100
pct     = 0.10
dtplot  = 3600*24*365
xtks    = [1/100,1/50,1/20,1/10,1/2,1/1]
xper    = [int(1/x) for x in xtks]
xlm     = [xtks[0],xtks[-1]]

for v in range(2):
    invar = invars[v]
    inflx     = [f[klon,klat,:] for f in invar]
    nsmooths  = nsmooth*np.ones(len(inflx))
    specs,freqs,CCs,dofs,r1s = scm.quick_spectrum(inflx,nsmooths,pct)

    if v ==0:
        ylm = [175,600]
    else:
        ylm = [50,775]

    fig,ax = plt.subplots(1,1,figsize=(8,3))
    for i in range(len(inflx)):
        if i == (len(inflx)):
            ls = 'dashed'
        else:
            ls = 'solid'
        ax.plot(freqs[i]*dtplot,specs[i]/dtplot,label=labels[i],lw=3,ls=ls,color=ecolors[i])

    plotspec = specs[1] + specs[2]
    #ax.plot(freqs[i]*dtplot,plotspec/dtplot,label=labels[i] + "(Add Spectra)",lw=3,ls=ls)
    ax.legend()
    ax.set_xticks(xtks)
    ax.set_xticklabels(xper,rotation=45)
    ax.set_xlim(xlm)
    ax.set_ylim(ylm)
    ax.set_title("%s Power Spectra @ %s  \n CESM1-%s" % (vnames[v],locstring,mconfig) )
    ax.set_xlabel("Period (Years)")
    ax.set_ylabel("Power ($W/m^{2}/cpy$)")
    ax.grid(True,ls='dotted')
    plt.savefig("%s%s_Power_Spectra_CESM1-%s.png"% (figpath,vnames[v],mconfig),dpi=150)


from collections import deque
n, l, r=map(int,input().split())
country=[]
for _ in range(n):
    country.append(list(map(int,input().split())))

dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]

def bfs(i, j):
    q=deque([(i,j)])
    visited[i][j]=True

    union=[(i, j)]
    total=country[i][j]
    while q:
        x, y=q.popleft()

        for m in range(4):
            nx=x+dx[m]
            ny=y+dy[m]

            if 0>nx or nx>=n or 0>ny or ny>=n:
                continue
            if visited[nx][ny]:
                continue
            if l <= abs(country[x][y]-country[nx][ny]) <= r:
                union.append((nx,ny))
                q.append((nx,ny))
                total+=country[nx][ny]
                visited[nx][ny]=True

    for x, y in union:
        country[x][y]=total//len(union)

    return len(union)

result=0
while True:
    visited=[[False]*n for i in range(n)]
    check=False
    for i in range(n):
        for j in range(n):
            if not visited[i][j]:
                if bfs(i,j) > 1:
                    check=True
    if not check:
        break
    result+=1

print(result)

# 2 20 50
# 50 30
# 20 40

# 2 40 50
# 50 30
# 20 40

# 2 20 50
# 50 30
# 30 40

# 3 5 10
# 10 15 20
# 20 30 25
# 40 22 10

# 4 10 50
# 10 100 20 90
# 80 100 60 70
# 70 20 30 40
# 50 20 100 10


from pathlib import Path
from setuptools import setup

with open('README.rst') as fd:
    DESCRIPTION = fd.read()

CLASSIFIERS = [
    'Intended Audience :: Developers',
    'License :: OSI Approved :: LGPL License',
    'Programming Language :: Python :: 3.6',
    'Topic :: Software Development :: Libraries :: Python Modules',
]

packages = [str(mod.parent) for mod in Path('unha2').rglob('__init__.py')]

setup(
    name='unha2',
    version='1.0a.dev1',
    description='A library for rocket chat',
    long_description=DESCRIPTION,
    author='Mathieu Pasquet',
    author_email='pypi@mathieui.net',
    license='LGPL',
    platforms=['any'],
    packages=packages,
    install_requires=['aiohttp'],
    classifiers=CLASSIFIERS
)


#!/usr/bin/env python2.7
import time
import cherrypy
from cherrypy.process.plugins import Monitor
import os.path
from timetable import Table

class WebInterface(object):
        @cherrypy.expose
        def index(self):
            return file("index.html")

        @cherrypy.expose
        def zones(self):
            return table.zone_states()

if __name__ == "__main__":
    table = Table()
    conf = {
         '/': {
             'tools.sessions.on': True,
             'tools.staticdir.root': './'
         },

         '/static': {
             'tools.staticdir.on': True,
             'tools.staticdir.dir': os.getcwd()+'/public'
         }
     }
    cherrypy.server.socket_host = '0.0.0.0'

    Monitor(cherrypy.engine, table.current, frequency=60).subscribe()
    cherrypy.quickstart(WebInterface(), '/', conf)