from datetime import datetime
from os import remove
import glob
import json
from pathlib import Path
from modules.constants import DATE_STR, DATETIME_TODAY

# Logs dir path
LOGS_PATH = Path().cwd() / "logs"

class LogsMixin:
    """Class responsible for manipulating usernames and session logs/errors locally."""
    expired_list = ""

    def export_username(self, username,
                        unfollow=False,
                        ignore=False,
                        scrape=False):
        """Saves followed user to unfollow list and to ignore list, to prevent future interaction with the account."""

        # Save to unfollow list
        if unfollow:
            path = LOGS_PATH / f"{DATE_STR}.txt"
            with path.open(mode="a") as f:
                f.write(f"{username}\n")

        # Save to ignore list
        if ignore:
            path = LOGS_PATH / "to_ignore.txt"
            with path.open(mode="a") as f:
                f.write(f"{username}\n")

        # Save scrape list
        if scrape:
            path = Path.cwd() / "to_scrape.txt"
            with path.open(mode="a") as f:
                f.write(f"{username}\n")

    def export_to_unfollow(self, usernames, filename):
        """Saves remaining usernames (list) waiting for unfollow to the original file."""
        path = LOGS_PATH / filename
        to_write = [str(line) for line in usernames]
        with path.open(mode="w") as f:
            f.write('\n'.join(to_write))
            f.write('\n')

    def expired_lists(self) -> bool:
        """Checks if there are lists atleast 4 days old to unfollow."""
        date_today = datetime.now()

        # Get all txt files in logs
        path = str(LOGS_PATH.absolute() / "*.txt")
        filenames = [Path(file).name[:-4] for file in glob.glob(path)]
        for date in filenames:

            try:
                fname_date = datetime.strptime(date, "%d-%m-%Y")
            except ValueError:
                pass
            else:
                # Check if the file older than 3 days
                if int((date_today - fname_date).days) >= 3:
                    self.expired_list = f'{fname_date.strftime("%d-%m-%Y")}.txt'
                    print("[IG] Expired list found")

                    return True

        return False

    def fetch_users_from_file(self, filename: str) -> list:
        """Grabs all usernames from a file and returns them as a list."""
        path = LOGS_PATH / filename
        output = []
        if path.exists():
            with open(path, "r") as f:
                output = [line.strip() for line in f.readlines()]

                return output
        else:
            print(f"The file '{filename}' doesn't exist.")

            return output

    def remove_finished_file(self, filename: str) -> None:
        """Remove empty unfollow list file."""
        path = LOGS_PATH / filename
        if path.exists():
            remove(path)
        else:
            print(f"The file '{filename}' doesn't exist.")

    def log_actions(self, method: str, actions: dict, **kwargs) -> None:
        """Logs the number of instagram actions made in a session.
            **kwargs:
            current_following: (int)
            target_account: (string)
            ...
        """
        dt = DATETIME_TODAY.replace(microsecond=0).isoformat()

        logs = {
            "date": dt,
            "method": method,
            "actions": {key: value for (key, value) in actions.items() if value != 0}
        }
        if kwargs:
            logs.update(kwargs)
        if len(logs["actions"]) != 0:
            logs = json.dumps(logs)

            path = LOGS_PATH / "actions_log.txt"
            with path.open(mode="a") as f:
                f.write(logs + "\n")

    def log_errors(self, errors: list) -> None:
        """Logs the errors encountered in a session."""
        path = LOGS_PATH / "errors_log.txt"
        dt = DATETIME_TODAY.replace(microsecond=0).isoformat()

        formatted = json.dumps({dt: errors})
        if len(errors) != 0:
            with path.open(mode="a") as f:
                f.write(formatted)
                f.write("\n")
                # f.write('\n'.join(errors))
                # f.write('\n')
            # TODO Make error logs file json
            # else:

    def logs_dir_create(self) -> None:
        if LOGS_PATH.exists():
            pass
        else:
            LOGS_PATH.mkdir()
            print("Logs directory created.")

if __name__ == "__main__":
    lm = LogsMixin()


from robomimic.config.base_config import BaseConfig

class BCConfig(BaseConfig):
    ALGO_NAME = "bc"

    def algo_config(self):
        """
        This function populates the `config.algo` attribute of the config, and is given to the
        `Algo` subclass (see `algo/algo.py`) for each algorithm through the `algo_config`
        argument to the constructor. Any parameter that an algorithm needs to determine its
        training and test-time behavior should be populated here.
        """

        # optimization parameters
        self.algo.optim_params.policy.learning_rate.initial = 1e-4  # policy learning rate
        self.algo.optim_params.policy.learning_rate.decay_factor = (
            0.1  # factor to decay LR by (if epoch schedule non-empty)
        )
        self.algo.optim_params.policy.learning_rate.epoch_schedule = (
            []
        )  # epochs where LR decay occurs
        self.algo.optim_params.policy.regularization.L2 = 0.00  # L2 regularization strength
        self.algo.optim_params.policy.learning_rate.betas = (0.9, 0.99)
        self.algo.optim_params.policy.learning_rate.lr_scheduler_interval = "epoch"

        # loss weights
        self.algo.loss.l2_weight = 1.0  # L2 loss weight
        self.algo.loss.l1_weight = 0.0  # L1 loss weight
        self.algo.loss.cos_weight = 0.0  # cosine loss weight

        # MLP network architecture (layers after observation encoder and RNN, if present)
        self.algo.actor_layer_dims = (1024, 1024)

        # stochastic Gaussian policy settings
        self.algo.gaussian.enabled = False  # whether to train a Gaussian policy
        self.algo.gaussian.fixed_std = False  # whether to train std output or keep it constant
        self.algo.gaussian.init_std = 0.1  # initial standard deviation (or constant)
        self.algo.gaussian.min_std = 0.01  # minimum std output from network
        self.algo.gaussian.std_activation = (
            "softplus"  # activation to use for std output from policy net
        )
        self.algo.gaussian.low_noise_eval = True  # low-std at test-time

        # stochastic GMM policy settings
        self.algo.gmm.enabled = False  # whether to train a GMM policy
        self.algo.gmm.num_modes = 5  # number of GMM modes
        self.algo.gmm.min_std = 0.0001  # minimum std output from network
        self.algo.gmm.std_activation = (
            "softplus"  # activation to use for std output from policy net
        )
        self.algo.gmm.low_noise_eval = True  # low-std at test-time

        # stochastic VAE policy settings
        self.algo.vae.enabled = False  # whether to train a VAE policy
        self.algo.vae.latent_dim = (
            14  # VAE latent dimnsion - set to twice the dimensionality of action space
        )
        self.algo.vae.latent_clip = None  # clip latent space when decoding (set to None to disable)
        self.algo.vae.kl_weight = (
            1.0  # beta-VAE weight to scale KL loss relative to reconstruction loss in ELBO
        )

        # VAE decoder settings
        self.algo.vae.decoder.is_conditioned = (
            True  # whether decoder should condition on observation
        )
        self.algo.vae.decoder.reconstruction_sum_across_elements = (
            False  # sum instead of mean for reconstruction loss
        )

        # VAE prior settings
        self.algo.vae.prior.learn = False  # learn Gaussian / GMM prior instead of N(0, 1)
        self.algo.vae.prior.is_conditioned = False  # whether to condition prior on observations
        self.algo.vae.prior.use_gmm = False  # whether to use GMM prior
        self.algo.vae.prior.gmm_num_modes = 10  # number of GMM modes
        self.algo.vae.prior.gmm_learn_weights = False  # whether to learn GMM weights
        self.algo.vae.prior.use_categorical = False  # whether to use categorical prior
        self.algo.vae.prior.categorical_dim = (
            10  # the number of categorical classes for each latent dimension
        )
        self.algo.vae.prior.categorical_gumbel_softmax_hard = (
            False  # use hard selection in forward pass
        )
        self.algo.vae.prior.categorical_init_temp = 1.0  # initial gumbel-softmax temp
        self.algo.vae.prior.categorical_temp_anneal_step = 0.001  # linear temp annealing rate
        self.algo.vae.prior.categorical_min_temp = 0.3  # lowest gumbel-softmax temp

        self.algo.vae.encoder_layer_dims = (300, 400)  # encoder MLP layer dimensions
        self.algo.vae.decoder_layer_dims = (300, 400)  # decoder MLP layer dimensions
        self.algo.vae.prior_layer_dims = (
            300,
            400,
        )  # prior MLP layer dimensions (if learning conditioned prior)

        # RNN policy settings
        self.algo.rnn.enabled = False  # whether to train RNN policy
        self.algo.rnn.horizon = 10  # unroll length for RNN - should usually match train.seq_length
        self.algo.rnn.hidden_dim = 400  # hidden dimension size
        self.algo.rnn.rnn_type = "LSTM"  # rnn type - one of "LSTM" or "GRU"
        self.algo.rnn.num_layers = 2  # number of RNN layers that are stacked
        self.algo.rnn.open_loop = False  # if True, action predictions are only based on a single observation (not sequence)
        self.algo.rnn.kwargs.bidirectional = False  # rnn kwargs
        self.algo.rnn.kwargs.do_not_lock_keys()

        # Transformer policy settings
        self.algo.transformer.enabled = False  # whether to train transformer policy
        self.algo.transformer.context_length = 64  # length of (s, a) seqeunces to feed to transformer - should usually match train.frame_stack
        self.algo.transformer.embed_dim = 256  # dimension for embeddings used by transformer
        self.algo.transformer.num_layers = 6  # number of transformer blocks to stack
        self.algo.transformer.num_heads = 8  # number of attention heads for each transformer block (should divide embed_dim evenly)
        self.algo.transformer.embedding_dropout = (
            0.1  # dropout probability for embedding inputs in transformer
        )
        self.algo.transformer.block_attention_dropout = (
            0.1  # dropout probability for attention outputs for each transformer block
        )
        self.algo.transformer.block_output_dropout = (
            0.1  # dropout probability for final outputs for each transformer block
        )
        self.algo.transformer.condition_on_actions = False  # whether to condition on the sequence of past actions in addition to the observation sequence
        self.algo.transformer.predict_obs = (
            False  # whether to predict observations in the output sequences as well
        )
        self.algo.transformer.mask_inputs = False  # whether to use bert style input masking
        self.algo.transformer.relative_timestep = True  # if true timesteps range from 0 to context length-1, if false use absolute position in trajectory
        self.algo.transformer.euclidean_distance_timestep = False  # if true timesteps are based the cumulative distance traveled by the end effector. otherwise integer timesteps
        self.algo.transformer.max_timestep = (
            1250  # for the nn.embedding layer, must know the maximal timestep value
        )
        self.algo.transformer.open_loop_predictions = (
            False  # if true don't run transformer at every step, execute a set of predicted actions
        )
        self.algo.transformer.sinusoidal_embedding = (
            False  # if True, use standard positional encodings (sin/cos)
        )
        self.algo.transformer.obs_noise_scale = (
            0.05  # amount of noise to add to the observations during training
        )
        self.algo.transformer.add_noise_to_train_obs = (
            False  # if true add noise to the observations during training
        )
        self.algo.transformer.use_custom_transformer_block = (
            True  # if True, use custom transformer block
        )
        self.algo.transformer.optimizer_type = "adamw"  # toggle the type of optimizer to use
        self.algo.transformer.lr_scheduler_type = "linear"  # toggle the type of lr_scheduler to use
        self.algo.transformer.lr_warmup = (
            False  # if True, warmup the learning rate from some small value
        )
        self.algo.transformer.activation = (
            "gelu"  # activation function for MLP in Transformer Block
        )
        self.algo.transformer.num_open_loop_actions_to_execute = (
            10  # number of actions to execute in open loop
        )
        self.algo.transformer.supervise_all_steps = (
            False  # if true, supervise all intermediate actions, otherwise only final one
        )
        self.algo.transformer.nn_parameter_for_timesteps = (
            True  # if true, use nn.Parameter otherwise use nn.Embedding
        )
        self.algo.transformer.num_task_ids = 1  # number of tasks we are training with
        self.algo.transformer.task_id_embed_dim = 0  # dimension of the task id embedding
        self.algo.transformer.language_enabled = False  # if true, condition on language embeddings
        self.algo.transformer.language_embedding = (
            "raw"  # string denoting the language embedding to use
        )
        self.algo.transformer.finetune_language_embedding = (
            False  # if true, finetune the language embedding
        )
        self.algo.transformer.kl_loss_weight = 0  # 5e-6  # weight of the KL loss
        self.algo.transformer.use_cvae = True
        self.algo.transformer.predict_signature = False
        self.algo.transformer.layer_dims = (1024, 1024)
        self.algo.transformer.latent_dim = 0
        self.algo.transformer.prior_use_gmm = True
        self.algo.transformer.prior_gmm_num_modes = 10
        self.algo.transformer.prior_gmm_learn_weights = True
        self.algo.transformer.replan_every_step = False
        self.algo.transformer.decoder = False
        self.algo.transformer.prior_use_categorical = False
        self.algo.transformer.prior_categorical_gumbel_softmax_hard = False
        self.algo.transformer.prior_categorical_dim = 10
        self.algo.transformer.primitive_type = "none"
        self.algo.transformer.reset_context_after_primitive_exec = True
        self.algo.transformer.block_drop_path = 0.0
        self.algo.transformer.use_cross_attention_conditioning = False
        self.algo.transformer.use_alternating_cross_attention_conditioning = False
        self.algo.transformer.key_value_from_condition = False
        self.algo.transformer.add_primitive_id = False
        self.algo.transformer.tokenize_primitive_id = False
        self.algo.transformer.channel_condition = False
        self.algo.transformer.tokenize_obs_components = False
        self.algo.transformer.num_patches_per_image_dim = 1
        self.algo.transformer.nets_to_freeze = ()
        self.algo.transformer.use_ndp_decoder = False
        self.algo.transformer.ndp_decoder_kwargs = None
        self.algo.transformer.transformer_type = "gpt"
        self.algo.transformer.mega_kwargs = {}

        self.algo.corner_loss.enabled = False

        self.algo.dml.enabled = (
            False  # if True, use Discretized Mixture of Logistics output distribution
        )
        self.algo.dml.num_modes = 2  # number of modes in the DML distribution
        self.algo.dml.num_classes = (
            256  # number of classes in each dimension of the discretized action space
        )
        self.algo.dml.log_scale_min = -7.0  # minimum value of the log scale
        self.algo.dml.constant_variance = True  # if True, use a constant variance

        self.algo.cat.enabled = False  # if True, use categorical output distribution
        self.algo.cat.num_classes = (
            256  # number of classes in each dimension of the categorical action space
        )

        self.env_seed = 0  # seed for environment
        self.wandb_project_name = "test"
        self.train.fast_dev_run = False  # whether to run training in debug mode
        self.train.max_grad_norm = None  # max gradient norm
        self.train.amp_enabled = False  # use automatic mixed precision
        self.train.num_gpus = 1  # number of gpus to use
        self.experiment.rollout.goal_conditioning_enabled = (
            False  # if True, use goal conditioning wrapper to sample goals for inference
        )
        self.train.load_next_obs = False  # whether or not to load s'
        self.experiment.rollout.goal_success_threshold = 0.01  # if the distance from the goal is less than goal_success_threshold, this counts as a success
        self.train.pad_frame_stack = True
        self.train.pad_seq_length = True
        self.train.frame_stack = 1
        self.experiment.rollout.is_mujoco = False
        self.experiment.rollout.valid_key = "valid"
        self.train.ckpt_path = None
        self.train.use_swa = False
        self.experiment.rollout.parallel_rollouts = True
        self.experiment.rollout.select_random_subset = False
        self.train.save_ckpt_on_epoch_end = True

        self.algo.dagger.enabled = False  # if true, enable dagger support
        self.algo.dagger.online_epoch_rate = 50  # how often to collect online data
        self.algo.dagger.num_rollouts = 1  # number of rollouts to collect per online epoch
        self.algo.dagger.rollout_type = (
            "state_error_mixed"  # toggle rollout type, can range from policy to closed loop tamp
        )
        self.algo.dagger.state_error_threshold = (
            0.001  # threshold for state error - triggers TAMP solver action
        )
        self.algo.dagger.action_error_threshold = (
            0.001  # threshold for action error - triggers TAMP solver action
        )
        self.algo.dagger.mpc_horizon = (
            100  # MPC horizon for closed loop tamp MPC - useful for running faster
        )


