import os, glob, math
import numpy as np
import tensorflow as tf
from PIL import Image

from myutils_tf import bwutils

def save_4ch_to_3ch(path_pixel_shift):
    print(path_pixel_shift)

    files = glob.glob(os.path.join(path_pixel_shift, '*.npy'))
    # print(files)
    for idx, file in enumerate(files):
        if '3ch' not in file:
            arr = np.load(file)
            arr_3ch = arr[:,:,(0,1,3)]
            file_new = file[:-4] + '_3ch.npy'
            np.save(file_new, arr_3ch)

def get_model(model_name, model_sig):
    base_path = os.path.join('model_dir', 'checkpoint')
    structure_path = os.path.join(base_path, model_name + '_model_structure.h5')
    ckpt_path = os.path.join(base_path, model_name + '_' + model_sig)
    print(structure_path, '\n', ckpt_path)

    # load model structure
    model = tf.keras.models.load_model(structure_path)

    # find latest weights and load
    ckpts = glob.glob(os.path.join(ckpt_path, '*.h5'))
    ckpts.sort()
    ckpt = ckpts[-1]

    model.load_weights(ckpt)

    # print(ckpt)
    # model.summary()
    return model

def normalize1_and_gamma(arr, bits=16, beta=1/2.2):
    arr = arr / (2**bits -1) # (0, 1)
    arr = arr ** beta   # (0, 1)
    return arr

def main():
    # model name
    model_name = 'unetv2'
    model_name = 'unet'

    # model sig
    model_sig = 'noise3'

    # get model
    model = get_model(model_name, model_sig)

    # test data
    PATH_PIXELSHIFT = 'C:/Users/AI38/datasets/pixelshfit/PixelShift200_test'
    files = glob.glob(os.path.join(PATH_PIXELSHIFT, '*_3ch.npy'))

    pad_size = 32
    patch_size = 128
    # shape = np.load(files[0]).shape
    # height, width, channels = np.load(files[0]).shape
    # npatches_y, npatches_x = math.ceil(shape[0]/patch_size), math.ceil(shape[1]/patch_size)
    # print(arr_pred.shape)
    for idx, file in enumerate(files):
        arr = np.load(file)    # (0, 65535)
        # arr = arr / (2**16 -1) # (0, 1)
        # arr = arr ** (1/2.2)   # (0, 1)
        arr = normalize1_and_gamma(arr)
        img_arr = Image.fromarray(  (arr*255).astype(np.uint8) )
        img_arr.save(os.path.join(PATH_PIXELSHIFT, f'inf_ref_%02d.png'%(idx+1)))

        print('arr.shape', arr.shape)
        arr = np.pad(arr, ((pad_size, pad_size), (pad_size, pad_size),(0, 0)), 'symmetric')
        print('arr.shape', arr.shape)

        height, width, channels = arr.shape
        npatches_y = math.ceil((height+2*pad_size) / (patch_size-2*pad_size))
        npatches_x = math.ceil((width +2*pad_size) / (patch_size-2*pad_size))

        arr_pred = np.zeros_like(arr)
        print(idx, file, arr.shape, arr_pred.shape)
        # exit()
        cnt=0
        tcnt= npatches_x*npatches_y
        for idx_y in range(npatches_y):
            for idx_x  in range(npatches_x):
                if(cnt%10==0):
                    print(f'{cnt} / {tcnt}')
                cnt+=1
                sy = idx_y * (patch_size-2*pad_size)
                ey = sy + patch_size
                sx = idx_x * (patch_size-2*pad_size)
                ex = sx + patch_size

                if ey >= height:
                    ey = height-1
                    sy = height-patch_size-1

                if ex >= width:
                    ex = width-1
                    sx = width-patch_size-1

                arr_patch = arr[sy:ey, sx:ex,:]

                print(np.amin(arr_patch), np.amax(arr_patch) )

                # pre-process
                arr_patch = arr_patch**(1/2.2)
                arr_patch = (arr_patch*2) -1  # (0, 1) -> (-1, 1)

                # prediction
                pred = model.predict(arr_patch[np.newaxis,...])
                print(pred.shape)

                # post-process
                arr_pred[sy+pad_size:ey-pad_size, sx+pad_size:ex-pad_size, :] = \
                             (pred[0, pad_size:-pad_size, pad_size:-pad_size, :]+1)/2 #  (-1, 1) -> (0, 1)
                # print(np.amin(arr_patch), np.amax(arr_patch), np.amin(arr_pred), np.amax(arr_pred))
                # exit()

        # arr_pred.astype(np.uint8)
        arr_pred = arr_pred[pad_size:-pad_size, pad_size:-pad_size, :]
        img_pred = Image.fromarray((arr_pred*255).astype(np.uint8))
        # name = os.path.join(PATH_PIXELSHIFT, f'inf_{model_name}_{model_sig}_%02d.png'%(idx+1))
        name = os.path.join(PATH_PIXELSHIFT, f'inf_{model_name}_{model_sig}_%02d_gamma.png'%(idx+1))
        img_pred.save(name)
        print(np.amin(img_pred), np.amax(img_pred), np.amin(arr_pred.astype(np.uint8)), np.amax(arr_pred.astype(np.uint8)))

        exit()

if __name__ == '__main__':
    main()


# Author: Vlad Niculae <vlad@vene.ro>
# License: GNU LGPL v3

import numpy as np
from numpy.testing import assert_array_equal

from ad3 import factor_graph as fg

def test_sequence_dense():

    n_states = 3
    transition = np.eye(n_states).ravel()
    graph = fg.PFactorGraph()

    vars_expected = [0, 1, None, None, 1]
    variables = [graph.create_multi_variable(n_states) for _ in vars_expected]
    for prev, curr in zip(variables, variables[1:]):
        graph.create_factor_dense([prev, curr], transition)
    for var, ix in zip(variables, vars_expected):
        if ix is not None:
            var.set_log_potential(ix, 1)

    value, marginals, additionals, status = graph.solve()
    # 3 points for "observed" values, 3 points for consecutive equal vals
    assert value == 6

    expected = [0, 1, 1, 1, 1]
    obtained = np.array(marginals).reshape(5, -1).argmax(axis=1)
    assert_array_equal(expected, obtained)


from math import factorial

def count_differences(adapters):
    one_count, three_count = 0, 0
    current_rating = 0
    adapters.sort()
    for x in set(adapters):
        if x - current_rating == 1:
            one_count += 1
        elif x - current_rating == 3:
            three_count += 1
        current_rating = x
    return one_count * (three_count + 1)

def count_arrangements(adapters):
    adapters.sort()
    complete_list = [0] + list(set(adapters)) + [adapters[-1] + 3]
    times = 1
    left, right = 0, 0
    while left < len(complete_list) - 1 and right < len(complete_list) - 1:
        while complete_list[right + 1] - complete_list[right] == 1:
            right += 1
        times *= count_combination(complete_list[left:right+1])
        right += 1
        left = right
    return times

def count_combination(adapters):
    if len(adapters) == 3:
        return 2
    elif len(adapters) > 3:
        # full list + (full list minus 1 of the middle numbers) + (full list minus combination of any 2 middle numbers)
        result = 1 + len(adapters) - 2 + int(factorial(len(adapters) - 2) / 2)
        return result
    return 1

with open("data.txt") as file:
    adapters = [int(i) for i in file.read().splitlines()]
    print(count_differences(adapters))
    print(count_arrangements(adapters))


import functools
import pandas as pd
import numpy as np
import periodictable as pt
from pathlib import Path
from tinydb import TinyDB, Query
from .transform import formula_to_elemental
from ..util.meta import pyrolite_datafolder
from ..util.database import _list_tindyb_unique_values
import logging

logging.getLogger(__name__).addHandler(logging.NullHandler())
logger = logging.getLogger(__name__)

__dbpath__ = pyrolite_datafolder(subfolder="mineral") / "mindb.json"

@functools.lru_cache(maxsize=None)  # cache outputs for speed
def list_groups():
    """
    List the mineral groups present in the mineral database.

    Returns
    ----------
    :class:`list`
    """
    return _list_tindyb_unique_values("group", dbpath=__dbpath__)

@functools.lru_cache(maxsize=None)  # cache outputs for speed
def list_minerals():
    """
    List the minerals present in the mineral database.

    Returns
    ----------
    :class:`list`
    """
    return _list_tindyb_unique_values("name", dbpath=__dbpath__)

@functools.lru_cache(maxsize=None)  # cache outputs for speed
def list_formulae():
    """
    List the mineral formulae present in the mineral database.

    Returns
    ----------
    :class:`list`
    """
    return _list_tindyb_unique_values("formula", dbpath=__dbpath__)

def get_mineral(name="", dbpath=None):
    """
    Get a specific mineral from the database.

    Parameters
    ------------
    name : :class:`str`
        Name of the desired mineral.
    dbpath : :class:`pathlib.Path`, :class:`str`
        Optional overriding of the default database path.

    Returns
    --------
    :class:`pd.Series`
    """
    if dbpath is None:
        dbpath = __dbpath__

    assert name in list_minerals()
    with TinyDB(str(dbpath)) as db:
        out = db.get(Query().name == name)

    return pd.Series(out)

def parse_composition(composition, drop_zeros=True):
    """
    Parse a composition reference and return the composiiton as a :class:`~pandas.Series`

    Parameters
    -----------
    composition : :class:`str` | :class:`periodictable.formulas.Formula`
    """
    mnrl = None
    if composition in list_minerals():
        mnrl = get_mineral(composition)

    try:  # formulae
        form = pt.formula(composition)
        mnrl = pd.Series(formula_to_elemental(form))
        # could also check for formulae in the database, using f.atoms
    except:
        pass

    assert mnrl is not None
    if drop_zeros:
        mnrl = mnrl[mnrl != 0]
    return mnrl