from tt import add

import pytest

@pytest.mark.parametrize(
    ('input_n', 'input_m', 'expected'),
    (
        (5, 10, 15),
        (10, 10, 20),
    )
)

def test_add(input_n, input_m, expected):
    assert add(input_n,input_m) == expected

from tt import ll

def test_ll():
    assert ll() == (2, 10, 12)

from tt import a

def test_a():
    assert a  == 444

from tt import lol

def test_lol(monkeypatch):
    monkeypatch.setattr()

    assert lol() == 2

# import random

# from tt import lol

# import pytest

# @pytest.mark.parametrize(
#     ('input_n1', 'input_nn', 'expected'),
#     (
#         (5, 5, 10),
#         (10, 4, 14),
#     )
# )

# def test_lol(input_n, input_m, expected):
#     assert lol() == expected


"""
                                            Binary Tree
Binary Tree are of three types full,complete and strict
example of application is huffman coding tree.

 -> inserting a node : if we want to insert a value 12 then we have check if current node has further right or left subtree if not then we will compare current node value with the value we want to insert

 - > finding minimum and maximum - Traverse only left part of subtrees to find minimum and traverse only right part for finding maximum

 ->  deleting a node from binary search tree.
        There are two ways to do that
            1) using left subtree and right subtree if we will traverse till we find the node to be deleted(self Node) Now using left subtree method we will look for maximum value in left subtree and will set self.data= maximum and then we will apply delete method again(i.e., recursion) till we reach the leaf node so that we can remove that peacfully

            same with right subtree method except the fact that we will look for minimum value from right subtree

*******Below is some bull shit theory!*******

-> Handshake theorem
        Basically it tells about properties of Binary tree  mentioned below
            -> Handshaking lemma is about an undirected graph. In every finite undirected graph, an even number of vertices will always have an odd degree.
            -> Sum of degree of all vertices is twice the number of edges i.e., Σdeg(V) = 2|E|
            Number of leaf nodes is always one more than number of internal nodes with two children

            -> N'th Catalan numbers

-> Insertion in a binary tree
        -> To insert in a binary tree we will traverse the tree by comparing each node with value to be inserted.
        whenever we will reach the leaf node we will set self.data = value.

-> BFS vs DFS
        BFS(or level order traversal) - visit row wise
        DFS : visit column wise column will come first.

AVL TREE
->  AVL tree is a self-balancing Binary Search Tree (BST) where the difference between heights of left and right subtrees cannot be more than one for all nodes.

        Why AVL Trees?
        Most of the BST operations (e.g., search, max, min, insert, delete.. etc) take O(h) time where h is the height of the BST. The cost of these operations may become O(n) for a skewed Binary tree. If we make sure that height of the tree remains O(Logn) after every insertion and deletion, then we can guarantee an upper bound of O(Logn) for all these operations. The height of an AVL tree is always O(Logn) where n is the number of nodes in the tree.

-> AVL tree insertion  have four cases which one to use will depend on where the new node has been inserted
    https://www.geeksforgeeks.org/avl-tree-set-1-insertion/
    Lets say the node inserted is w, now from w traverse to the unbalanced node, now there can be four cases of unbalancing  which can handled as follows

    lets take w be the inserted node, y be the node in between the unbalanced node and inserted node, and z be the unbalanced node.

    If the structure of unbalanced tree is left left position then rotating it to the right from z node will make the tree balanced.
    If the structure of unbalanced tree is right right position then rotating it to the left from z node will make the tree balanced.
    If the structure of unbalanced tree is left right position then rotating it to the left first from the y node and then rotating to the right from z node.
    If the structure of unbalanced tree is right left position then rotating it to the right first from the y node and then rotating to the left from z node.

--> Applications of Binary tree - https://www.geeksforgeeks.org/applications-of-minimum-spanning-tree/
    1. Minimum Spanning Tree problem can be solved using Binary tree
    2. Minimum Bottleneck Spanning Tree(MSBT) - The minimum bottleneck spanning tree in an undirected graph is a tree whose most expensive edge is as minimum as possible
            All minimum spanning trees are minimum bottleneck spanning tree but vice versa is not True
    3.LDPC (low density parity correction)  - It is used to transmit signals over noisy channels with noise threshold value as close as possible to theoritical threshold value also known as shannon threshold.

---> BFS and DFS
        . BFS and DFS(Inorder, Preorder and Postorder) all four traversals require O(n) time
        . Extra Space required for Level Order Traversal is O(w) where w is maximum width of Binary Tree. In level order traversal, queue one by one stores nodes of different level.
        . Extra Space required for Depth First Traversals is O(h) where h is maximum height of Binary Tree. In Depth First Traversals, stack (or function call stack) stores all ancestors of a node.

--> Binary Tree (Array implementation)
         . It is tree representing technique using array such that array indexes are values in tree nodes and   array values give the parent node of that particular index (or node).
         . The value of the root node index would always be -1 as there is no parent for root.
         for example construct binary tree using {1, 5, 5, 2, 2, -1, 3}
         . https://www.geeksforgeeks.org/construct-a-binary-tree-from-parent-array-representation/

--->  AVL tree(Balanced Binary Tree)
         . AVL tree is a self-balancing Binary Search Tree (BST) where the difference between heights of left and right subtrees cannot be more than one for all nodes.
         There can be 4 cases for unbalanced Binary Search Tree right after insertion.
                1. Left Left Case : Perform RR(Right Rotation)
                2. Left Right Case : LR then RR
                3. Right Right Case : LR
                4. Right Left Case : RR then LR

---> Continous Tree
         . A tree is a Continuous tree if in each root to leaf path, the absolute difference between keys of two adjacent is 1. We are given a binary tree, we need to check if the tree is continuous or not. For Example:

                Cont. Tree                      Not Cont. Tree
                     3                               7
                    / \                            /   \
                   2   4                          5     8
                  / \   \                        / \     \
                 1   3   5  8                    6  4     10

--> Applications of Tree : https://www.geeksforgeeks.org/applications-of-tree-data-structure/
"""

class BinarySearchTreeNode:
    def __init__(self,key) :
        self.left = None
        self.right  = None
        self.data = key

    def add_child(self, data):
        if data == self.data:
            return # node already exist

        if data < self.data:
            if self.left:
                self.left.add_child(data)

            else:
                self.left = BinarySearchTreeNode(data)
                # self.avl_balance(data)   uncomment these two lines if you want avl trees.
        else:
            if self.right:
                self.right.add_child(data)
            else:
                self.right = BinarySearchTreeNode(data)
                # self.avl_balance(data)

    def search(self,value):

        if self.data==value:
            return True

        if self.data>value:
            if self.left:
                return self.left.search(value)
            else:
                return False

        if self.data<value:
            if self.right:
                return self.right.search(value)
            else:
                return False

    def inorder_traversal(self):  #inorder == (left_node->root_node->right_node)
        elements = []
        if self.left :
            elements +=self.left.inorder_traversal()
        elements.append(self.data)
        if self.right:
            elements+=self.right.inorder_traversal()
        return elements

    def preorder_traversal(self):   #preorder == root_node-> left_node -> right_node
        elements = []
        elements.append(self.data)
        if self.left :
            elements +=self.left.inorder_traversal()
        if self.right:
            elements+=self.right.inorder_traversal()
        return elements

    def postorder_traversal(self):   #postorder ==  left_node -> right_node -> root_node
        elements = []
        if self.left :
            elements +=self.left.inorder_traversal()
        if self.right:
            elements+=self.right.inorder_traversal()
        elements.append(self.data)
        return elements

    def delete(self,value):

        if value<self.data:
            if self.left:
                self.left = self.left.delete(value)
            else:
                return None

        elif value>self.data:
            if self.right:
                self.right = self.right.delete(value)
            else:
                return None
        else:
            if self.right is None and self.left is None:
                return None
            if self.left is  None:
                return self.right
            if self.right is None:
                return self.left

            min_val = self.find_min()
            self.data = min_val
            self.right.delete(min_val)

    def find_min(self):
        if self.left is None:
            return self.data
        return self.left.find_min()

    def find_max(self):
        if self.right is None:
            return self.data
        return self.right.find_max()

    def insertion_list(self,value):
        if self.data:
            if self.data>value:
                if self.left:
                    self.left.insertion_list(value)
                else:
                    self.left = BinarySearchTreeNode(value)

            elif self.data<value:
                if self.right:
                    self.right.insertion_list(value)
                else:
                    self.right = BinarySearchTreeNode(value)

            else:
                print("already exists")
                return
        else:
            self.data = value

    def get_height(self,root):
        a,b=0,0

        if root is None:
            return 0
        while root.left or root.right:
            if root.right:
                a += 1
                root = root.right
            else:
                b += 1
                root = root.left
        return max(a,b)+1

    def print_current_level(self,root,level):
        if root is None:
            return None
        if level==1:
            print(root.data,end=" -> ")
        elif level>1:
            self.print_current_level(root.left,level-1)
            self.print_current_level(root.right,level-1)

    def bfs(self):
        h = self.get_height()
        print("bfs => ",end="")
        for i in range(1,h+1):
            self.print_current_level(self,i)
        print("None")

#its a fucked up func improve it.
    def avl_balance(self,value):
        print(value)
        print("right height",self.get_height(self.right),"left height - >",self.get_height(self.left))
        bal = self.get_height(self.left) - self.get_height(self.right)
        print("bal",bal)
        if bal>1 and value<self.left.data:
            self.right_rotate()

        if bal>1 and value>self.left.data:
            self.left = self.left_rotate()
            self.right_rotate()
        if bal<-1 and value>self.right.data:
            self.left_rotate()
        if bal<-1 and value<self.right.data:
            self.right  = self.right_rotate()
            self.left_rotate()

    def right_rotate(self):

        y= self.left
        t2 = y.right
        y.right = self
        self.left = t2
        self = y

    def left_rotate(self):

        y= self.right
        t2 = y.left
        y.left = self
        self.right = t2
        self = y

    def check_cont_tree(self,root):
        if not root:
            return True
        if root.left:
            if not abs(root.data-root.left.data)==1:
                return False
        if root.right:
            if not abs(root.data-root.right.data)==1:
                return False
        if self.check_cont_tree(root.left) and self.check_cont_tree(root.right):
            return True

def build_tree(element):
    BT = BinarySearchTreeNode(element[0])

    for i in range(1,len(element)):
        BT.add_child(element[i])
        # BT.avl_balance(element[i])

    return BT

# element = [17,4,9,20,18,345,22,11]
element = [7,5,8,6,4,10]
my_list = build_tree(element)
print(my_list.inorder_traversal()) #this will be sorted list.
print(my_list.check_cont_tree(my_list))

# my_list.bfs()
# print("Inorder =>",my_list.preorder_traversal())
# print("Postorder =>",my_list.postorder_traversal())
# print(my_list.dfs())
# print(my_list.get_height())
# print(my_list.search(34))

# print(my_list.find_min())
# print(my_list.find_max())

# my_list.insertion_list(14)
# print("After -> ", my_list.inorder_traversal())
# print(my_list.inorder_traversal())
# my_list.delete(4)


from math import pi
import torch
import torch.nn as nn

from pytorch_lightning.core.module import LightningModule
from loc_ndf.models import loss
from loc_ndf.utils import vis, utils
import open3d as o3d
from easydict import EasyDict
import tqdm
from loc_ndf.utils import pytimer

##################################################################
################ Lightning Module ################################
##################################################################
class LocNDF(LightningModule):
    def __init__(self, hparams: dict):
        super().__init__()
       # name you hyperparameter hparams, then it will be saved automagically.
        self.save_hyperparameters(hparams)
        self.update_map_params()  # self.T_local and self.occupancy_mask

        self.model = get_network(hparams['model'])
        self.loss = loss.ProjectedDistanceLoss(**hparams['loss']['params'])

    def update_map_params(self, points=None):
        T_local = utils.compute_T_from_bounding_box(
            self.hparams['bounding_box'])
        self.register_buffer('T_local', T_local)

        mask = utils.get_occ_mask(
            points=points, **self.hparams['occupancy_mask'])
        self.register_buffer('occupancy_mask', mask)

    def forward(self, x: torch.Tensor, in_global_frame=True):
        if in_global_frame:
            x = utils.transform(x, self.T_local)
        distance = self.model(x)
        return distance

    def training_step(self, batch: dict, batch_idx):
        points = self.forward(batch['points'])

        inter_grad, inter_val = self.compute_gradient_dists(batch['inter'])

        rand_grad, _ = self.compute_gradient_dists(batch['random'])

        loss, losses = self.loss(
            points_distance=points,
            points=batch['points'],
            inter_val=inter_val,
            inter_grad=inter_grad,
            inter_pos=batch['inter'],
            ray_dists=batch['dists'],
            rand_grad=rand_grad)

        for k, v in losses.items():
            self.log(f'train/{k}', v)
        return loss

    def compute_gradient_dists(self, position: torch.Tensor):
        position.requires_grad_(True)
        val = self.forward(position)
        grad = utils.compute_gradient(val, position)
        return grad, val

    def configure_optimizers(self):
        optimizer = torch.optim.AdamW(
            self.parameters(), lr=self.hparams['train']['lr'])
        scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
            optimizer, T_max=self.hparams['train']['max_epoch'], eta_min=self.hparams['train']['lr']/1e3)
        return [optimizer], [scheduler]

    def get_grid(self, nv=[500, 500, 50]):
        mins = self.hparams['bounding_box'][0]
        maxs = self.hparams['bounding_box'][1]
        x = torch.linspace(mins[0], maxs[0], nv[0],
                           device=self.device, dtype=self.dtype)
        y = torch.linspace(mins[1], maxs[1], nv[1],
                           device=self.device, dtype=self.dtype)
        z = torch.linspace(mins[2], maxs[2], nv[2],
                           device=self.device, dtype=self.dtype)
        xx, yy, zz = torch.meshgrid(x, y, z, indexing='ij')
        # make homogenous
        grid = torch.stack([xx, yy, zz, torch.ones_like(zz)], -1)
        return grid

    def get_occupancy_mask(self, nv=[500, 500, 50]):
        """ Returns the occupancy mask for evaluating the mesh for a given voxelsize.
        Be aware that the stored occupancy might be stored in a lower resolution thus the values are interpolated.
        """
        return torch.nn.functional.interpolate(self.occupancy_mask[None, None, ...].float(), size=nv).squeeze().bool()

    def get_mesh(self, nv=[500, 500, 50], tau=None, file=None, verbose=False, mask=None):
        tau = self.hparams['data']['isosurface'] if tau is None else tau
        pytimer.tic()
        if verbose:
            print('Start meshing')
        grid = self.get_grid(nv)
        pytimer.tocTic('Created grid', verbose=verbose)
        rows = []
        with torch.no_grad():
            for row in tqdm.tqdm(grid, leave=False, desc='Eval Grid'):
                rows.append(self.forward(row))
        pytimer.tocTic('Evaluated model', verbose=verbose)
        dist = torch.stack(rows).squeeze().cpu().numpy()
        mesh = vis.grid_to_mesh(
            dist, tau=tau,
            ascent=self.hparams['data']['gradient_ascent'],
            mins=self.hparams['bounding_box'][0],
            maxs=self.hparams['bounding_box'][1],
            mask=mask)
        pytimer.tocTic('finished meshing', verbose=verbose)

        if file is not None:
            o3d.io.write_triangle_mesh(file, mesh)
        pytimer.tocTic(f'stored to disk: {file}', verbose=verbose)
        return mesh