def get_mineral_group(group=""):
    """
    Extract a mineral group from the database.

    Parameters
    -----------
    group : :class:`str`
        Group to extract from the mineral database.

    Returns
    ---------
    :class:`pandas.DataFrame`
        Dataframe of group members and compositions.
    """
    assert group in list_groups()
    with TinyDB(str(__dbpath__)) as db:
        grp = db.search(Query().group == group)

    df = pd.DataFrame(grp)
    meta, chem = (
        ["name", "formula"],
        [i for i in df.columns if i not in ["name", "formula", "group"]],
    )
    df = df.reindex(columns=meta + chem)
    df.loc[:, chem] = df.loc[:, chem].apply(pd.to_numeric)
    df = df.loc[:, (df != 0).any(axis=0)]  # remove zero-only columns
    return df

def update_database(path=None, **kwargs):
    """
    Update the mineral composition database.

    Parameters
    -----------
    path : :class:`str` | :class:`pathlib.Path`
        The desired filepath for the JSON database.

    Notes
    ------
    This will take the 'mins.csv' file from the mineral pyrolite data folder
    and construct a document-based JSON database.
    """
    mindf = pd.read_csv(pyrolite_datafolder(subfolder="mineral") / "mins.csv")
    mindf = mindf.reindex(
        columns=mindf.columns.tolist()
        + [str(a) for a in pt.formula(" ".join(mindf.formula.to_list())).atoms]
    )
    for ix in mindf.index:  # add elemental compositions
        el = parse_composition(pt.formula(mindf.loc[ix, "formula"]))
        mindf.loc[ix, el.index] = el

    mindf = mindf.fillna(0.0)

    if path is None:
        path = __dbpath__

    path = Path(path).with_suffix(".json")

    # name group formula composition
    with TinyDB(str(path)) as db:
        db.purge()
        for k, v in mindf.T.to_dict().items():
            db.insert(v)
        db.close()


"""
Support for random optimizers, including the random-greedy path.
"""

import functools
import heapq
import math
import numbers
import time
from collections import deque
from random import choices as random_choices
from random import seed as random_seed
from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple

from . import helpers, paths
from .typing import ArrayIndexType, ArrayType, PathType

__all__ = ["RandomGreedy", "random_greedy", "random_greedy_128"]

class RandomOptimizer(paths.PathOptimizer):
    """Base class for running any random path finder that benefits
    from repeated calling, possibly in a parallel fashion. Custom random
    optimizers should subclass this, and the `setup` method should be
    implemented with the following signature:

    ```python
    def setup(self, inputs, output, size_dict):
        # custom preparation here ...
        return trial_fn, trial_args
    ```

    Where `trial_fn` itself should have the signature::

    ```python
    def trial_fn(r, *trial_args):
        # custom computation of path here
        return ssa_path, cost, size
    ```

    Where `r` is the run number and could for example be used to seed a
    random number generator. See `RandomGreedy` for an example.

    **Parameters:**

    - **max_repeats** - *(int, optional)* The maximum number of repeat trials to have.
    - **max_time** - *(float, optional)* The maximum amount of time to run the algorithm for.
    - **minimize** - *({'flops', 'size'}, optional)* Whether to favour paths that minimize the total estimated flop-count or
        the size of the largest intermediate created.
    - **parallel** - *({bool, int, or executor-pool like}, optional)* Whether to parallelize the random trials, by default `False`. If
        `True`, use a `concurrent.futures.ProcessPoolExecutor` with the same
        number of processes as cores. If an integer is specified, use that many
        processes instead. Finally, you can supply a custom executor-pool which
        should have an API matching that of the python 3 standard library
        module `concurrent.futures`. Namely, a `submit` method that returns
        `Future` objects, themselves with `result` and `cancel` methods.
    - **pre_dispatch** - *(int, optional)* If running in parallel, how many jobs to pre-dispatch so as to avoid
        submitting all jobs at once. Should also be more than twice the number
        of workers to avoid under-subscription. Default: 128.

    **Attributes:**

    - **path** - *(list[tuple[int]])* The best path found so far.
    - **costs** - *(list[int])* The list of each trial's costs found so far.
    - **sizes** - *(list[int])* The list of each trial's largest intermediate size so far.
    """

    def __init__(
        self,
        max_repeats: int = 32,
        max_time: Optional[float] = None,
        minimize: str = "flops",
        parallel: bool = False,
        pre_dispatch: int = 128,
    ):

        if minimize not in ("flops", "size"):
            raise ValueError("`minimize` should be one of {'flops', 'size'}.")

        self.max_repeats = max_repeats
        self.max_time = max_time
        self.minimize = minimize
        self.better = paths.get_better_fn(minimize)
        self._parallel = False
        self.parallel = parallel
        self.pre_dispatch = pre_dispatch

        self.costs: List[int] = []
        self.sizes: List[int] = []
        self.best: Dict[str, Any] = {"flops": float("inf"), "size": float("inf")}

        self._repeats_start = 0
        self._executor: Any
        self._futures: Any

    @property
    def path(self) -> PathType:
        """The best path found so far."""
        return paths.ssa_to_linear(self.best["ssa_path"])

    @property
    def parallel(self) -> bool:
        return self._parallel

    @parallel.setter
    def parallel(self, parallel: bool) -> None:
        # shutdown any previous executor if we are managing it
        if getattr(self, "_managing_executor", False):
            self._executor.shutdown()

        self._parallel = parallel
        self._managing_executor = False

        if parallel is False:
            self._executor = None
            return

        if parallel is True:
            from concurrent.futures import ProcessPoolExecutor

            self._executor = ProcessPoolExecutor()
            self._managing_executor = True
            return

        if isinstance(parallel, numbers.Number):
            from concurrent.futures import ProcessPoolExecutor

            self._executor = ProcessPoolExecutor(parallel)
            self._managing_executor = True
            return

        # assume a pool-executor has been supplied
        self._executor = parallel

    def _gen_results_parallel(self, repeats: Iterable[int], trial_fn: Any, args: Any) -> Generator[Any, None, None]:
        """Lazily generate results from an executor without submitting all jobs at once."""
        self._futures = deque()

        # the idea here is to submit at least ``pre_dispatch`` jobs *before* we
        # yield any results, then do both in tandem, before draining the queue
        for r in repeats:
            if len(self._futures) < self.pre_dispatch:
                self._futures.append(self._executor.submit(trial_fn, r, *args))
                continue
            yield self._futures.popleft().result()

        while self._futures:
            yield self._futures.popleft().result()

    def _cancel_futures(self) -> None:
        if self._executor is not None:
            for f in self._futures:
                f.cancel()

    def setup(
        self,
        inputs: List[ArrayIndexType],
        output: ArrayIndexType,
        size_dict: Dict[str, int],
    ) -> Tuple[Any, Any]:
        raise NotImplementedError

    def __call__(
        self,
        inputs: List[ArrayIndexType],
        output: ArrayIndexType,
        size_dict: Dict[str, int],
        memory_limit: Optional[int] = None,
    ) -> PathType:
        self._check_args_against_first_call(inputs, output, size_dict)

        # start a timer?
        if self.max_time is not None:
            t0 = time.time()

        trial_fn, trial_args = self.setup(inputs, output, size_dict)

        r_start = self._repeats_start + len(self.costs)
        r_stop = r_start + self.max_repeats
        repeats = range(r_start, r_stop)

        # create the trials lazily
        if self._executor is not None:
            trials = self._gen_results_parallel(repeats, trial_fn, trial_args)
        else:
            trials = (trial_fn(r, *trial_args) for r in repeats)

        # assess the trials
        for ssa_path, cost, size in trials:

            # keep track of all costs and sizes
            self.costs.append(cost)
            self.sizes.append(size)

            # check if we have found a new best
            found_new_best = self.better(cost, size, self.best["flops"], self.best["size"])

            if found_new_best:
                self.best["flops"] = cost
                self.best["size"] = size
                self.best["ssa_path"] = ssa_path

            # check if we have run out of time
            if (self.max_time is not None) and (time.time() > t0 + self.max_time):
                break

        self._cancel_futures()
        return self.path

    def __del__(self):
        # if we created the parallel pool-executor, shut it down
        if getattr(self, "_managing_executor", False):
            self._executor.shutdown()

def thermal_chooser(queue, remaining, nbranch=8, temperature=1, rel_temperature=True):
    """A contraction 'chooser' that weights possible contractions using a
    Boltzmann distribution. Explicitly, given costs `c_i` (with `c_0` the
    smallest), the relative weights, `w_i`, are computed as:

        $$w_i = exp( -(c_i - c_0) / temperature)$$

    Additionally, if `rel_temperature` is set, scale `temperature` by
    `abs(c_0)` to account for likely fluctuating cost magnitudes during the
    course of a contraction.

    **Parameters:**

    - **queue** - *(list)* The heapified list of candidate contractions.
    - **remaining** - *(dict[str, int])* Mapping of remaining inputs' indices to the ssa id.
    - **temperature** - *(float, optional)* When choosing a possible contraction, its relative probability will be
        proportional to `exp(-cost / temperature)`. Thus the larger
        `temperature` is, the further random paths will stray from the normal
        'greedy' path. Conversely, if set to zero, only paths with exactly the
        same cost as the best at each step will be explored.
    - **rel_temperature** - *(bool, optional)* Whether to normalize the `temperature` at each step to the scale of
        the best cost. This is generally beneficial as the magnitude of costs
        can vary significantly throughout a contraction.
    - **nbranch** - *(int, optional)* How many potential paths to calculate probability for and choose from at each step.

    **Returns:**

    - **cost**
    - **k1**
    - **k2**
    - **k3**
    """
    n = 0
    choices = []
    while queue and n < nbranch:
        cost, k1, k2, k12 = heapq.heappop(queue)
        if k1 not in remaining or k2 not in remaining:
            continue  # candidate is obsolete
        choices.append((cost, k1, k2, k12))
        n += 1

    if n == 0:
        return None
    if n == 1:
        return choices[0]

    costs = [choice[0][0] for choice in choices]
    cmin = costs[0]

    # adjust by the overall scale to account for fluctuating absolute costs
    if rel_temperature:
        temperature *= max(1, abs(cmin))

    # compute relative probability for each potential contraction
    if temperature == 0.0:
        energies = [1 if c == cmin else 0 for c in costs]
    else:
        # shift by cmin for numerical reasons
        energies = [math.exp(-(c - cmin) / temperature) for c in costs]

    # randomly choose a contraction based on energies
    (chosen,) = random_choices(range(n), weights=energies)
    cost, k1, k2, k12 = choices.pop(chosen)

    # put the other choice back in the heap
    for other in choices:
        heapq.heappush(queue, other)

    return cost, k1, k2, k12