##################################################################
################ Network Architecture ############################
##################################################################

class LidarNerf(nn.Module):
    def __init__(self,
                 inter_fdim: int,
                 pos_encoding: dict,
                 sigmoid=True):
        super().__init__()
        self.pos_encoding = PositionalEncoder(**pos_encoding['params'])
        in_dim = self.pos_encoding.featureSize()
        self.net1 = nn.Sequential(
            MLP_Block(in_dim, inter_fdim),
            MLP_Block(inter_fdim,
                      inter_fdim),
            MLP_Block(inter_fdim,
                      inter_fdim),
            MLP_Block(inter_fdim,
                      inter_fdim),
            MLP_Block(inter_fdim,
                      inter_fdim))
        self.net2 = nn.Sequential(
            MLP_Block(inter_fdim+in_dim,
                      inter_fdim),
            MLP_Block(inter_fdim,
                      inter_fdim),
            MLP_Block(inter_fdim,
                      inter_fdim),
            nn.Linear(inter_fdim, 1),
            nn.Sigmoid() if sigmoid else nn.Identity()
        )

    def forward(self, x):
        pos = self.pos_encoding(x)

        x = self.net1(pos)
        x = torch.cat([x, pos], -1)
        x = self.net2(x)
        return x

class Siren(nn.Module):
    def __init__(self,
                 inter_fdim: int,
                 pos_encoding: dict,
                 sigmoid=True,
                 sin=True):
        super().__init__()
        self.pos_encoding = PositionalEncoder(**pos_encoding['params'])
        in_dim = self.pos_encoding.featureSize()
        self.net = nn.Sequential(
            MLP_Block(in_dim, inter_fdim, sin=sin),
            MLP_Block(inter_fdim,
                      inter_fdim, sin=sin),
            MLP_Block(inter_fdim,
                      inter_fdim, sin=sin),
            MLP_Block(inter_fdim,
                      inter_fdim, sin=sin),
            MLP_Block(inter_fdim,
                      inter_fdim, sin=sin),
            nn.Linear(inter_fdim, 1),
            nn.Sigmoid() if sigmoid else nn.Identity()
        )

    def forward(self, x):
        pos = self.pos_encoding(x)
        x = self.net(pos)
        return x

class Networks(EasyDict):
    LidarNerf = LidarNerf
    Siren = Siren

def get_network(type_params: dict) -> nn.Module:
    """ dict type_params {
        type: str, specifies which loss
        params: dict, kwargs of the loss
    }
    """
    return Networks()[type_params['type']](**type_params['params'])

################################################################
###################### Blocks ##################################
################################################################

class SinLayer(nn.Module):
    def forward(self, x):
        return torch.sin(x)

class MLP_Block(nn.Module):
    def __init__(self, in_dim: int, out_dim: int, sin=False):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(in_features=in_dim, out_features=out_dim),
            nn.LayerNorm(out_dim),
            SinLayer() if sin else nn.LeakyReLU())

    def forward(self, x):
        return self.net(x)

################################################################
################ Positional Encoding ###########################
################################################################

class PositionalEncoder(nn.Module):
    def __init__(self, freq, num_bands=5, dimensionality=3, base=2):
        super().__init__()
        self.freq, self.num_bands = torch.tensor(freq), num_bands
        self.dimensionality, self.base = dimensionality, torch.tensor(base)

    def forward(self, x):
        x = x[..., :self.dimensionality, None]
        device, dtype, orig_x = x.device, x.dtype, x

        scales = torch.logspace(0., torch.log(
            self.freq / 2) / torch.log(self.base), self.num_bands, base=self.base, device=device, dtype=dtype)
        # Fancy reshaping
        scales = scales[(*((None,) * (len(x.shape) - 1)), Ellipsis)]

        x = x * scales * pi
        x = torch.cat([x.sin(), x.cos()], dim=-1)
        x = torch.cat((x, orig_x), dim=-1)
        x = x.flatten(-2, -1)
        return x

    def featureSize(self):
        return self.dimensionality*(self.num_bands*2+1)
################################################################


import streamlit as st
import altair as alt
import inspect
from vega_datasets import data

@st.experimental_memo
def get_chart_37227(use_container_width: bool):
    import altair as alt
    from vega_datasets import data

    # Since these data are each more than 5,000 rows we'll import from the URLs
    airports = data.airports.url
    flights_airport = data.flights_airport.url

    states = alt.topo_feature(data.us_10m.url, feature="states")

    # Create mouseover selection
    select_city = alt.selection_single(
        on="mouseover", nearest=True, fields=["origin"], empty="none"
    )

    # Define which attributes to lookup from airports.csv
    lookup_data = alt.LookupData(
        airports, key="iata", fields=["state", "latitude", "longitude"]
    )

    background = alt.Chart(states).mark_geoshape(
        fill="lightgray",
        stroke="white"
    ).properties(
        width=750,
        height=500
    ).project("albersUsa")

    connections = alt.Chart(flights_airport).mark_rule(opacity=0.35).encode(
        latitude="latitude:Q",
        longitude="longitude:Q",
        latitude2="lat2:Q",
        longitude2="lon2:Q"
    ).transform_lookup(
        lookup="origin",
        from_=lookup_data
    ).transform_lookup(
        lookup="destination",
        from_=lookup_data,
        as_=["state", "lat2", "lon2"]
    ).transform_filter(
        select_city
    )

    points = alt.Chart(flights_airport).mark_circle().encode(
        latitude="latitude:Q",
        longitude="longitude:Q",
        size=alt.Size("routes:Q", scale=alt.Scale(range=[0, 1000]), legend=None),
        order=alt.Order("routes:Q", sort="descending"),
        tooltip=["origin:N", "routes:Q"]
    ).transform_aggregate(
        routes="count()",
        groupby=["origin"]
    ).transform_lookup(
        lookup="origin",
        from_=lookup_data
    ).transform_filter(
        (alt.datum.state != "PR") & (alt.datum.state != "VI")
    ).add_selection(
        select_city
    )

    chart = (background + connections + points).configure_view(stroke=None)

    tab1, tab2 = st.tabs(["Streamlit theme (default)", "Altair native theme"])

    with tab1:
        st.altair_chart(chart, theme="streamlit", use_container_width=True)
    with tab2:
        st.altair_chart(chart, theme=None, use_container_width=True)

try:
    st.expander("See code").code(inspect.getsource(get_chart_37227))
    get_chart_37227(use_container_width=True)
except Exception as e:
    st.exception(e)


from Tokenizer import *
from math import *
import re

class Document:
    tkn = Tokenizer()

    def __init__(self, id, text):
        #document ID
        self.id = id
        #document's raw text
        self.raw_text = text
        #raw_text with url and mentions removed
        self.url_removed = ' '.join(re.sub(r"(?:\@|http?\://|https?\://|www)\S+", "", text).split())
        #populate document's token list
        self.token_list = Document.tkn.get_tokens(text)
        #raw token list
        self.raw_token_list = Document.tkn.get_raw_tokens(text)
        #tf-idf vector
        self.tf_idf = []
        #norm of tf-idf vector
        self.norm = 0
        #token frequency map
        self.freq_map = dict()

        for token in self.token_list:
            self.freq_map[token] = self.freq_map.get(token, 0) + 1

    # def get_id(self):
    #     return self.id

    # def get_text(self):
    #     return self.raw_text

    # def get_token_list(self):
    #     return self.token_list

    # def get_freq_map(self):
    #     return self.freq_map

    # def size(self):
    #     return len(self.token_list)

    def calc_norm(self, doc_freq, N):
        for token in self.token_list:
            self.tf_idf.append(
                (1 + log10(0.0 + self.freq_map[token])) * log10((0.0 + N) / (0.0 + doc_freq[token]))
            )
        self.norm = sqrt(sum(i*i for i in self.tf_idf))

    # def get_norm(self):
    #     return self.norm

    def __str__(self):
        return "Doc# {}: {}".format(self.get_id(), str(self.token_list))

    def __lt__(self, other):
        return other.norm > self.norm

if __name__ == '__main__':
    d = Document(1, 'hello Hello , ,,,\n  \
                 \
                 \
                 \
                 world "I am ti http://bit.ly/a0vT5sred! I like fruit...and milk 大西瓜 \
                 world "I am ti @coollx @jiaxungao I like fruit...and milk 大西瓜')
    print(d.freq_map)
    print(d.tf_idf)
    print(d.url_removed)


import requests