def ssa_path_compute_cost(
    ssa_path: PathType,
    inputs: List[ArrayIndexType],
    output: ArrayIndexType,
    size_dict: Dict[str, int],
) -> Tuple[int, int]:
    """Compute the flops and max size of an ssa path."""
    inputs = list(map(frozenset, inputs))  # type: ignore
    output = frozenset(output)
    remaining = set(range(len(inputs)))
    total_cost = 0
    max_size = 0

    for i, j in ssa_path:
        k12, flops12 = paths.calc_k12_flops(inputs, output, remaining, i, j, size_dict)  # type: ignore
        remaining.discard(i)
        remaining.discard(j)
        remaining.add(len(inputs))
        inputs.append(k12)
        total_cost += flops12
        max_size = max(max_size, helpers.compute_size_by_dict(k12, size_dict))

    return total_cost, max_size

def _trial_greedy_ssa_path_and_cost(
    r: int,
    inputs: List[ArrayIndexType],
    output: ArrayIndexType,
    size_dict: Dict[str, int],
    choose_fn: Any,
    cost_fn: Any,
) -> Tuple[PathType, int, int]:
    """A single, repeatable, greedy trial run. **Returns:** ``ssa_path`` and cost."""
    if r == 0:
        # always start with the standard greedy approach
        choose_fn = None

    random_seed(r)

    ssa_path = paths.ssa_greedy_optimize(inputs, output, size_dict, choose_fn, cost_fn)
    cost, size = ssa_path_compute_cost(ssa_path, inputs, output, size_dict)

    return ssa_path, cost, size

class RandomGreedy(RandomOptimizer):
    """

    **Parameters:**

    - **cost_fn** - *(callable, optional)* A function that returns a heuristic 'cost' of a potential contraction
        with which to sort candidates. Should have signature
        `cost_fn(size12, size1, size2, k12, k1, k2)`.
    - **temperature** - *(float, optional)* When choosing a possible contraction, its relative probability will be
        proportional to `exp(-cost / temperature)`. Thus the larger
        `temperature` is, the further random paths will stray from the normal
        'greedy' path. Conversely, if set to zero, only paths with exactly the
        same cost as the best at each step will be explored.
    - **rel_temperature** - *(bool, optional)* Whether to normalize the ``temperature`` at each step to the scale of
        the best cost. This is generally beneficial as the magnitude of costs
        can vary significantly throughout a contraction. If False, the
        algorithm will end up branching when the absolute cost is low, but
        stick to the 'greedy' path when the cost is high - this can also be
        beneficial.
    - **nbranch** - *(int, optional)* How many potential paths to calculate probability for and choose from at each step.
    - **kwargs** - Supplied to RandomOptimizer.
    """

    def __init__(
        self,
        cost_fn: str = "memory-removed-jitter",
        temperature: float = 1.0,
        rel_temperature: bool = True,
        nbranch: int = 8,
        **kwargs: Any,
    ):
        self.cost_fn = cost_fn
        self.temperature = temperature
        self.rel_temperature = rel_temperature
        self.nbranch = nbranch
        super().__init__(**kwargs)

    @property
    def choose_fn(self) -> Any:
        """The function that chooses which contraction to take - make this a
        property so that ``temperature`` and ``nbranch`` etc. can be updated
        between runs.
        """
        if self.nbranch == 1:
            return None

        return functools.partial(
            thermal_chooser,
            temperature=self.temperature,
            nbranch=self.nbranch,
            rel_temperature=self.rel_temperature,
        )

    def setup(
        self,
        inputs: List[ArrayIndexType],
        output: ArrayIndexType,
        size_dict: Dict[str, int],
    ) -> Tuple[Any, Any]:
        fn = _trial_greedy_ssa_path_and_cost
        args = (inputs, output, size_dict, self.choose_fn, self.cost_fn)
        return fn, args

def random_greedy(
    inputs: List[ArrayIndexType],
    output: ArrayIndexType,
    idx_dict: Dict[str, int],
    memory_limit: Optional[int] = None,
    **optimizer_kwargs: Any,
) -> ArrayType:
    """ """
    optimizer = RandomGreedy(**optimizer_kwargs)
    return optimizer(inputs, output, idx_dict, memory_limit)

random_greedy_128 = functools.partial(random_greedy, max_repeats=128)