class DataFormZephyrScale:
    def __init__(self, token):
        """
               初始化 DateFormZephyrScale 对象。

               参数：
               token -- Zephyr Scale API 的认证 token
               """
        self.bearer_token = token  # 初始化时传入实际的 bearer_token
        self.base_url = "https://api.zephyrscale.smartbear.com/v2"
        self.headers = {
            'Authorization': f'Bearer {self.bearer_token}',
            'Content-Type': 'application/json'
        }

    def data_form_zephyr_scale(self, case_key):
        """
               获取指定的测试案例 key 对应的测试步骤数据。

               参数：
               case_key -- 测试案例的 key

               返回值：
               测试步骤数据的 JSON 对象
        """
        url = f"{self.base_url}/testcases/{case_key}/teststeps"
        response1 = requests.get(url, headers=self.headers)
        return response1.json()['values'][0]['inline']['testData']

    def data_handling(self,lines):
        lines = lines.split("<br />")
        request_dict = {}

        # 逐行提取信息
        for line in lines:
            print(line)
            if "POST" in line:
                request_dict["method"] = "POST"
                continue
            if "http://" in line:
                request_dict["endpoint"] = line.split("127.0.0.1:5000")[-1]
                continue
            if "content-type:" in line:
                request_dict["head"] = line
                continue
            if "加密令牌" in line:
                request_dict["token"] = line
                continue
            if "状态码：" in line:
                key, value = line.split("：")
                request_dict[key] = value
                continue
        return request_dict

# 实现案例
# token = "XXXXX" #your actual token
# date_form = DateFormZephyrScale(token)
# print(date_form.date_form_zephyr_scale("HOR-T86"))


# -*- coding:utf8 -*-
"""
在一个电脑中编写1个程序，有2个功能
1.获取键盘数据，并将其发送给对方
2.接收数据并显示
并且功能数据进行选择以上的2个功能调用
"""
import socket

def send_data(udp_socket):
    """获取键盘数据，并将其发送给对方"""
    addr_ip = input("\n请输入对方的ip地址:")
    addr_port = int(input("请输入对方的port:"))
    send_msg = input("请输入要发送的数据:")
    udp_socket.sendto(send_msg.encode("gbk"), (addr_ip, addr_port))
    # window gbk   linux utf-8

def recv_data(udp_socket):
    """接收数据并显示"""
    recv_tuple = udp_socket.recvfrom(1024)
    recv_msg = recv_tuple[0].decode("gbk")  # window gbk   linux utf-8
    recv_addr = recv_tuple[1]
    print("%s: %s" % (recv_addr, recv_msg))
    # print("%s: %s" % (str(recv_addr), recv_msg))  # str 可以不加吗

def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    local_addr = ("", 10456)
    udp_socket.bind(local_addr)

    while True:
        print("=" * 30)
        print("1:发送消息")
        print("2:接收消息")
        print("0:结束")
        print("="*30)
        op = input("请输入要操作的功能序号:")

        if op == "1":
            send_data(udp_socket)
        elif op == "2":
            recv_data(udp_socket)
        elif op == "0":
            break
        else:
            print("输入有误，请重新输入...")

if __name__ == "__main__":
    main()


import numpy as np

def segment_dataframe_per_column(df, column):
    array = df[column].values
    stops = np.where(array[1:] != array[:-1])[0] + 1
    starts = np.concatenate([[0], stops])
    stops = np.concatenate([stops, [len(array)]])

    for start, stop in zip(starts, stops):
        yield array[start], df.iloc[start:stop]


import unittest

class myObject:
    def __init__(self, city, height, size):
        self.city = city
        self.height = height
        self.size = size
        self.altitude = 1000 + height

    def addHeight(self, adding):
        self.altitude += adding

class TestOo1(unittest.TestCase):

    def test_myObject(self):
        test_obj = myObject('Calgary', 3.4, 5)
        self.assertEqual(1003.4, test_obj.altitude)

        test_obj.addHeight(10)
        self.assertEqual(1013.4, test_obj.altitude)


"""Models related to operations and operation types."""
from pydent.base import ModelBase
from pydent.exceptions import AquariumModelError
from pydent.marshaller import add_schema
from pydent.models.crud_mixin import SaveMixin
from pydent.models.data_associations import DataAssociatorMixin
from pydent.models.field_value_mixins import FieldTypeInterface
from pydent.models.field_value_mixins import FieldValueInterface
from pydent.relationships import Function
from pydent.relationships import HasMany
from pydent.relationships import HasManyGeneric
from pydent.relationships import HasManyThrough
from pydent.relationships import HasOne
from pydent.relationships import HasOneFromMany
from pydent.relationships import Raw
from pydent.utils import filter_list

@add_schema
class Operation(FieldValueInterface, DataAssociatorMixin, ModelBase):
    """A Operation model."""

    fields = dict(
        field_values=HasMany(
            "FieldValue", ref="parent_id", additional_args={"parent_class": "Operation"}
        ),
        data_associations=HasManyGeneric(
            "DataAssociation", additional_args={"parent_class": "Operation"}
        ),
        operation_type=HasOne("OperationType"),
        job_associations=HasMany("JobAssociation", "Operation"),
        jobs=HasManyThrough("Job", "JobAssociation"),
        plan_associations=HasMany("PlanAssociation", "Operation"),
        plans=HasManyThrough("Plan", "PlanAssociation"),
        status=Raw(default="planning"),
        routing=Function("get_routing"),
        user=HasOne("User"),
    )

    METATYPE = "operation_type"

    def __init__(
        self, operation_type_id=None, operation_type=None, status=None, x=0, y=0
    ):
        super().__init__(
            operation_type_id=operation_type_id,
            operation_type=operation_type,
            status=status,
            field_values=None,
            x=x,
            y=y,
        )

    def get_routing(self):
        routing_dict = {}
        fvs = self.field_values
        ot = self.operation_type
        if ot is None:
            return routing_dict
        for ft in ot.field_types:
            if ft.routing is not None:
                routing_dict[ft.routing] = None
        if fvs is not None:
            for fv in self.field_values:
                ft = self.safe_get_field_type(fv)
                if ft.routing is not None:
                    routing_dict[ft.routing] = fv.sid
        return routing_dict

    @property
    def successors(self):
        successors = []
        if self.outputs:
            for output in self.outputs:
                for s in output.successors:
                    successors.append(s.operation)
        return successors

    @property
    def predecessors(self):
        predecessors = []
        if self.inputs:
            for inputs in self.inputs:
                for s in inputs.predecessors:
                    predecessors.append(s.operation)
        return predecessors

    def init_field_values(self):
        """Initialize the :class:`FieldValue` from the :class:`FieldType` of
        the parent :class:`Operation` type."""
        self.field_values = []
        for field_type in self.get_metatype().field_types:
            if not field_type.array:
                self.new_field_value_from_field_type(field_type)
        return self

    def field_value_array(self, name, role):
        """Returns :class:`FieldValue` array with name and role."""
        return filter_list(self.get_field_value_array(name, role))

    def field_value(self, name, role):
        """Returns :class:`FieldValue` with name and role.

        Return None if not found.
        """
        if self.field_values:
            fvs = self.field_value_array(name, role)

            if len(fvs) == 0:
                return None

            if len(fvs) == 1:
                return fvs[0]

            msg = "More than one FieldValue found for the field value"
            msg += (
                " of operation {}.(id={}).{}.{}. Are you sure you didn't mean to "
                "call 'field_value_array'?"
            )
            raise AquariumModelError(
                msg.format(self.operation_type, self.id, role, name)
            )

    @property
    def plan(self):
        return self.plans[0]

    def input_array(self, name):
        return self.get_field_value_array(name, "input")

    def output_array(self, name):
        return self.get_field_value_array(name, "output")

    def input(self, name):
        """Returns the input :class:`FieldValue` by name."""
        return self.field_value(name, "input")

    def output(self, name):
        """Returns the output :class:`FieldValue` by name."""
        return self.field_value(name, "output")

    def add_to_input_array(
        self, name, sample=None, item=None, value=None, container=None
    ):
        """Creates and adds a new input :class:`FieldValue`. When setting
        values to items/samples/containers, the item/sample/container must be
        saved.

        :param name: name of the FieldType/FieldValue
        :type name: string
        :param sample: an existing Sample
        :type sample: Sample
        :param item: an existing Item
        :type item: Item
        :param value: a string or number value
        :type value: string|integer
        :param container: an existing ObjectType
        :type container: ObjectType
        :return: the newly created FieldValue
        :rtype: FieldValue
        """
        return self.new_field_value(
            name,
            "input",
            dict(sample=sample, item=item, value=value, container=container),
        )

    def add_to_output_array(
        self, name, sample=None, item=None, value=None, container=None
    ):
        """Creates and adds a new output :class:`FieldValue`. When setting
        values to items/samples/containers, the item/sample/container must be
        saved.

        :param name: name of the FieldType/FieldValue
        :type name: string
        :param sample: an existing Sample
        :type sample: Sample
        :param item: an existing Item
        :type item: Item
        :param value: a string or number value
        :type value: string|integer
        :param container: an existing ObjectType
        :type container: ObjectType
        :return: the newly created FieldValue
        :rtype: FieldValue
        """
        return self.new_field_value(
            name,
            "output",
            dict(sample=sample, item=item, value=value, container=container),
        )

    @property
    def inputs(self):
        """Return a list of all input :class:`FieldValues`"""
        return [fv for fv in self.field_values if fv.role == "input"]

    @property
    def outputs(self):
        """Return a list of all output :class:`FieldValues`"""
        return [fv for fv in self.field_values if fv.role == "output"]

    def set_input(
        self, name, sample=None, item=None, value=None, container=None, object_type=None
    ):
        """Sets a input :class:`FieldValue` to a value. When setting values to
        items/samples/containers, the item/sample/container must be saved.

        :param name: name of the FieldValue/FieldType
        :type name: string
        :param sample: an existing Sample
        :type sample: Sample
        :param item: an existing Item
        :type item: Item
        :param value: a string or number value
        :type value: string|integer
        :param container: an existing ObjectType
        :type container: ObjectType
        :return: the existing FieldValue modified
        :rtype: FieldValue
        """
        if object_type is None and container:
            object_type = container
        return self.set_field_value(
            name,
            "input",
            dict(sample=sample, item=item, value=value, object_type=container),
        )

    def set_output(
        self, name, sample=None, item=None, value=None, container=None, object_type=None
    ):
        """Sets a output :class:`FieldValue` to a value. When setting values to
        items/samples/containers, the item/sample/container must be saved.

        :param name: name of the FieldValue/FieldType
        :type name: string
        :param sample: an existing Sample
        :type sample: Sample
        :param item: an existing Item
        :type item: Item
        :param value: a string or number value
        :type value: string|integer
        :param container: an existing ObjectType
        :type container: ObjectType
        :return: the existing FieldValue modified
        :rtype: FieldValue
        """
        if object_type is None and container:
            object_type = container
        return self.set_field_value(
            name,
            "output",
            dict(sample=sample, item=item, value=value, object_type=object_type),
        )

    def set_input_array(self, name, values):
        """Sets input :class:`FieldValue` array using values. Values should be
        a list of dictionaries containing sample, item, container, or values
        keys. When setting values to items/samples/containers, the
        item/sample/container must be saved.

        :param name: name of the FieldType/FieldValues being modified
        :type name: string
        :param values: list of dictionary of values to set
                (e.g. [{"sample": mysample}, {"item": myitem}])
        :type values: list
        :return: the list of modified FieldValues
        :rtype: list
        """
        return self.set_field_value_array(name, "input", values)

    def set_output_array(self, name, values):
        """Sets output :class:`FieldValue` array using values. Values should be
        a list of dictionaries containing sample, item, container, or values
        keys. When setting values to items/samples/containers, the
        item/sample/container must be saved.

        :param name: name of the FieldType/FieldValues being modified
        :type name: string
        :param values: list of dictionary of values to set
                (e.g. [{"sample": mysample}, {"item": myitem}])
        :type values: list
        :return: the list of modified FieldValues
        :rtype: list
        """
        return self.set_field_value_array(name, "output", values)

    def show(self, pre=""):
        """Print the operation nicely."""
        print(pre + self.operation_type.name + " " + str(self.cost))
        for field_value in self.field_values:
            field_value.show(pre=pre + "  ")

    def __str__(self):
        return self._to_str(operation_type_name=self.operation_type.name)

@add_schema
class OperationType(FieldTypeInterface, SaveMixin, ModelBase):
    """Represents an OperationType, which is the definition of a protocol in
    Aquarium."""

    fields = dict(
        operations=HasMany("Operation", "OperationType"),
        field_types=HasMany(
            "FieldType",
            ref="parent_id",
            additional_args={"parent_class": "OperationType"},
        ),
        codes=HasManyGeneric("Code"),
        cost_model=HasOneFromMany(
            "Code",
            ref="parent_id",
            additional_args={"parent_class": "OperationType", "name": "cost_model"},
        ),
        documentation=HasOneFromMany(
            "Code",
            ref="parent_id",
            additional_args={"parent_class": "OperationType", "name": "documentation"},
        ),
        precondition=HasOneFromMany(
            "Code",
            ref="parent_id",
            additional_args={"parent_class": "OperationType", "name": "precondition"},
        ),
        protocol=HasOneFromMany(
            "Code",
            ref="parent_id",
            additional_args={"parent_class": "OperationType", "name": "protocol"},
        ),
        test=HasOneFromMany(
            "Code",
            ref="parent_id",
            additional_args={"parent_class": "OperationType", "name": "test"},
        ),
    )

    def code(self, accessor):
        if accessor in [
            "protocol",
            "precondition",
            "documentation",
            "cost_model",
            "test",
        ]:
            return getattr(self, accessor)
        return None

    def instance(self, xpos=0, ypos=0):
        operation = self.session.Operation.new(
            operation_type_id=self.id, status="planning", x=xpos, y=ypos
        )
        operation.operation_type = self
        operation.init_field_values()
        return operation

    def field_type(self, name, role):
        if self.field_types:
            fts = filter_list(self.field_types, role=role, name=name)
            if len(fts) > 0:
                return fts[0]

    def sample_type(self):
        sample_types = []
        for field_type in self.field_types:
            for allowable_field_type in field_type.allowable_field_types:
                sample_types.append(allowable_field_type.sample_type)
        return sample_types

    def object_type(self):
        object_types = []
        for field_type in self.field_types:
            for allowable_field_type in field_type.allowable_field_types:
                object_types.append(allowable_field_type.object_type)
        return object_types

    def output(self, name):
        return self.field_type(name, "output")

    def input(self, name):
        return self.field_type(name, "input")

    def save(self):
        """Saves the Operation Type to the Aquarium server.

        Requires this Operation Type to be connected to a session.
        """
        return self.reload(self.session.utils.create_operation_type(self))

    def to_save_json(self):
        op_data = self.dump(
            include={
                "field_types": {"allowable_field_types": {}},
                "protocol": {},
                "cost_model": {},
                "documentation": {},
                "precondition": {},
                "test": {},
            }
        )

        # Format 'sample_type' and 'object_type' keys for afts
        for ft_d, ft in zip(op_data["field_types"], self.field_types):
            for aft_d, aft in zip(
                ft_d["allowable_field_types"], ft.allowable_field_types
            ):
                aft_d["sample_type"] = {"name": aft.sample_type.name}
                aft_d["object_type"] = {"name": aft.object_type.name}
        return op_data

    def _get_create_json(self):
        return self.to_save_json()

    def _get_update_json(self):
        return self.to_save_json()

    def __str__(self):
        return self._to_str("id", "name", "category")


import pandas as pd
from fuzzywuzzy import process
from gensim.models import Word2Vec
model = Word2Vec.load("models/word2vec.model")

def res_imp(restaurant, search_term = ''):
    # read absa results
    result = pd.read_json('data/result.json')

    # confirm restaurant name if restaurant name doesn't match
    name = process.extractOne(restaurant, set(result['name']))
    if name[1] < 95:
        ratios = process.extract(name[0], set(result['name']))
        print('We found the following restaurants: \n')
        print([x[0] for x in ratios])
        restaurant = input("Sense-R: Which restaurant are you referring to?\nUser: ")
        name = process.extractOne(restaurant, set(result['name']))

    print("For " + str(name[0]) + ":")

    # get on results for restaurant
    restaurant_result = result.loc[result['name'] == restaurant]
    # unpack lists in dataframe
    output = restaurant_result.explode(['aspect', 'sentiment', 'confidence'])

    # aggregate sentiments by restaurant
    pos = (output['sentiment']=='Positive').sum()
    neu = (output['sentiment']=='Neutral').sum()
    neg = (output['sentiment']=='Negative').sum()

    if search_term in ['', 'no', 'none']:
        # print opinions counts for restaurant
        pos = (output['sentiment']=='Positive').sum()
        neu = (output['sentiment']=='Neutral').sum()
        neg = (output['sentiment']=='Negative').sum()
        print('There were ' + str(pos) + ' positive opinions, ' + str(neu) + ' neutral opinions, and ' + str(neg) + ' negative opinions about ' + restaurant)
    else:
        # one-hot encode sentiment column
        output = pd.concat([output, pd.get_dummies(output.sentiment)], axis=1).drop('sentiment', axis=1)
        # aggregate sentiments by aspect
        if 'Neutral' in output.columns:
            aggregate = output.groupby("aspect").agg(
                positive = ('Positive', sum),
                neutral = ('Neutral', sum),
                negative = ('Negative', sum)
            )
        else:
            aggregate = output.groupby("aspect").agg(
                positive = ('Positive', sum),
                negative = ('Negative', sum)
            )
        # find top 3 closest aspect
        cos_sim = {}
        for index in aggregate.index:
            score = []
            for s_word in search_term.split():
                s_word = process.extractOne(s_word, model.wv.index_to_key)
                for word in index.split():
                    word = process.extractOne(word, model.wv.index_to_key)
                    score.append(model.wv.similarity(s_word[0], word[0]))
            cos_sim[index] = sum(score) / len(score)
        closest_match = sorted(cos_sim, key=cos_sim.get, reverse=True)[:3]

        for search_term in closest_match:
            # give summary of opinions
            search_result = aggregate.loc[aggregate.index == search_term]
            pos = str(search_result['positive'][0])
            neu = str(0)
            if 'neutral' in search_result.columns:
                neu = str(search_result['neutral'][0])
            neg = str(search_result['negative'][0])
            print('There were ' + pos + ' positive opinions, ' + neu + ' neutral opinions, and ' + neg + ' negative opinions about ' + search_term)


#Question 8

def main():
    classA = int(input("How many Class A seats were sold? "))
    classB = int(input("How many Class B seats were sold? "))
    classC = int(input("How many Class C seats were sold? "))

    print() #clear a line
    calcIncome(classA, classB, classC)

def calcIncome(classA, classB, classC):
    income = (15 * classA) + (12 * classB) + (9 * classC)

    print("Total ticket income: $", format(income, '.2f'), sep = "")

main()


import configparser
import textwrap

CONFIG_LOC = r"%LOCALAPPDATA%\GOG.com\Galaxy\Configuration\plugins\ps2\config.ini"

class Config:
    def __init__(self):
        self.cfg = configparser.ConfigParser(allow_no_value=True)
        self.cfg.set("DEFAULT", "; Make sure to use / instead of \ in file paths.")
        self.cfg["DEFAULT"]["roms_path"] = "C:/Games/PS2"
        self.cfg["DEFAULT"]["emu_path"] = "C:/Program Files (x86)/PCSX2 1.4.0/pcsx2.exe"
        self.cfg["DEFAULT"]["config_path"] = "C:/Documents/PCSX2/configs"
        self.cfg["DEFAULT"]["method"] = "default"
        self.cfg["DEFAULT"]["api_key"] = None
        self.cfg["DEFAULT"]["emu_fullscreen"] = False
        self.cfg["DEFAULT"]["emu_no_gui"] = False
        self.cfg["DEFAULT"]["emu_config"] = False

        self.cfg.add_section("Paths")
        self.cfg.set("Paths", textwrap.dedent(
                """\
                ; Set your roms folder, path to your pcsx2.exe and optional config path here
                ; To use the config feature, create a folder named "configs" inside "Documents/PCSX2" (the folder containing your bios, savestates etc.)
                ; Put the path to that folder down below
                ; To create settings for a game, copy the "inis" or "inis_1.4.0" folder into the "configs" folder and rename it to match the rom.
                ; Make sure that the renamed folders have the same name as the corresponding rom without the extension.
                ; eg. ROM: "Shadow of the Colossus.iso" | FOLDER: "Shadow of the Colossus"
                ; Without a specific config folder for a game, the default settings will be used.
                ; If you want to specify that PCSX2 does a full boot for a game follow the above instructions
                ; and simply add an empty file "fullboot.ini" to the rom folder in "configs"\
                """
            )
        )

        self.cfg.add_section("Method")
        self.cfg.set("Method", textwrap.dedent(
                """\
                ; "default": your files have to be named exactly as they are in the PCSX2 database (if the name contains a ":", delete it)
                ; "giant": use the Giant Bomb API to search for the name of your files in their database (requires a Giant Bomb account for an API key)
                ; "iso": reads your iso files directly for the serial of the game and then matches the name to it (only adds all your games if they are all iso files)
                ; Also set your API key here if you are using the Giant Bomb method\
                """
            )
        )

        self.cfg.add_section("EmuSettings")
        self.cfg.set("EmuSettings", textwrap.dedent(
                """\
                ; emu_fullscreen: Set to True if you want to launch in fullscreen by default
                ; emu_no_gui: Set to True if you want to suppress the gui when launching a game
                ; emu_config: Set to True if you want to use game specific configurations\
                """
            )
        )