t=int(input())
while(t):
    t-=1
    a=str(input())
    n=len(a)
    a=list(a)
    if(n%2==1):
        a1=a[0:n//2]
        a2=a[n//2+1:n]
        #print(a1,a2)
    else:
        a1=a[0:n//2]
        a2=a[n//2:n]
        #print(a1,a2)
    a1.sort()
    a2.sort()
    if(a1==a2):
        print("YES")
    else:
        print("NO")


import argparse
import os
from glob import glob
import json
import jellyfish
from text_extraction import Rectangle, AUTHOR_LABEL, DESCRIPTION_LABEL
import re
import pandas as pd
from tqdm import tqdm

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input-folder", required=True, help="Folder with the json file")
ap.add_argument("-o", "--output-folder", required=True, help="Folder with the saved corrected json files")
args = ap.parse_args()

INPUT_FOLDER = args.input_folder
OUTPUT_FOLDER = args.output_folder

input_elements = sorted([os.path.basename(f) for f in glob(os.path.join(OUTPUT_FOLDER, '*.json'))])

def get_transcription(basename, groundtruth: bool):
    saved_file = os.path.join(OUTPUT_FOLDER, basename)
    if groundtruth:
        with open(saved_file, 'r') as f:
            return json.load(f)
    else:
        input_file = os.path.join(INPUT_FOLDER, basename)
        rects = Rectangle.load_from_json(input_file)
        return {
            AUTHOR_LABEL: next((r.text for r in rects if r.label == AUTHOR_LABEL), ''),
            DESCRIPTION_LABEL: next((r.text for r in rects if r.label == DESCRIPTION_LABEL), '')
        }

def normalized_str(s):
    s = s.lower()
    s = re.sub(r"[,;\-\.\n\(\)']", ' ', s)
    s = re.sub(' +', ' ', s)
    return s.strip()

results = []
for basename in tqdm(input_elements):
    gt_transcription = get_transcription(basename, groundtruth=True)
    input_transcription = get_transcription(basename, groundtruth=False)
    gt_author, gt_description = gt_transcription[AUTHOR_LABEL], gt_transcription[DESCRIPTION_LABEL]
    extracted_author, extracted_description = input_transcription[AUTHOR_LABEL], input_transcription[DESCRIPTION_LABEL]
    # print(gt_author, gt_description, extracted_author, extracted_description)
    try:
        results.append({
            'basename': basename,
            'author_error': jellyfish.damerau_levenshtein_distance(gt_author, extracted_author),
            'description_error': jellyfish.damerau_levenshtein_distance(gt_description, extracted_description),
            'author_len': len(gt_author),
            'description_len': len(gt_description),
            'author_error_normalized': jellyfish.damerau_levenshtein_distance(normalized_str(gt_author),
                                                                              normalized_str(extracted_author)),
            'description_error_normalized': jellyfish.damerau_levenshtein_distance(normalized_str(gt_description),
                                                                                normalized_str(
                                                                                extracted_description))
        })
        if jellyfish.damerau_levenshtein_distance(normalized_str(gt_author), normalized_str(extracted_author))>0:
            print(gt_author, extracted_author)
    except Exception:
        print(basename)

df = pd.DataFrame.from_records(results)

print('CER (author) : {:.2f}'.format(100 * df.author_error.sum() / df.author_len.sum()))
print('CER (description) : {:.2f}'.format(100 * df.description_error.sum() / df.description_len.sum()))
print('CER (author, normalized) : {:.2f}'.format(100 * df.author_error_normalized.sum() / df.author_len.sum()))
print('CER (description, normalized) : {:.2f}'.format(
    100 * df.description_error_normalized.sum() / df.description_len.sum()))

print('Perfect transcription (author) : {:.2f}'.format(100 * (df.author_error == 0).sum() / len(df)))
print('Perfect transcription (description) : {:.2f}'.format(100 * (df.description_error == 0).sum() / len(df)))
print('Perfect transcription (author, normalized) : {:.2f}'.format(
    100 * (df.author_error_normalized == 0).sum() / len(df)))
print('Perfect transcription (description, normalized) : {:.2f}'.format(
    100 * (df.description_error_normalized == 0).sum() / len(df)))

print('1-away transcription (author) : {:.2f}'.format(100 * (df.author_error <= 1).sum() / len(df)))
print('1-away  transcription (description) : {:.2f}'.format(100 * (df.description_error <= 1).sum() / len(df)))
print('1-away  transcription (author, normalized) : {:.2f}'.format(
    100 * (df.author_error_normalized <= 1).sum() / len(df)))
print('1-away  transcription (description, normalized) : {:.2f}'.format(
    100 * (df.description_error_normalized <= 1).sum() / len(df)))


'''
Copyright 2022 Airbus SAS

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
from climateeconomics.core.core_witness.climateeco_discipline import ClimateEcoDiscipline
from climateeconomics.core.core_witness.macroeconomics_model import MacroEconomics
from sostrades_core.tools.post_processing.charts.two_axes_instanciated_chart import InstanciatedSeries, TwoAxesInstanciatedChart
from sostrades_core.tools.post_processing.charts.chart_filter import ChartFilter
import pandas as pd
import numpy as np
from copy import deepcopy

class InvestDiscipline(ClimateEcoDiscipline):
    "Macroeconomics discipline for WITNESS"

    # ontology information
    _ontology_data = {
        'label': 'WITNESS Investissement Model',
        'type': 'Research',
        'source': 'SoSTrades Project',
        'validated': '',
        'validated_by': 'SoSTrades Project',
        'last_modification_date': '',
        'category': '',
        'definition': '',
        'icon': '',
        'version': '',
    }
    _maturity = 'Research'
    years = np.arange(2020, 2101)
    DESC_IN = {
        'energy_investment_macro': {'type': 'dataframe', 'visibility': 'Shared', 'namespace': 'ns_witness'},
        'energy_investment': {'type': 'dataframe', 'visibility': 'Shared', 'namespace': 'ns_energy_mix'},
        'invest_norm': {'type': 'float', 'default': 10.0},
        'formulation': {'type': 'string', 'default': 'objective', 'possile_values': ['objective', 'constraint']},
        'max_difference': {'type': 'float', 'default': 1.0e-1},
    }

    DESC_OUT = {
        'invest_objective': {'type': 'dataframe', 'visibility': 'Shared', 'namespace': 'ns_witness'},
        'diff_norm': {'type': 'array'}
    }

    def run(self):
        # Get inputs
        inputs = self.get_sosdisc_inputs()

        difference = np.linalg.norm(inputs['energy_investment_macro']['energy_investment'].values -
                                    inputs['energy_investment']['energy_investment'].values) / inputs['invest_norm']

        if inputs['formulation'] == 'objective':
            invest_objective = difference
        elif inputs['formulation'] == 'constraint':
            invest_objective = inputs['max_difference'] - difference

        # Store output data
        dict_values = {'invest_objective': pd.DataFrame(
            {'norm': [invest_objective]}),
            'diff_norm': difference}
        self.store_sos_outputs_values(dict_values)

    def compute_sos_jacobian(self):
        """
        Compute jacobian for each coupling variable
        gradiant of coupling variable to compute
        """
        inputs = self.get_sosdisc_inputs()
        invest_objective = self.get_sosdisc_outputs(
            'invest_objective')['norm'].values[0]
        dinvestment = (inputs['energy_investment_macro']['energy_investment'].values -
                       inputs['energy_investment']['energy_investment'].values) / invest_objective / inputs['invest_norm']**2

        self.set_partial_derivative_for_other_types(
            ('invest_objective', 'norm'), ('energy_investment_macro', 'energy_investment'), dinvestment)  # Invest from T$ to G$
        self.set_partial_derivative_for_other_types(
            ('invest_objective', 'norm'), ('energy_investment', 'energy_investment'), -dinvestment)  # Invest from T$ to G$

    def get_chart_filter_list(self):

        # For the outputs, making a graph for tco vs year for each range and for specific
        # value of ToT with a shift of five year between then

        chart_filters = []

        chart_list = ['Difference of investments']
        # First filter to deal with the view : program or actor
        chart_filters.append(ChartFilter(
            'Charts', chart_list, chart_list, 'charts'))

        return chart_filters

    def get_post_processing_list(self, chart_filters=None):

        # For the outputs, making a graph for tco vs year for each range and for specific
        # value of ToT with a shift of five year between then

        instanciated_charts = []

        # Overload default value with chart filter
        if chart_filters is not None:
            for chart_filter in chart_filters:
                if chart_filter.filter_key == 'charts':
                    chart_list = chart_filter.selected_values

        if 'Difference of investments' in chart_list:

            energy_investment_macro = self.get_sosdisc_inputs(
                'energy_investment_macro')

            energy_investment = self.get_sosdisc_inputs('energy_investment')

            years = list(energy_investment_macro['years'].values)

            year_start = years[0]
            year_end = years[len(years) - 1]

            chart_name = 'Energy investments between macroeconomy output and energy input'

            new_chart = TwoAxesInstanciatedChart(
                'years', 'Investments', chart_name=chart_name)

            energy_investment_series = InstanciatedSeries(
                years, list(energy_investment['energy_investment'].values), 'energy investment (energy)', 'lines')

            new_chart.series.append(energy_investment_series)

            energy_investment_macro_series = InstanciatedSeries(
                years, list(energy_investment_macro['energy_investment'].values), 'energy_investment (macroeconomy)', 'lines')

            new_chart.series.append(energy_investment_macro_series)
            instanciated_charts.append(new_chart)

            norm = self.get_sosdisc_outputs('diff_norm')
            chart_name = 'Differences between energy investments'

            new_chart = TwoAxesInstanciatedChart(
                'years', 'Differences of investments', chart_name=chart_name)

            energy_investment_series = InstanciatedSeries(
                years, list(energy_investment_macro['energy_investment'].values - energy_investment['energy_investment'].values), '', 'lines')

            new_chart.series.append(energy_investment_series)

            instanciated_charts.append(new_chart)

        return instanciated_charts


import mysql.connector
from enc_dec import *
# MySQL 연결 설정

config = {
}

def upsert_db(file_id, share_doc_url):

    # MySQL 연결
    conn = mysql.connector.connect(**config)
    cursor = conn.cursor()

    # 조회할 데이터
    file_id_to_search = file_id  # 조회할 파일 ID에 맞게 수정

    # 데이터 조회 쿼리
    select_query = "SELECT * FROM share_doc WHERE file_id = %s"

    # 데이터 삽입 쿼리
    insert_query = "INSERT INTO share_doc (file_id, share_doc_url) VALUES (%s, %s)"

    # 데이터 업데이트 쿼리
    update_query = "UPDATE share_doc SET share_doc_url = %s, uptdate=now()  WHERE file_id = %s"

    # 데이터베이스에서 데이터 조회
    cursor.execute(select_query, (file_id_to_search,))
    existing_data = cursor.fetchone()

    if existing_data:
        # 데이터가 존재하는 경우 업데이트
        new_share_data = share_doc_url  # 업데이트할 데이터에 맞게 수정
        cursor.execute(update_query, (new_share_data, file_id_to_search))
        conn.commit()
        print(f"데이터가 업데이트되었습니다. (file_id: {file_id_to_search})")
    else:
        # 데이터가 존재하지 않는 경우 삽입
        share_data_to_insert = share_doc_url  # 삽입할 데이터에 맞게 수정
        cursor.execute(insert_query, (file_id_to_search, share_data_to_insert))
        conn.commit()
        print(f"데이터가 삽입되었습니다. (file_id: {file_id_to_search})")

    # 연결 종료
    cursor.close()
    conn.close()

def delete_db(file_id):
    # MySQL 연결 설정

    # MySQL 연결
    conn = mysql.connector.connect(**config)
    cursor = conn.cursor()

    # 조회할 데이터
    file_id_to_search = file_id  # 조회할 파일 ID에 맞게 수정

    # 데이터 조회 쿼리
    #select_query = "SELECT * FROM share_doc WHERE file_id = %s"

    # 데이터 업데이트 쿼리
    delete_query = "DELETE FROM share_doc WHERE file_id = %s"

    # 데이터베이스에서 데이터 조회
    #cursor.execute(select_query, (file_id_to_search,))
    #existing_data = cursor.fetchone()

    #if existing_data:
        # 데이터가 존재하는 경우 업데이트
    cursor.execute(delete_query, (file_id_to_search,))
    conn.commit()
    #print(f"데이터가 삭제되었습니다. (file_id: {file_id_to_search})")

    # 연결 종료
    cursor.close()
    conn.close()
a=''
b=''

def get_aws():
    global a
    global b
    # MySQL 연결
    conn = mysql.connector.connect(**config)
    cursor = conn.cursor()
     # 키 파일에서 키를 읽어옴
    with open("c:/pdf/license/license.key", "rb") as key_file:
        key = key_file.read()
    # 조회할 데이터
    file_id_to_search = key  # 조회할 파일 ID에 맞게 수정

    # 데이터 조회 쿼리
    select_query = "SELECT * FROM awsk_mgmt WHERE enc_key = %s"

    # 데이터베이스에서 데이터 조회
    cursor.execute(select_query, (file_id_to_search,))
    existing_data = cursor.fetchone()
    #print(existing_data[1])
    #print(existing_data[2])

    a = get_dec_awsacckey(key, existing_data[1])
    b = get_dec_awsacckey(key, existing_data[2])
    empty_tuple = (a,b)
    #print(a, b)
    #print(existing_data.type)

    # 연결 종료
    cursor.close()
    conn.close()
    return empty_tuple

if __name__ == "__main__":
    empty_tuple = get_aws()
    print(empty_tuple[0])
    print(empty_tuple[1])


import pyautogui
import time

# Locating the game window

pyautogui.alert('Put the mouse pointer over the top left corner of the game then press "Enter"')
TOP_LEFT = pyautogui.position()

pyautogui.alert('Put the mouse pointer over the bottom right corner of the game then press "Enter"')
BOT_RIGHT = pyautogui.position()

DIM = (BOT_RIGHT[0] - TOP_LEFT[0], BOT_RIGHT[1] - TOP_LEFT[1])

print(TOP_LEFT,BOT_RIGHT,DIM)

# Generating the positions

QSKILL = (0.3*DIM[0]+TOP_LEFT[0], 0.9*DIM[1]+TOP_LEFT[1])
WSKILL = (0.4*DIM[0]+TOP_LEFT[0], 0.9*DIM[1]+TOP_LEFT[1])
ESKILL = (0.5*DIM[0]+TOP_LEFT[0], 0.9*DIM[1]+TOP_LEFT[1])
RSKILL = (0.6*DIM[0]+TOP_LEFT[0], 0.9*DIM[1]+TOP_LEFT[1])
SKILLS = [QSKILL,WSKILL,ESKILL,RSKILL]

SLOTZ = [[( (0.1+(i*0.07))*DIM[0]+TOP_LEFT[0], (0.26+(j*0.125))*DIM[1]+TOP_LEFT[1] )for i in range(5)]for j in range(6)]
SLOTS = [None,]
for line in SLOTZ:
    SLOTS += line

# Tool functions

def use(slot, chest = False):
    pyautogui.moveTo(SLOTS[slot][0], SLOTS[slot][1])
    time.sleep(.1)
    pyautogui.click()
    pyautogui.moveRel(0.194*DIM[0], 0.185*DIM[1])
    time.sleep(.1)
    pyautogui.click()
    if chest :
        pyautogui.moveTo(0.7*DIM[0]+TOP_LEFT[0], 0.5*DIM[1]+TOP_LEFT[1])
        time.sleep(.4)
        pyautogui.click()

def sell(slot):
    pyautogui.click(SLOTS[slot][0], SLOTS[slot][1])
    time.sleep(.4)
    pos= pyautogui.locateCenterOnScreen('sell_button.png', region=(SLOTS[slot][0], SLOTS[slot][1], DIM[0]/4, DIM[1]/2), grayscale=True)
    print(pos)
    pyautogui.click(pos[0],pos[1])

def equip(slot):
    pyautogui.moveTo(SLOTS[slot][0], SLOTS[slot][1])
    time.sleep(.1)
    pyautogui.click()
    pyautogui.moveRel(0.192*DIM[0], 0.198*DIM[1])
    time.sleep(.1)
    pyautogui.click()

def open_chest(slot, n):
    for i in range(n):
        use(slot, chest=True)

running = True

while running :

    userinput = pyautogui.prompt(text = '1 - Open Chests \n2 - Sell items\n 9 - Quit', title = 'What do you want to do ?')

    if userinput == '1':
        i = pyautogui.prompt(text='Print the slot number (1 to 30) of the chest followed by the number of chests to open. Example : 5 20').split()
        open_chest(int(i[0]), int(i[1]))

    elif userinput == '2':

        pyautogui.alert('Put the mouse pointer over the "SELL" button then press "Enter"')
        pos = pyautogui.position()
        pyautogui.screenshot('sell_button.png', region=(pos[0],pos[1], 100,50))

        i = pyautogui.prompt(text='Write the starting and end slot (inclusive) of the items you want to sell, EVERYTHING in between will be sold !').split()
        start, end = int(i[0]), int(i[1])
        for slot in range(start, end+1):
            sell(slot)
            time.sleep(.1)

    else :
        running = False


from configs import ssd300 as cfg

import torch
import torchvision.transforms as transforms

def base_transform(size):
    transform = transforms.Compose([
        transforms.Resize(size),
        transforms.ToTensor()
    ])
    return transform

class BaseTransform:
    def __init__(self, size, mean):
        self.size = size

    def __call__(self, image, boxes=None, labels=None):
        return base_transform(self.size), boxes, labels

class VOCAnnotationTransform(object):
    """Transforms a VOC annotation into a Tensor of bbox coords and label index
    Initilized with a dictionary lookup of classnames to indexes
    Arguments:
        class_to_ind (dict, optional): dictionary lookup of classnames -> indexes
            (default: alphabetic indexing of VOC's 20 classes)
        keep_difficult (bool, optional): keep difficult instances or not
            (default: False)
        height (int): height
        width (int): width
    """

    def __init__(self, class_to_ind=None, keep_difficult=False):
        self.class_to_ind = class_to_ind or dict(
            zip(cfg.VOC_CLASSES, range(len(cfg.VOC_CLASSES))))
        self.keep_difficult = keep_difficult

    def __call__(self, target, width, height):
        """
        Arguments:
            target (annotation) : the target annotation to be made usable
                will be an ET.Element
        Returns:
            a list containing lists of bounding boxes  [bbox coords, class name]
        """
        res = []
        for obj in target.iter('object'):
            difficult = int(obj.find('difficult').text) == 1
            if not self.keep_difficult and difficult:
                continue
            name = obj.find('name').text.lower().strip()
            bbox = obj.find('bndbox')

            pts = ['xmin', 'ymin', 'xmax', 'ymax']
            bndbox = []
            for i, pt in enumerate(pts):
                cur_pt = int(bbox.find(pt).text) - 1
                # scale height or width
                cur_pt = cur_pt / width if i % 2 == 0 else cur_pt / height
                bndbox.append(cur_pt)
            label_idx = self.class_to_ind[name]
            bndbox.append(label_idx)
            res += [bndbox]  # [xmin, ymin, xmax, ymax, label_ind]
            # img_id = target.find('filename').text[:-4]

        return res  # [[xmin, ymin, xmax, ymax, label_ind], ... ]


import json
from typing import Any, Dict, List, Optional, Set

from clairvoyance.entities import GraphQLPrimitive
from clairvoyance.entities.context import log
from clairvoyance.entities.primitives import GraphQLKind

class Schema:
    """Host of the introspection data."""

    def __init__(
        self,
        query_type: str = None,
        mutation_type: str = None,
        subscription_type: str = None,
        schema: Dict[str, Any] = None,
    ):
        if schema:
            self._schema = {
                'directives': schema['data']['__schema']['directives'],
                'mutationType': schema['data']['__schema']['mutationType'],
                'queryType': schema['data']['__schema']['queryType'],
                'subscriptionType': schema['data']['__schema']['subscriptionType'],
                'types': [],
            }
            self.types = {}
            for t in schema['data']['__schema']['types']:
                typ = Type.from_json(t)
                self.types[typ.name] = typ
        else:
            self.query_type = {'name': query_type} if query_type else None
            self.mutation_type = {'name': mutation_type} if mutation_type else None
            self.subscription_type = ({'name': subscription_type} if subscription_type else None)
            self._schema = {
                'directives': [],
                'queryType': self.query_type,
                'mutationType': self.mutation_type,
                'subscriptionType': self.subscription_type,
                'types': [],
            }
            self.types = {
                GraphQLPrimitive.STRING: Type(
                    name=GraphQLPrimitive.STRING,
                    kind=GraphQLKind.SCALAR,
                ),
                GraphQLPrimitive.ID: Type(
                    name=GraphQLPrimitive.ID,
                    kind=GraphQLKind.SCALAR,
                ),
            }
            if query_type:
                self.add_type(query_type, 'OBJECT')
            if mutation_type:
                self.add_type(mutation_type, 'OBJECT')
            if subscription_type:
                self.add_type(subscription_type, 'OBJECT')

    # Adds type to schema if it's not exists already
    def add_type(
        self,
        name: str,
        kind: str,
    ) -> None:
        """Adds type to schema if it's not exists already."""

        if name not in self.types:
            typ = Type(name=name, kind=kind)
            self.types[name] = typ

    def __repr__(self) -> str:
        """String representation of the schema."""

        schema = {'data': {'__schema': self._schema}}

        for t in self.types.values():
            schema['data']['__schema']['types'].append(t.to_json())

        output = json.dumps(schema, indent=4, sort_keys=True)
        return output

    def get_path_from_root(
        self,
        name: str,
    ) -> List[str]:
        """Getting path starting from root.

        The algorigthm explores the schema in a DFS manner. It uses a set to keep track of visited nodes, and a list to keep track of the path. Keeping track of
        the visited nodes is necessary to avoid infinite loops (ie. recursions in the schema). If a full iteration over the types is made without finding a
        match, it means that the schema is not connected, and the path cannot be found.
        """

        log().debug(f'Entered get_path_from_root({name})')
        path_from_root: List[str] = []

        if name not in self.types:
            raise Exception(f'Type \'{name}\' not in schema!')

        roots = [
            self._schema['queryType']['name'] if self._schema['queryType'] else '',
            self._schema['mutationType']['name'] if self._schema['mutationType'] else '',
            self._schema['subscriptionType']['name'] if self._schema['subscriptionType'] else '',
        ]
        roots = [r for r in roots if r]

        visited = set()
        initial_name = name
        while name not in roots:
            found = False
            for t in self.types.values():
                for f in t.fields:
                    key = f'{t.name}.{f.name}'
                    if key in visited:
                        continue
                    if f.type.name == name:
                        path_from_root.insert(0, f.name)
                        visited.add(key)
                        name = t.name
                        found = True
            if not found:
                log().debug('get_path_from_root: Ran an iteration with no matches found')
                raise Exception(f'Could not find path from root to \'{initial_name}\' \nCurrent path: {path_from_root}')

        # Prepend queryType or mutationType
        path_from_root.insert(0, name)

        return path_from_root

    def get_type_without_fields(
        self,
        ignored: Set[str] = None,
    ) -> str:
        """Gets the type without a field."""
        ignored = ignored or set()

        for t in self.types.values():
            if not t.fields and t.name not in ignored and t.kind != GraphQLKind.INPUT_OBJECT:
                return t.name

        return ''

    def convert_path_to_document(
        self,
        path: List[str],
    ) -> str:
        """Converts a path to document."""

        log().debug(f'Entered convert_path_to_document({path})')
        doc = 'FUZZ'

        while len(path) > 1:
            doc = f'{path.pop()} {{ {doc} }}'

        if self._schema['queryType'] and path[0] == self._schema['queryType']['name']:
            doc = f'query {{ {doc} }}'
        elif self._schema['mutationType'] and path[0] == self._schema['mutationType']['name']:
            doc = f'mutation {{ {doc} }}'
        elif self._schema['subscriptionType'] and path[0] == self._schema['subscriptionType']['name']:
            doc = f'subscription {{ {doc} }}'
        else:
            raise Exception('Unknown operation type')

        return doc

class TypeRef:
    def __init__(
        self,
        name: str,
        kind: str,
        is_list: bool = False,
        non_null_item: bool = False,
        non_null: bool = False,
    ) -> None:
        if not is_list and non_null_item:
            raise Exception('elements can\'t be NON_NULL if TypeRef is not LIST')

        self.name = name
        self.kind = kind
        self.is_list = is_list
        self.non_null = non_null
        self.list = self.is_list
        self.non_null_item = non_null_item

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, TypeRef):
            for key, attr in self.__dict__.items():
                if attr != other.__dict__[key]:
                    return False
            return True
        return False

    def __str__(self) -> str:
        return str(self.__dict__)

    def to_json(self) -> Dict[str, Any]:
        j: Dict[str, Any] = {'kind': self.kind, 'name': self.name, 'ofType': None}

        if self.non_null_item:
            j = {'kind': GraphQLKind.NON_NULL, 'name': None, 'ofType': j}

        if self.list:
            j = {'kind': GraphQLKind.LIST, 'name': None, 'ofType': j}

        if self.non_null:
            j = {'kind': GraphQLKind.NON_NULL, 'name': None, 'ofType': j}

        return j

class InputValue:
    def __init__(
        self,
        name: str,
        typ: TypeRef,
    ) -> None:
        self.name = name
        self.type = typ

    def __str__(self) -> str:
        return f'{{ \'name\': {self.name}, \'type\': {str(self.type)} }}'

    def to_json(self) -> dict:
        return {
            'defaultValue': None,
            'description': None,
            'name': self.name,
            'type': self.type.to_json(),
        }

    @classmethod
    def from_json(
        cls,
        _json: Dict[str, Any],
    ) -> 'InputValue':
        name = _json['name']
        typ = field_or_arg_type_from_json(_json['type'])

        return cls(
            name=name,
            typ=typ,
        )

def field_or_arg_type_from_json(_json: Dict[str, Any]) -> 'TypeRef':
    typ = None

    if _json['kind'] not in [GraphQLKind.NON_NULL, GraphQLKind.LIST]:
        typ = TypeRef(
            name=_json['name'],
            kind=_json['kind'],
        )
    elif not _json['ofType']['ofType']:
        actual_type = _json['ofType']

        if _json['kind'] == GraphQLKind.NON_NULL:
            typ = TypeRef(
                name=actual_type['name'],
                kind=actual_type['kind'],
                non_null=True,
            )
        elif _json['kind'] == GraphQLKind.LIST:
            typ = TypeRef(
                name=actual_type['name'],
                kind=actual_type['kind'],
                is_list=True,
            )
        else:
            raise Exception(f'Unexpected type.kind: {_json["kind"]}')
    elif not _json['ofType']['ofType']['ofType']:
        actual_type = _json['ofType']['ofType']

        if _json['kind'] == GraphQLKind.NON_NULL:
            typ = TypeRef(
                actual_type['name'],
                actual_type['kind'],
                True,
                False,
                True,
            )
        elif _json['kind'] == GraphQLKind.LIST:
            typ = TypeRef(
                name=actual_type['name'],
                kind=actual_type['kind'],
                is_list=True,
                non_null_item=True,
            )
        else:
            raise Exception(f'Unexpected type.kind: {_json["kind"]}')
    elif not _json['ofType']['ofType']['ofType']['ofType']:
        actual_type = _json['ofType']['ofType']['ofType']
        typ = TypeRef(
            name=actual_type['name'],
            kind=actual_type['kind'],
            is_list=True,
            non_null_item=True,
            non_null=True,
        )
    else:
        raise Exception('Invalid field or arg (too many \'ofType\')')

    return typ

class Field:
    def __init__(
        self,
        name: str,
        typeref: Optional[TypeRef],
        args: List[InputValue] = None,
    ):
        if not typeref:
            raise Exception(f'Can\'t create {name} Field from {typeref} TypeRef.')

        self.name = name
        self.type = typeref
        self.args = args or []

    def to_json(self) -> dict:
        return {
            'args': [a.to_json() for a in self.args],
            'deprecationReason': None,
            'description': None,
            'isDeprecated': False,
            'name': self.name,
            'type': self.type.to_json(),
        }

    @classmethod
    def from_json(cls, _json: Dict[str, Any]) -> 'Field':
        name = _json['name']
        typ = field_or_arg_type_from_json(_json['type'])

        args = []
        for a in _json['args']:
            args.append(InputValue.from_json(a))

        return cls(name, typ, args)

class Type:
    def __init__(
        self,
        name: str = '',
        kind: str = '',
        fields: List[Field] = None,
    ):
        self.name = name
        self.kind = kind
        self.fields: List[Field] = fields or []

    def to_json(self) -> Dict[str, Any]:
        # dirty hack

        if not self.fields:
            field_typeref = TypeRef(
                name=GraphQLPrimitive.STRING,
                kind=GraphQLKind.SCALAR,
            )
            dummy = Field('dummy', field_typeref)
            self.fields.append(dummy)

        output: Dict[str, Any] = {
            'description': None,
            'enumValues': None,
            'interfaces': [],
            'kind': self.kind,
            'name': self.name,
            'possibleTypes': None,
        }

        if self.kind in [GraphQLKind.OBJECT, GraphQLKind.INTERFACE]:
            output['fields'] = [f.to_json() for f in self.fields]
            output['inputFields'] = None
        elif self.kind == GraphQLKind.INPUT_OBJECT:
            output['fields'] = None
            output['inputFields'] = [f.to_json() for f in self.fields]

        return output

    @classmethod
    def from_json(
        cls,
        _json: Dict[str, Any],
    ) -> 'Type':
        name = _json['name']
        kind = _json['kind']
        fields = []

        if kind in [GraphQLKind.OBJECT, GraphQLKind.INTERFACE, GraphQLKind.INPUT_OBJECT]:
            fields_field = ''
            if kind in [GraphQLKind.OBJECT, GraphQLKind.INTERFACE]:
                fields_field = 'fields'
            elif kind == GraphQLKind.INPUT_OBJECT:
                fields_field = 'inputFields'

            for f in _json[fields_field]:
                # Don't add dummy fields!
                if f['name'] == 'dummy':
                    continue
                fields.append(Field.from_json(f))

        return cls(
            name=name,
            kind=kind,
            fields=fields,
        )


import setuptools

with open("README.md") as fh:
    long_description = fh.read()

setuptools.setup(
    name="pysqueezebox",
    version="0.7.1",
    license="apache-2.0",
    author="Raj Laud",
    author_email="raj.laud@gmail.com",
    description="Asynchronous library to control Logitech Media Server",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/rajlaud/pysqueezebox",
    packages=setuptools.find_packages(),
    python_requires=">=3.6",
    install_requires=["aiohttp", "async-timeout"],
)


from __future__ import absolute_import, division, print_function, unicode_literals

import uuid
from contextlib import contextmanager

from pants.backend.codegen.thrift.java.java_thrift_library import JavaThriftLibrary
from pants.backend.codegen.thrift.java.thrift_defaults import ThriftDefaults
from pants.build_graph.target import Target
from pants_test.test_base import TestBase

class TestThriftDefaults(TestBase):
  def create_thrift_defaults(self, **options):
    self.context(for_subsystems=[ThriftDefaults], options={
      ThriftDefaults.options_scope: options
    })
    return ThriftDefaults.global_instance()

  @contextmanager
  def invalid_fixtures(self):
    target = self.make_target(spec='not_java_thift_library_{}'.format(uuid.uuid4()),
                              target_type=Target)
    thrift_defaults = self.create_thrift_defaults()
    with self.assertRaises(ValueError):
      yield thrift_defaults, target

  def test_compiler_invalid(self):
    with self.invalid_fixtures() as (thrift_defaults, target):
      thrift_defaults.compiler(target)

  def test_language_invalid(self):
    with self.invalid_fixtures() as (thrift_defaults, target):
      thrift_defaults.language(target)

  def create_thrift_library(self, **kwargs):
    return self.make_target(spec='java_thift_library_{}'.format(uuid.uuid4()),
                            target_type=JavaThriftLibrary,
                            **kwargs)

  def test_compiler(self):
    thrift_defaults = self.create_thrift_defaults(compiler='thrift')
    self.assertEqual('thrift', thrift_defaults.compiler(self.create_thrift_library()))
    self.assertEqual('scrooge',
                     thrift_defaults.compiler(self.create_thrift_library(compiler='scrooge')))

  def test_language(self):
    thrift_defaults = self.create_thrift_defaults(language='java')
    self.assertEqual('java', thrift_defaults.language(self.create_thrift_library()))
    self.assertEqual('scala',
                     thrift_defaults.language(self.create_thrift_library(language='scala')))


import os
import helper, wiredtiger, wttest
from wtscenario import make_scenarios

# test_prefetch01.py
#    Test basic functionality of the prefetch configuration.

class test_prefetch01(wttest.WiredTigerTestCase):
    new_dir = 'new.dir'

    conn_avail = [
        ('available', dict(available=True)),
        ('not-available', dict(available=False))
    ]

    conn_default = [
        ('default-off', dict(default=True)),
        ('default-on', dict(default=False)),
    ]

    session_cfg = [
        ('no-config', dict(scenario='no-config', enabled=False, has_config=False)),
        ('enabled', dict(scenario='enabled', enabled=True, has_config=True)),
        ('not-enabled', dict(scenario='not-enabled', enabled=False, has_config=True)),
    ]

    scenarios = make_scenarios(conn_avail, conn_default, session_cfg)

    def test_prefetch_config(self):
        conn_cfg = 'prefetch=(available=%s,default=%s)' % (str(self.available).lower(), str(self.default).lower())
        session_cfg = ''
        msg = '/pre-fetching cannot be enabled/'

        if self.has_config:
            session_cfg = 'prefetch=(enabled=%s)' % (str(self.enabled).lower())

        os.mkdir(self.new_dir)
        helper.copy_wiredtiger_home(self, '.', self.new_dir)

        if not self.available and self.default:
            # Test that we can't enable a connection's sessions to have pre-fetching when
            # pre-fetching is configured as unavailable.
            self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
                lambda: self.wiredtiger_open(self.new_dir, conn_cfg), msg)
        elif not self.available and self.enabled:
            # Test that we can't enable a specific session to have pre-fetching turned on
            # if pre-fetching is configured as unavailable.
            new_conn = self.wiredtiger_open(self.new_dir, conn_cfg)
            self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
                lambda: new_conn.open_session(session_cfg), msg)
        else:
            new_conn = self.wiredtiger_open(self.new_dir, conn_cfg)
            new_session = new_conn.open_session(session_cfg)
            self.assertEqual(new_session.close(), 0)

if __name__ == '__main__':
    wttest.run()


from django.http import HttpResponse
from django.shortcuts import render
from config import settings
#from email.message import EmailMessage

from django.core.mail import EmailMessage
# Create your views here.

def home(request):
    return render(request,"index.html")

def send_email(request):
    if request.method=='POST':
        name=request.POST['name']
        sender_email=request.POST['email']
        msg=request.POST['msg']
        phone=request.POST['phone']

        email=EmailMessage(
            f'Xabar qoldiruvchi: {sender_email}',
            f'Ismi: {name}\nXabari: {msg}\nTel raqami: {phone}',
            settings.EMAIL_HOST_USER,
            [sender_email]
        )
        email.fail_silently=True
        email.send()
        return HttpResponse("Muvaffaqiyatli jo'natildi")
    else:
        return HttpResponse("Jo'natilmadi")


from django.urls import path
from . import views

app_name = 'base'

urlpatterns = [
    path('home/', views.landing_page, name='home'),
    path('school_registered/', views.school_list_page, name='school_registered'),
    path('contact_us/', views.contact_us_page, name='contact_us'),

]


import pyriemann
import mne
from mne.io import read_raw_gdf
import scipy
from scipy import signal
from scipy.signal import butter, filtfilt, sosfiltfilt
import os

import pickle
import sklearn
import seaborn as sns
import matplotlib
import matplotlib as mpl
mpl.use('Qt5Agg') # for using pyplot (pip install pyqt5)

import matplotlib.pyplot as plt
import numpy as np

# Bandpass filtering
def butter_lowpass_filter(data, lowcut, fs, order):
    nyq = fs/2
    low = lowcut/nyq
    b, a = butter(order, low, btype='low')
    # demean before filtering
    meandat = np.mean(data, axis=1)
    data = data - meandat[:, np.newaxis]
    y = filtfilt(b, a, data) # zero-phase filter # data: [ch x time]
    return y

def butter_highpass_filter(data, highcut, fs, order):
    nyq = fs/2
    high = highcut/nyq
    b, a = butter(order, high, btype='high')
    # demean before filtering
    meandat = np.mean(data, axis=1)
    data = data - meandat[:, np.newaxis]
    y = filtfilt(b, a, data) # zero-phase filter # data: [ch x time]
    return y

def butter_bandpass_filter(data, lowcut, highcut, fs, order):
    nyq = fs/2
    low = lowcut/nyq
    high = highcut/nyq
    sos = butter(order, [low, high], btype='band', output='sos')
    # demean before filtering
    meandat = np.mean(data, axis=1)
    data = data - meandat[:, np.newaxis]
    y = sosfiltfilt(sos, data) # zero-phase filter # data: [ch x time]
    # specify pandlen to make the result the same as Matlab filtfilt()
    return y

# User parameters
# 769, 770, 774, 780 - left, right, up (tongue), down (feet)
#markers = [769, 770, 780, 774]
#markers_arr = {769:0, 770:1, 780:2, 774:3}
markers = [769, 770] # left, right
markers_arr = {769:1, 770:2}

# for g.tec EEG
nCh = 16
fs = 512
frame = [0.5, 3]
nTime = int((frame[1]-frame[0]) * 512)
#nTrial = 20
nClass = len(markers)
bp = [8, 30]

ch_names = ['FP1', 'FP2', 'F4', 'Fz', 'F3', 'T7', 'C3', 'Cz', 'C4', 'T8', 'P4', 'Pz', 'P3', 'O1', 'Oz', 'O2']
roi = ['F4', 'Fz', 'F3', 'C3', 'Cz', 'C4', 'P4', 'Pz', 'P3']
roi_id = np.zeros((len(roi)), dtype=np.int64)

for i in range(len(roi)):
  roi_id[i] = ch_names.index(roi[i]) # use roi_id

nSub = 3
train_EEG = np.array([]).reshape(0, nCh, nTime)
train_labels = []

for i in range(4):
    fname = './data/s%02d/MI_run%02d.gdf' % (nSub, (i+1))
    print(fname)

    eeg = read_raw_gdf(fname)
    ano_types = eeg.annotations.description.astype(int) # markers
    ano_latency = np.round(eeg.annotations.onset, 4)
    eeg_times = np.round(eeg.times, 4)
    dat = eeg.get_data() * 1000000
    ch_names = eeg.ch_names

    merge_EEG = np.array([]).reshape(nCh, nTime, 0)
    for cur_markers in markers:
        event_indicies = np.argwhere(ano_types == cur_markers)
        event_latencies = ano_latency[event_indicies]
        print('current marker is '+str(cur_markers))
        n_trial = 0
        epoched_EEG = np.array([]).reshape(nCh, nTime, 0)
        tmp_labels = markers_arr[cur_markers] * np.ones((len(event_latencies)))
        train_labels = np.append(train_labels, tmp_labels)

        for cur_latency in event_latencies:
            m_onset = np.where(eeg_times == cur_latency)[0][0]
            tmp_epoch = dat[:, m_onset + int(frame[0]*fs):m_onset + int(frame[1]*fs)]

            # epoch-level bandpass filtering
            tmp_epoch = butter_bandpass_filter(tmp_epoch, bp[0], bp[1], fs, 4)
            epoched_EEG = np.dstack((epoched_EEG, tmp_epoch))
            n_trial = n_trial + 1
        merge_EEG = np.dstack((merge_EEG, epoched_EEG))

    merge_EEG = np.transpose(merge_EEG, (2, 0, 1)) # now [trial x ch x time]
    train_EEG = np.vstack((train_EEG, merge_EEG))

cov_train = pyriemann.estimation.Covariances().fit_transform(train_EEG[:, roi_id, :])
print(cov_train.shape)
print(train_labels.shape)

mdm = pyriemann.classification.MDM()
mdm.metric = 'Riemann'
mdm.fit(cov_train, train_labels) # training

mdm_train_acc = np.sum(mdm.predict(cov_train) == train_labels) / len(train_labels) # train - meaningless
print('training accuracy is', np.round(mdm_train_acc,4))

trained = {'COV':cov_train, 'Labels':train_labels}
fname_user = input('Enter model name: ')
fname_model = './data/s%02d/%s.pkl' % (nSub, fname_user)
print(fname_model, 'saved.')
out_file = open(fname_model, 'wb')
pickle.dump(trained, out_file)
out_file.close()


#1st example

'''class Base:
    def Fun():
        print("Hello World")

class Derive(Base):
    def AnotherFun():
        print("Bye World")

obj=Derive()
obj.Fun()
obj.AnotherFun()'''

#2nd example
#-----------------------------------

class Bank:
    acno=0
    name=''
    branch=''
    balance=0.0
    def Input(self):
            acno=int(input("Enter Account Number"))
            name=input("Enter your name")
            branch=input("Enter your Branch Name")
            balance=float(input("Enter your Bank Balance"))

    def Output(self):
            print("Account Number : ", self.acno)
            print("Name : ", self.name)
            print("Branch : ", self.branch)
            print("Bank Balance : ", self.balance)

    def Fun(self):
            print("test")

class BankV1(Bank):
    aadhar=0

    def Input(self):        #Overriding
        Bank.Input(self)
        self.aadhar=input("Enter Aadhar Number : ")
    def Output(self):
        Bank.Output(self)   #Overriding
        print("Your Aadhar Number is : ", self.aadhar)

c=BankV1()
c.Input()
c.Output()


#!/usr/bin/env python3
import os
from sys import argv, exit
from pathlib import Path
import vertex_cover_lib as vcl

EXACT_LIMIT = 80

def main(num_vertices, num_edges, seed, weighted, approx, file_full_extension):
    # Automatic cast:
    num_vertices = int(num_vertices)
    num_edges = int(num_edges)
    seed = int(seed)
    weighted = int(weighted)
    approx = int(approx)
    # Generate graph instance
    instance = vcl.instances_generator(1, 1, num_vertices, num_edges, seed, weighted)[0]

    #if num_vertices <= EXACT_LIMIT:
    if not approx:
      if not weighted:
        size, sol = vcl.calculate_minimum_vc(instance['graph'])
      else:
        sol, size, weight = vcl.calculate_minimum_weight_vc(instance['graph'])
        instance['risp_weight'] = weight

      instance['exact_sol'] = True
      instance['risp'] = sol

    else:
      if not weighted:
        size, sol, max_matching = vcl.calculate_approx_vc(instance['graph'])
        instance['exact_sol'] = False
        instance['risp'] = f'{sol}\n{max_matching}'
        #instance['risp'] = max_matching
      else:
        sol, size, weight = vcl.calculate_weighted_approx_vc(instance['graph'])
        instance['exact_sol'] = False
        instance['risp'] = sol
        instance['risp_weight'] = weight

    # Generate selected output
    print(vcl.instance_to_str(instance, vcl.file_extension_to_format_name(file_full_extension)))

if __name__ == "__main__":
    from sys import argv
    #assert len(argv) == 5, 'Miss arguments'
    main(argv[1], argv[2], argv[3], argv[4], argv[5], argv[6])
    exit(0)


import matplotlib
matplotlib.use('TKAgg')

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from dateutil import parser

import numpy as np
import pandas as pd
import datetime

df_ferrara = pd.read_csv('WeatherData/ferrara_270615.csv')
df_milano = pd.read_csv('WeatherData/milano_270615.csv')
df_mantova = pd.read_csv('WeatherData/mantova_270615.csv')
df_ravenna = pd.read_csv('WeatherData/ravenna_270615.csv')
df_torino = pd.read_csv('WeatherData/torino_270615.csv')
df_asti = pd.read_csv('WeatherData/asti_270615.csv')
df_bologna = pd.read_csv('WeatherData/bologna_270615.csv')
df_piacenza = pd.read_csv('WeatherData/piacenza_270615.csv')
df_cesena = pd.read_csv('WeatherData/cesena_270615.csv')
df_faenza = pd.read_csv('WeatherData/faenza_270615.csv')

# dist 是一个装城市距离海边距离的列表
dist = [df_ravenna['dist'][0],
    df_cesena['dist'][0],
    df_faenza['dist'][0],
    df_ferrara['dist'][0],
    df_bologna['dist'][0],
    df_mantova['dist'][0],
    df_piacenza['dist'][0],
    df_milano['dist'][0],
    df_asti['dist'][0],
    df_torino['dist'][0]
]

# temp_max 是一个存放每个城市最高温度的列表
temp_max = [df_ravenna['temp'].max(),
    df_cesena['temp'].max(),
    df_faenza['temp'].max(),
    df_ferrara['temp'].max(),
    df_bologna['temp'].max(),
    df_mantova['temp'].max(),
    df_piacenza['temp'].max(),
    df_milano['temp'].max(),
    df_asti['temp'].max(),
    df_torino['temp'].max()
]

# temp_min 是一个存放每个城市最低温度的列表
temp_min = [df_ravenna['temp'].min(),
    df_cesena['temp'].min(),
    df_faenza['temp'].min(),
    df_ferrara['temp'].min(),
    df_bologna['temp'].min(),
    df_mantova['temp'].min(),
    df_piacenza['temp'].min(),
    df_milano['temp'].min(),
    df_asti['temp'].min(),
    df_torino['temp'].min()
]

# 调用 subplots() 函数，重新定义 fig, ax 变量
fig, ax = plt.subplots()
plt.xticks(rotation=70)

hours = mdates.DateFormatter('%H:%M')
ax.xaxis.set_major_formatter(hours)

# 先把最高温画出来。
fig, ax = plt.subplots()
ax.plot(dist,temp_max,'ro')

# 用线性回归算法得到两条直线，分别表示两种不同的气温趋势，这样做很有趣。我们可以使用scikit-learn库的SVR方法。

from sklearn.svm import SVR

# dist1是靠近海的城市集合，dist2是远离海洋的城市集合
dist1 = dist[0:5]
dist2 = dist[5:10]

# 改变列表的结构，dist1现在是5个列表的集合
# 之后我们会看到 numpy 中 reshape() 函数也有同样的作用
dist1 = [[x] for x in dist1]
dist2 = [[x] for x in dist2]

# temp_max1 是 dist1 中城市的对应最高温度
temp_max1 = temp_max[0:5]
# temp_max2 是 dist2 中城市的对应最高温度
temp_max2 = temp_max[5:10]

# 我们调用SVR函数，在参数中规定了使用线性的拟合函数
# 并且把 C 设为1000来尽量拟合数据（因为不需要精确预测不用担心过拟合）
svr_lin1 = SVR(kernel='linear', C=1e3)
svr_lin2 = SVR(kernel='linear', C=1e3)

# 加入数据，进行拟合（这一步可能会跑很久，大概10多分钟，休息一下:) ）
svr_lin1.fit(dist1, temp_max1)
svr_lin2.fit(dist2, temp_max2)

# 关于 reshape 函数请看代码后面的详细讨论
xp1 = np.arange(10,100,10).reshape((9,1))
xp2 = np.arange(50,400,50).reshape((7,1))
yp1 = svr_lin1.predict(xp1)
yp2 = svr_lin2.predict(xp2)

# ax = fig.add_subplot(122)

# 限制了 x 轴的取值范围
ax.set_xlim(0,400)

# 画出图像
ax.plot(xp1, yp1, c='b', label='Strong sea effect')
ax.plot(xp2, yp2, c='g', label='Light sea effect')

print(svr_lin1.coef_)  #斜率
print(svr_lin1.intercept_)  # 截距
print(svr_lin2.coef_)
print(svr_lin2.intercept_)

# 你可能会考虑将这两条直线的交点作为受海洋影响和不受海洋影响的区域的分界点，或者至少是海洋影响较弱的分界点。
from scipy.optimize import fsolve

# 定义了第一条拟合直线
def line1(x):
    a1 = svr_lin1.coef_[0][0]
    b1 = svr_lin1.intercept_[0]
    return a1*x + b1

# 定义了第二条拟合直线
def line2(x):
    a2 = svr_lin2.coef_[0][0]
    b2 = svr_lin2.intercept_[0]
    return a2*x + b2

# 定义了找到两条直线的交点的 x 坐标的函数
def findIntersection(fun1,fun2,x0):
    return fsolve(lambda x : fun1(x) - fun2(x),x0)

result = findIntersection(line1,line2,0.0)
print("[x,y] = [ %d , %d ]" % (result,line1(result)))

ax.plot(result, line1(result), 'ys')

fig.show()

气象数据分析/气象线性分析.py


from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation

from model_utils.models import TimeStampedModel

from files.mixins import UploadedFileMixin
from permissions.models import PermissionManagerMixin

from utils.models import CreatedByMixin
from utils.models.slug_field import AutoSlugCustomManagerField
from utils.descriptors import ChoicesDescriptorMixin

from ..managers.post import PostManager, AllPostManager
from ..conf import settings
from .mails.mails import PostEmailMixin
from .mixins import PostStatsMixin, PostPermissionsMixin, PostMetricMixin

class Post(
        PostPermissionsMixin,
        PostMetricMixin,
        PostStatsMixin,
        UploadedFileMixin,
        PermissionManagerMixin,
        CreatedByMixin,
        ChoicesDescriptorMixin,
        PostEmailMixin,
        TimeStampedModel):

    # Define here because of AutoSlugField
    objects = PostManager()
    all_objects = AllPostManager()

    title = models.CharField(max_length=255)
    description = models.TextField()

    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
        null=True,
    )
    object_id = models.PositiveIntegerField(null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    slug = AutoSlugCustomManagerField(
        populate_from='title',
        unique=True,
        null=True,
        blank=False,
    )
    tags = models.ManyToManyField('keywords.Keyword')
    _type = models.CharField(
        max_length=1,
        choices=settings.FORUM_POST_CH_TYPE)
    status = models.CharField(
        max_length=1,
        choices=settings.FORUM_CH_POST_STATUS,
        default=settings.FORUM_CH_POST_STATUS_DEFAULT)

    CHOICES_DESCRIPTOR_FIELDS = [
        '_type',
        'status',
    ]
    CHOICES_DESCRIPTOR_FIELDS_CHOICES = [
        settings.FORUM_POST_CH_TYPE,
        settings.FORUM_CH_POST_STATUS,
    ]

    logs = GenericRelation('PostAnswerStatus')
    files = GenericRelation('files.UploadedFile')

    objects = PostManager()
    all_objects = AllPostManager()
    slug_manager = AllPostManager()

    class Meta:
        verbose_name = 'Post'
        verbose_name_plural = 'Posts'
        ordering = ['-modified']
        base_manager_name = 'objects'
        permissions = settings.FORUM_PERMS_POST_ALL_PERMISSIONS

    def __str__(self):
        return self.title

    @property
    def category_name(self):
        category_name = ''
        if self.is_q_a_session:
            category_name = '{} - {} - {}'.format(
                self.get__type_display(),
                self.content_object.team.project,
                self.content_object.session.name,
            )
        elif self.content_object:
            category_name = self.content_object.name
        else:
            category_name = self.get__type_display()

        return category_name

    @property
    def circle(self):
        if self.is_circle:
            return self.content_object
        return None

    @property
    def qa_session(self):
        if self.is_q_a_session:
            return self.content_object.session
        return None

    @property
    def team(self):
        if self.is_project:
            return self.content_object
        elif self.is_q_a_session:
            return self.content_object.team
        return None

    @property
    def project(self):
        if self.team:
            return self.team.project
        return None

    @property
    def created_by_role(self):
        return self.created_by.user_title

    @property
    def url(self):
        if self.is_circle or self.is_project or self.is_announcement:
            if self.is_circle:
                circle = self.circle.slug
            elif self.is_project:
                circle = 'participant-questions'
            else:
                circle = 'announcements'
            return settings.FRONTEND_POST_DETAIL_PAGE.format(
                slug=self.slug,
                circle=circle)
        elif self.is_q_a_session:
            return settings.FRONTEND_JOBS_SWARM_SESSION_QUESTION_PAGE.format(
                **{
                    'pk_qa_session': self.content_object.session.pk,
                    'pk': self.pk
                })
        else:
            return ''

    @property
    def url_project(self):
        kwargs = {}
        if self.project is not None:
            kwargs = {
                'project_id': self.project.pk,
                'team_id': self.team.pk,
                'pk': self.pk,
            }
        if self.is_project:
            kwargs['section'] = 'ask-ecosystem'
        elif self.is_q_a_session:
            kwargs['section'] = 'swarm-session'
        else:
            kwargs = None
        if kwargs is not None:
            return settings.FRONTEND_PROJECT_QUESTION_PAGE.format(**kwargs)
        return ''

    def set_status(self, user_from, new_status):
        self.logs.create(
            user=user_from, status=self.status)
        self.status = new_status
        self.save(update_fields=['modified', 'status'])

    def mark_as_removed(self, user_from):
        self.can_update_or_remove(user_from)
        self.set_status(user_from, settings.FORUM_CH_REMOVED)
        self.action_removed(user_from)

    def reply(self, user_from, comment, timestamp=None, **kwargs):
        self.can_reply(user_from)
        answer = self.answers.create(
            comment=comment,
            created_by=user_from,
            reply_to=kwargs.get('reply_to'),
        )
        kwargs['target_object'] = answer
        if timestamp:
            self.answers.filter(pk=answer.pk).update(
                created=timestamp,
                modified=timestamp)
            Post.objects.filter(pk=self.pk).update(modified=timestamp)
        else:
            self.save(update_fields=['modified'])

        if kwargs.get('email_notification', True):
            self.send_email_reply(answer)

        answer.see(user_from)
        super().reply(user_from, comment, timestamp, **kwargs)
        return answer