import cv2
import numpy as np
import scipy
from scipy import ndimage, spatial
gauss = cv2.getGaussianKernel(5, 0.5)
mask = np.zeros((5,5))
mask[2][2] = 1

mask = ndimage.gaussian_filter(mask, 0.5)
# print(mask)
mask = np.zeros((3,3))
mask[1][1] = 1
# print(ndimage.sobel(mask, axis = 1, mode = 'nearest'))

image = np.random.rand(5,5)

empty = np.zeros((3,3))
empty[1][1] = 1
xSobel = ndimage.sobel(empty, axis = 1)
ySobel = ndimage.sobel(empty, axis = 0)
#and for 2nd order derivatives

xxSobel = ndimage.sobel(xSobel, axis = 1)
# print(xxSobel)
Gradxx = ndimage.convolve(image, xxSobel, mode = 'nearest')
# print(Gradxx)

# print(image)
gradx = ndimage.convolve(image, xSobel, mode = 'nearest')
# print(gradx)
gradxx = ndimage.convolve(gradx, xSobel, mode = 'nearest')

hello = np.asarray([[1,2,3],[4,5,6],[7,8,9]])
# print(hello)
mask = np.asarray([[1,2,1]])
# mask[1][1] = 1
# mask[1][0] = 1
# mask[1][2] = 1
# mask[0][1] = 1
# mask[2][1] = 1

# print(mask)

convolve = ndimage.convolve(image, mask)
correlate = ndimage.correlate(image, mask)
# print(convolve)
# print(correlate)

K = np.array([1/16, 4/16, 6/16, 4/16, 1/16], dtype=np.float32)
print(K)


from datetime import datetime
from pprint import pprint as pp

from paprika.data.data_type import DataType
from paprika.data.data_channel import DataChannel
from paprika.data.feed import Feed
from paprika.data.feed_filter import TimeFreqFilter, Filtration
from paprika.data.constants import TimePeriod
from paprika.signals.pair_spread_ols_signal import PairSpread

def test_pair_spread_signal():
    # to check what is available:
    # print(DataChannel.table_names(arctic_source_name='mdb'))

    # set up the pairs data you will be looking at
    pairs_feed = Feed('PAIRS_FEED', datetime(2017, 7, 1), datetime(2017, 7, 28))
    pairs_feed.set_feed(["EUX.FBTP201709", "EUX.FBTS201709"], DataType.TRADES)

    # how much data did we actually get?
    pp(pairs_feed.shape)

    pair_signal = PairSpread(Y="FBTP201709", X="FBTS201709", BETA=1.2, SD_SUPPLIED=1.2, SD_FACTOR=0.5)
    pair_signal.add_filtration(Filtration(TimeFreqFilter(TimePeriod.SECOND, 600)))
    pairs_feed.add_subscriber(pair_signal)

    # execute the signal
    pair_signal.run()

    # show some of your results
    print(pair_signal.get_parameter("WEIGHT_ALLOCATION"))
    print(pair_signal.get_parameter("BETA_HISTORY"))
    print(pair_signal.parameters)

    # let's adapt the beta with time
    pair_signal_2 = PairSpread(Y="FBTP201709", X="FBTS201709",
                               BETA=1.2, BETA_UPDATE_FACTOR=1.01,
                               SD_SUPPLIED=1.2, SD_FACTOR=0.5)
    pair_signal_2.add_filtration(Filtration(TimeFreqFilter(TimePeriod.SECOND, 600)))
    pairs_feed.add_subscriber(pair_signal_2)
    pair_signal_2.run()
    print(pair_signal_2.get_parameter("WEIGHT_ALLOCATION"))
    print(pair_signal_2.get_parameter("BETA_HISTORY"))
    print(pair_signal_2.parameters)

    # let's use the rolling historical standard deviation
    pair_signal_3 = PairSpread(Y="FBTP201709", X="FBTS201709",
                               BETA=1.2, SD_FACTOR=2.0, NUM_OBS=20.0)
    pair_signal_3.add_filtration(Filtration(TimeFreqFilter(TimePeriod.SECOND, 600)))
    pairs_feed.add_subscriber(pair_signal_3)
    pair_signal_3.run()
    print(pair_signal_3.get_parameter("WEIGHT_ALLOCATION"))
    print(pair_signal_3.get_parameter("BETA_HISTORY"))
    print(pair_signal_3.parameters)

    # let's use the rolling historical standard deviation and some adaptive beta
    pair_signal_4 = PairSpread(Y="FBTP201709", X="FBTS201709",
                               BETA=1.2, SD_FACTOR=1.0, NUM_OBS=20.0, BETA_UPDATE_FACTOR=1.05)
    pair_signal_4.add_filtration(Filtration(TimeFreqFilter(TimePeriod.SECOND, 600)))
    pairs_feed.add_subscriber(pair_signal_4)
    pair_signal_4.run()
    print(pair_signal_4.get_parameter("WEIGHT_ALLOCATION"))
    print(pair_signal_4.get_parameter("BETA_HISTORY"))
    print(pair_signal_4.parameters)

    # check that we don't get a speed penalty for accidentally creating a duplicated feed
    # set up the pairs data you will be looking at
    pairs_feed_duplicate = Feed('PAIRS_FEED_2', datetime(2017, 7, 1), datetime(2017, 7, 28))
    pairs_feed_duplicate.set_feed(["EUX.FBTP201709", "EUX.FBTS201709"], DataType.TRADES)

    # how much data did we actually get?
    pp(pairs_feed_duplicate.shape)

    pair_signal_5 = PairSpread(Y="FBTP201709", X="FBTS201709",
                               BETA=1.2, SD_FACTOR=1.0, NUM_OBS=40.0)
    pair_signal_5.add_filtration(Filtration(TimeFreqFilter(TimePeriod.SECOND, 600)))
    pairs_feed_duplicate.add_subscriber(pair_signal_5)

    # execute the signal
    pair_signal_5.run()

    # clear out your used feeds
    DataChannel.clear_all_feeds()


from django.urls import path
from . import views
from .views import BlogDestroyApi, BlogDetailApi, BlogListApi, BlogUpdateApi, BlogCreateApi

urlpatterns = [
    path('add/', BlogCreateApi.as_view(), name = "uploadBlog"),
    path('bloglist/', BlogListApi.as_view(), name = "blog_list"),
    path('blogUpdate/<int:pk>/', BlogUpdateApi.as_view(), name = "blog_update"),
    path('blogdetail/<int:pk>/',BlogDetailApi.as_view(), name = "blog_detail" ),
    path('blogdelete/<int:pk>/', BlogDestroyApi.as_view(), name = "blog_delete"),
]


import pyposeidon.meteo as pmeteo
import pyposeidon.model as pmodel
import pytest
import xarray as xr
import os
import shutil
import numpy as np

from . import DATA_DIR

@pytest.mark.parametrize("input_name", ["erai.grib", "era5.grib", "uvp_2018100112.grib"])
def test_schism(tmpdir, input_name):
    filename = (DATA_DIR / input_name).as_posix()
    # read meteo file
    df = pmeteo.Meteo(meteo_source=filename)
    df.Dataset = df.Dataset.sortby("latitude", ascending=True)

    rpath = str(tmpdir) + "/"
    # output to uvp files
    df.to_output(solver_name="schism", rpath=rpath)

    # read again meteo
    path = rpath + "/sflux/"
    dr = xr.open_dataset(path + "/sflux_air_1.0001.nc")

    # cleanup
    #    try:
    #        shutil.rmtree(path)
    #    except OSError as e:
    #        print ("Error: %s - %s." % (e.filename, e.strerror))

    # compare
    assert np.array_equal(df.Dataset.msl.values, dr.prmsl.values)
    assert np.array_equal(df.Dataset.u10.values, dr.uwind.values)
    assert np.array_equal(df.Dataset.v10.values, dr.vwind.values)

@pytest.mark.parametrize("input_name", ["erai.grib", "era5.grib", "uvp_2018100112.grib"])
def test_d3d(tmpdir, input_name):
    filename = (DATA_DIR / input_name).as_posix()
    # read meteo file
    df = pmeteo.Meteo(meteo_source=filename)

    rpath = str(tmpdir) + "/"
    # output to uvp files
    df.to_output(solver_name="d3d", rpath=rpath)

    # read again meteo
    m = pmodel.set(solver_name="d3d")

    p = m.from_force(rpath + "p.amp", "msl")
    u = m.from_force(rpath + "u.amu", "u10")
    v = m.from_force(rpath + "v.amv", "v10")

    dr = xr.merge([p, u, v])
    dr = dr.sortby("latitude", ascending=True)

    # compare
    df.Dataset = df.Dataset.sortby("latitude", ascending=True)

    assert np.abs(df.Dataset.msl.values - dr.msl.values).max() < 1e-3
    assert np.abs(df.Dataset.u10.values - dr.u10.values).max() < 1e-3
    assert np.abs(df.Dataset.v10.values - dr.v10.values).max() < 1e-3


import json

# Parses stored data and prints to screen
def jsonPrintEntry(entry):
    print(entry["title"])
    print(entry["company"])
    print(entry["location"])
    print(entry["time"])
    print(entry["link"])
    print(entry["source"])
    print()

def jsonPrintFile(file):
    for entry in file:
        jsonPrintEntry(entry)

def jsonReadFile(path):
    with open(path) as json_data:
        jobData = json.load(json_data)

    return jobData

path = "..\\data\\jobs.json"
jobData = jsonReadFile(path)
jsonPrintFile(jobData)


# Challenge: Make a spirograph each with a radius of 100 with different colors.

import turtle as t
import random

# get random colors
t.colormode(255)

def get_color():
    r = random.randint(0, 255)
    g = random.randint(0, 255)
    b = random.randint(0, 255)
    return (r, g, b)

tim = t.Turtle()
tim.speed("fastest")

def draw_spirograph(size_of_gap):
    for _ in range(int(360 / size_of_gap)):
        tim.color(get_color())
        tim.circle(100)
        tim.setheading(tim.heading() + size_of_gap)

draw_spirograph(5)

screen = t.Screen()
screen.exitonclick()


'''
https://leetcode.com/problems/set-matrix-zeroes/description/
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
Follow up: Did you use extra space?
A straight forward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best solution.
Could you devise a constant space solution?
'''

# O(n^2) time, O(m + n) space
def setzeroes(matrix):
    rows = len(matrix)
    cols = len(matrix[0])
    r = [False for _ in range(rows)]
    c = [False for _ in range(cols)]

    # keep track of where the 0s are
    for i in range(rows):
        for k in range(cols):
            if matrix[i][k] == 0:
                r[i] = True
                c[k] = True
    # set the zeroes
    for i in range(rows):
        for k in range(cols):
            if r[i] or c[k]:
                matrix[i][k] = 0
    print(matrix)

# using constant space, but still O(n^2) time
def followup(matrix):
    rows, cols = len(matrix), len(matrix[0])
    rowzero, colzero = False, False

    # first: mark if row 0 and col 0 have 0s in them
    for i in range(rows):
        if matrix[i][0] == 0:
            colzero = True
    for i in range(cols):
        if matrix[0][i] == 0:
            rowzero = True

    # second: loop through matrix. if position [i][k] == 0,
    # use the first row/col to mark. [i][0] = 0 and [0][k] = 0
    for i in range(1, rows):
        for k in range(1, cols):
            if matrix[i][k] == 0:
                matrix[i][0] = 0
                matrix[0][k] = 0

    # third: loop through matrix again. if row / col is marked ^, then set that entire row / col to 0
    for i in range(1, rows):
        if matrix[i][0] == 0:
            for k in range(1, cols):
                matrix[i][k] = 0
    for i in range(1, cols):
        if matrix[0][i] == 0:
            for k in range(1, rows):
                matrix[k][i] = 0

    # fourth: if row 0 or col 0 had a 0 initially, set entire row / col to 0
    if rowzero:
        matrix[0] = [0] * cols
    if colzero:
        for i in range(rows):
            matrix[i][0] = 0
    print(matrix)

matrix = [[1,1,1],[1,0,1],[1,1,1]]
setzeroes(matrix) # [[1, 0, 1], [0, 0, 0], [1, 0, 1]]
matrix = [[1,1,1],[0,1,1],[1,1,1]]
followup(matrix) # [[0, 1, 1], [0, 0, 0], [0, 1, 1]]
matrix = [[0,0,0,5],[4,3,1,4],[0,1,1,4],[1,2,1,3],[0,0,1,1]]
followup(matrix) # [[0, 0, 0, 0], [0, 0, 0, 4], [0, 0, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0]]


import json
try:
    # For Python 3.0 and later
    from urllib.error import HTTPError
    import urllib.request as urllib
except ImportError:
    # Fall back to Python 2's urllib2
    import urllib2 as urllib
    from urllib2 import HTTPError

url = 'https://review.opendev.org/projects/'

# This is what a project looks like
'''
  "openstack-attic/akanda": {
    "id": "openstack-attic%2Fakanda",
    "state": "READ_ONLY"
  },
'''

def is_in_openstack_namespace(proj):
    return proj.startswith('openstack/')

def has_grenade_plugin(proj):
    try:
        r = urllib.urlopen(
            "https://opendev.org/%s/src/branch/master/devstack/upgrade/upgrade.sh" % proj)
        return True
    except HTTPError as err:
        if err.code == 404:
            return False

r = urllib.urlopen(url)
projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:])))

found_plugins = filter(has_grenade_plugin, projects)

for project in found_plugins:
    print(project[10:])


import itertools
floors = (0, 1, 2, 3, 4)
for (H, K, L, P, R) in list(itertools.permutations(floors)):
    if K != 0 and \
            L != 0 and L != 4 and \
            P > K and \
            abs(R - L) > 1 and \
            abs(L - K) > 1 and \
            H != 4:
        print('H', 'K', 'L', 'P', 'R')
        print(H, K, L, P, R)
        break


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

from __future__ import print_function
import struct
import socket
import fcntl
import time
import sys
import os
from threading import RLock, Thread
from time import sleep
from contextlib import contextmanager
from collections import deque, defaultdict

import pcap
import dpkt

TYPE = 0x11
SMOOTH_INTERVAL = 1.5

def log(*args, **kwargs):
    """
        print the input args and kwargs
        :param args:
        :param kwargs:
        :return:
    """
    print(*args, **kwargs)

def get_mac(dev):
    """
        get the route's MAC address
        :param dev: the route
        :return: the MAC address of the route
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', dev[:15]))[18:24]

def mac_to_str(mac):
    """
        transform MAC address into string
        :param mac:
        :return: the string of MAC address
    """
    return ':'.join(['%02x' % ord(x) for x in mac])

def parse_packet(rtpacket):
    """
        parse the radiotap packet
        :param rtpacket: the radiotap packet
        :return: (signal, client_mac) or None : None will be returned when the packet is not a ethernet packet
    """
    radiotap = dpkt.radiotap.Radiotap(rtpacket)
    it_len = struct.unpack('<H', struct.pack('>H', radiotap.length))[0]
    if radiotap.version != 0 or it_len < 8 or it_len + 34 > len(rtpacket):
        return None
    client_mac = rtpacket[it_len + 10 : it_len + 16]
    #print (mac_to_str(client_mac))
    for field in radiotap.fields:
        # print (`field`)
        if isinstance(field, dpkt.radiotap.Radiotap.AntennaSignal):
            signal = field.db - 256
            if signal < 0 and signal > -128 and len(client_mac) == 6:
                return signal, client_mac
            else:
                # print ('error mac : ' + mac_to_str(client_mac))
                break
    return None

class Daemon:

    def __init__(self, wdev, out_ip, out_port, interval):
        """
            the daemon running on the OpenWrt device
            :param wdev: Wireless device
            :param out_ip: the ip address of sending data
            :param out_port: the port of out_ip
            :param interval: the time interval of sending data (ms)
            :return:
        """
        self.addr = (out_ip, out_port)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.ap_mac = get_mac('br-lan')
        log('AP Mac:', mac_to_str(self.ap_mac))
        self.interval = interval / 1000.
        self.wdev = wdev
        self.signals = defaultdict(deque)
        self.lock_signals = RLock()
        self.need_quit = False
        self.pcap = None

    def start(self):
        """
            start running the daemon
            :return:
        """
        wdev = self.wdev
        os.system('ifconfig {} down && ifconfig {} up'.format(wdev, wdev))
        log('Daemon started:\n  dev: {}\n  mac: {}\n  dest: {}\n  interval: {}\n'.format(
            wdev, mac_to_str(self.ap_mac), self.addr, self.interval))
        th_send = Thread(target=self.run_send)
        th_capture = Thread(target=self.run_capture)
        ths = [
            th_send,
            th_capture,
        ]

        self.need_quit = False
        for th in ths:
            th.daemon = True
            th.start()

        try:
            for th in ths:
                th.join()
        except KeyboardInterrupt:
            self.quit()

    def run_send(self):
        """
            sending captured data to the (out_ip, out_port) (running by a thread)
            :return:
        """
        with self.guard():
            while not self.need_quit:
                sleep(self.interval)
                with self.lock_signals:
                    timestamp = time.time()
                    to_del = []
                    for client_mac, que in self.signals.iteritems():
                        while que and que[0][0] + SMOOTH_INTERVAL < timestamp:
                            que.popleft()
                        if not que:
                            to_del.append(client_mac)
                    for client_mac in to_del:
                        del self.signals[client_mac]
                    signals = []
                    for client_mac, que in self.signals.iteritems():
                        # que: deque<(timestamp, signal)>
                        signal = sum([signal for _, signal in que]) / len(que)
                        print('\t', mac_to_str(client_mac), len(que), signal)
                        signals.append((client_mac, signal))
                    self.send_record(timestamp, signals)

    def run_capture(self):
        """
            capture the data and save it in a queue (running by a thread)
            :return:
        """
        with self.guard():
            while not self.need_quit:
                recv_count = 0
                cap = pcap.pcap(self.wdev)
                for packet in cap:
                    if self.need_quit:
                        break
                    # log('start capture loop')
                    if packet is None:
                        continue
                    timestamp, rtpacket = packet
                    result = parse_packet(rtpacket)
                    if result is None:
                        # log('failed to parse the packet')
                        continue
                    signal, client_mac = result
                    with self.lock_signals:
                        que = self.signals[client_mac]
                        que.append((timestamp, signal))
                    recv_count += 1

    def quit(self):
        """
            quit the deamon
            :return:
        """
        self.need_quit = True

    @contextmanager
    def guard(self):
        """
            insure two thread(th_send, th_capture) working well
            :return:
        """
        try:
            yield
        except:
            self.quit()
            raise

    def send_record(self, timestamp, signals):
        """
            packet the sending data and send it
            :param timestamp: the timestamp of sending time
            :param signals: (client_mac, rssi)'s list
            :return:
            A record contains a head and a body
            head:
            -------------------------------------------------
            | type(1) | ap_mac(6) | timestamp(8) | count(1) |
            -------------------------------------------------
            body:
            --------------------
            | mac(6) | rssi(1) |
            --------------------
        """
        try:
            head = struct.pack('>B6sIxxxxB',
                    TYPE, self.ap_mac, timestamp, len(signals))
            body = b''.join(
                struct.pack('>6sb', client_mac, signal) for client_mac, signal in signals
            )
            record = head + body
            self.sock.sendto(record, self.addr)
            log('time:', timestamp, 'sent', len(signals), 'signals')
            print ('-----------------------------------------------------------------')
        except socket.error as e:
            log('error:', e)
            return

if __name__ == '__main__':
    if len(sys.argv) < 5:
        exit('usage: python rssiCapture.py wdev out_ip out_port interval')
    else:
        wdev, out_ip, out_port, interval = sys.argv[1:]
        out_port = int(out_port)
        interval = int(interval)
        Daemon(wdev, out_ip, out_port, interval).start()