from deepdoctection.datasets import DatasetCategories

class TestDatasetCategories:
    """
    Testing DatasetCategories
    """

    @staticmethod
    def setup() -> DatasetCategories:
        """
        Arrange testing setup
        """
        categories = ["FOO", "BAK", "BAZ"]
        sub_categories = {
            "BAK": {"sub": ["BAK_11", "BAK_12"], "sub_2": ["BAK_21", "BAK_22"]},
            "FOO": {"cat": ["FOO_1", "FOO_2", "FOO_3"]},
        }

        return DatasetCategories(init_categories=categories, init_sub_categories=sub_categories)

    @staticmethod
    def test_set_cat_to_subcat_and_check_categories() -> None:
        """
        Categories are dumped and annotation ids are correctly assigned and meth: is_cat_to_sub_cat works properly.
        """

        # Arrange
        cats = TestDatasetCategories.setup()

        # Assert
        assert cats.get_categories() == {"1": "FOO", "2": "BAK", "3": "BAZ"}
        assert not cats.is_cat_to_sub_cat()

        # Act
        cats.set_cat_to_sub_cat({"BAK": "sub_2"})

        # Assert
        assert cats.get_categories(as_dict=False, init=True) == ["FOO", "BAK", "BAZ"]
        assert cats.get_categories(as_dict=False) == ["FOO", "BAK_21", "BAK_22", "BAZ"]
        assert cats.is_cat_to_sub_cat()

        # Act
        cats.set_cat_to_sub_cat({"BAK": "sub", "FOO": "cat"})

        # Assert
        assert cats.get_categories(name_as_key=True) == {
            "FOO_1": "1",
            "FOO_2": "2",
            "FOO_3": "3",
            "BAK_11": "4",
            "BAK_12": "5",
            "BAZ": "6",
        }

    @staticmethod
    def test_filter_and_check_categories() -> None:
        """
        Categories are filtered and meth: is_filtered works properly
        """

        # Arrange
        cats = TestDatasetCategories.setup()

        # Assert
        assert not cats.is_filtered()

        # Act
        cats.set_cat_to_sub_cat({"BAK": "sub", "FOO": "cat"})
        cats.filter_categories(categories=["FOO_1", "BAZ", "BAK_11"])

        # Assert
        assert cats.get_categories(name_as_key=True, filtered=True) == {"FOO_1": "1", "BAZ": "3", "BAK_11": "2"}
        assert cats.is_filtered()

    @staticmethod
    def test_check_sub_categories() -> None:
        """
        get_sub_categories works as expected
        """

        # Arrange
        cats = TestDatasetCategories.setup()

        # Assert
        assert cats.get_sub_categories() == {"BAK": ["sub", "sub_2"], "FOO": ["cat"]}

    @staticmethod
    def test_set_sub_categories_and_check_sub_categories() -> None:
        """
        when categories are replaced with sub categories then get_sub_categories works as expected
        """

        # Arrange
        cats = TestDatasetCategories.setup()
        cats.set_cat_to_sub_cat({"FOO": "cat"})

        # Act
        assert cats.get_sub_categories(categories=["FOO_1", "FOO_2", "FOO_3"]) == {
            "FOO_1": [],
            "FOO_2": [],
            "FOO_3": [],
        }


import math
import torch
import torch.nn as nn
from torch.autograd import Variable

class Embeddings(nn.Module):
  def __init__(self, vocab_size, dim):
    super(Embeddings,self).__init__()
    self.emb = nn.Embedding(vocab_size,dim)
    self.dim = dim
  def forward(self, x):
    """
    1) 임베딩 값에 math.sqrt(self.d_model)을 곱해주는 이유는 무엇인지 찾아볼것
    2) nn.Embedding에 다시 한번 찾아볼것
    """
    return self.emb(x) * math.sqrt(self.dim)

class PositionalEmbedding(nn.Module):
  def __init__(self, dim, max_seq_len):
    super().__init__()
    self.embedding = nn.Embedding(max_seq_len, dim)

  def forward(self, x):
    t = torch.arange(x.shape[1], device=x.device)
    return self.embedding(t)

class PositionalEncoding(nn.Module):
  def __init__(self, max_seq_len, d_model,dropout=0.1):
    super(PositionalEncoding,self).__init__()
    self.dropout = nn.Dropout(p=dropout)

    pe = torch.zeros(max_seq_len, d_model)

    position = torch.arange(0,max_seq_len).unsqueeze(1)
    base = torch.ones(d_model//2).fill_(10000)
    pow_term = torch.arange(0, d_model, 2) / torch.tensor(d_model,dtype=torch.float32)
    div_term = torch.pow(base,pow_term)

    pe[:, 0::2] = torch.sin(position / div_term)
    pe[:, 1::2] = torch.cos(position / div_term)

    pe = pe.unsqueeze(0)

    # pe를 학습되지 않는 변수로 등록
    self.register_buffer('positional_encoding', pe)

  def forward(self, x):
    x = x + Variable(self.positional_encoding[:, :x.size(1)], requires_grad=False)
    return self.dropout(x)


'''
Given an array, rotate the array to the right by k steps, where k is non-negative.
'''

# reverse the first n - k elements -> [4,3,2,1,5,6,7]
# reverse the rest of them -> [4,3,2,1,7,6,5]
# reverse the entire array -> [5,6,7,1,2,3,4]

def rotateArray(nums, k):
  # basic check
  if not k or k <= 0:
    return

  # number of rotationssi just k % len(nums)
  k, end = k % len(nums), len(nums) - 1
  reverse(nums, 0, end - k)
  reverse(nums, end - k + 1, end)
  reverse(nums, 0, end)

def reverse(nums, start, end):
  while start < end:
    nums[start], nums[end] = nums[end], nums[start]
    start += 1
    end -= 1

nums=[1,2,3,4,5,6,7]
rotateArray(nums, k=3)
print(nums)


class Student:
    def __init__(self, name, grades, **kwargs):
        self.name = name
        self.grades = grades
        self.kwargs = kwargs

    def avereage_grade(self):
        return sum(self.grades) / len(self.grades)

student = Student("Bob", (50, 70, 43, 90), **{"corona": "virus", "flango": "flito"})
print(student.name)
print(student.grades)
print(student.avereage_grade())
print(student.kwargs)


"""
https://scipython.com/blog/simulating-two-dimensional-polycrystals/

"""

import io
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.patches import Circle
from matplotlib.patches import Polygon
import random

from .atom import Atom
from .grain import Grain
from .sim_cells import SimCells

# from atom import Atom
# from grain import Grain
# from sim_cells import SimCells

DEFAULT_DPI=100.0

def distance(p, q):
    """Return the Euclidean distance between points p and q."""
    return np.hypot(*(p-q))

class Crystal:
    """A simulation of a two-dimensional polycrystal."""

    def __init__(self, ngrains=5, seed_minimum_distance=0.2, lattice='hex',
                 atom_diameter=0.02, xsize=1000.0, ysize=1000.0):
        """Initialise the polycrystal.

        ngrains is the number of grains, to be placed randomly on the unit
        square with a minumum distance, seed_minimum_distance, between them.
        hex = 'hex' or 'square' is the crystalline lattice type and d is the
        atom diameter.

        """

        """
            Lattice - arranjo do modelo (hexagonal ou quadrangular)
            atom_diameter (d) eh o diametro de cada circulo que compoe o modelo
        """

        self.ngrains = ngrains
        self.seed_minimum_distance = seed_minimum_distance
        self.lattice = lattice
        self.atom_diameter = atom_diameter
        self.atoms, self.grains = [], []
        self.xsize = xsize
        self.ysize = ysize

        print("\n\nCrystal")
        print("ngrains: ", ngrains)
        print("seed_minimum_distance", seed_minimum_distance)
        print("lattice: " , lattice)
        print("diameter: " , atom_diameter)
        print("xsize: " , xsize)
        print("ysize: " , ysize)
        print()
        print()

    def seed_grains(self):

        """De acordo com o critério de validação de distancia minima entre os
        seeds (Origens) dos Grains, obtém o ponto de origem de cada um dos
        Grains e os instancia."""

        """Esta funcão foi ajustada em 11/12/2021 para quando só existir
        1 Grain aceitar diretamente o seed sugerido pelo ramdomize. Neste caso,
        não há necessidade do uso de seed_minimum_distance como critério de
        validação.
        """

        """Caso no futuro deseje-se utilizar esta função para multiplos Grains
        deve-se verificar a necessidade de ajustar o código, pois ocorre
        aceitação do seed proposto pelo randomize independente do critério de
        validação seed_minimum_distance.
        """

        # Reset the crystal.
        self.atoms, self.grains = [], []
#       self.sim_cells = SimCells(self.atom_diameter)

        self.sim_cells = SimCells(self.atom_diameter, self.xsize)

        if self.ngrains == 1:
            """ Fixando a coordenada de origem do Atom seed. """
            grain_origin_atom_coord = np.array([self.atom_diameter/2, self.atom_diameter/2])

            #"""
            grain_origin_atom_coord = np.random.random((2,))
            grain_origin_atom_coord[0] *= self.xsize
            grain_origin_atom_coord[1] *= self.ysize
            #"""

            # Initialise a grain and add its seed atom.
            grain = Grain(0, grain_origin_atom_coord, self.lattice)
            self.grains.append(grain)
            atom = Atom(grain, grain_origin_atom_coord)
            self.atoms.append(atom)
            self.sim_cells.add_atom_to_cell(atom)

        # else:
        #     for i in range(self.ngrains):
        #         print("\n\ni: ", i, len(self.atoms))
        #         while True:
        #             grain_origin_atom_coord = np.random.random((2,))
        #             for atom in self.atoms:

        #                 if distance(grain_origin_atom_coord, atom.coords) < self.seed_minimum_distance:
        #                     print(grain_origin_atom_coord, atom.coords,
        #                           distance(grain_origin_atom_coord, atom.coords),
        #                           self.seed_minimum_distance, len(self.atoms), "ACEITOU ATOM!\n")
        #                     # Seed atom too close to another: go back and try again
        #                     break
        #                 print(grain_origin_atom_coord, atom.coords,
        #                       distance(grain_origin_atom_coord, atom.coords),
        #                       self.seed_minimum_distance, len(self.atoms), "NÃO ACEITOU ATOM!")
        #             else:
        #                 print("VEIO PRA CÁ")
        #                 # Initialise a grain and add its seed atom.
        #                 grain = Grain(i, grain_origin_atom_coord, self.lattice)
        #                 self.grains.append(grain)
        #                 atom = Atom(grain, grain_origin_atom_coord)
        #                 self.atoms.append(atom)
        #                 self.sim_cells.add_atom_to_cell(atom)
        #                 break

    def grow_crystal(self):
        """Grow a new polycrystal."""

        print("\ngrow_crystal")

        self.seed_grains()

        # i_active is a list of the indices of atoms whcih have space next
        # to them to place a new atom.
        i_active = list(range(self.ngrains))

        while i_active:
            # Pick a random "active" atom, and get its neighbouring lattice
            # sites with enough space to place a new atom
            i = np.random.choice(i_active)

            candidate_sites = self.get_neighbour_candidate_sites(self.atoms[i])

            if not candidate_sites:
                # No candidate site was found: the atom is no longer active.
                i_active.remove(i)

                #raise Exception()
                print("len(i_active): ", len(i_active))
                print("len(candidate_sites): ", len(candidate_sites))

                #raise Exception()

                continue

            # Add the atom and mark it as active (until we know better).
            n = len(self.atoms)
            #print("Atom 002")
            atom = Atom(self.atoms[i].grain, random.choice(candidate_sites))
            self.atoms.append(atom)
            self.sim_cells.add_atom_to_cell(atom)
            i_active.append(n)

        print(len(self.atoms), 'atoms placed')

    def get_neighbour_candidate_sites(self, atom):
        """Return candidate locations next to atom to place a new atom.

        Look for sites on the crystal lattice of the grain of the provided
        atom with enough space to locate a new atom and return a list of
        the site coordinates.

        """

        print("\nget_neighbour_candidate_sites: ", atom.coords)

        neighbour_sites = atom.coords + (self.atom_diameter * atom.grain.lattice_disp)
        candidate_sites = []

        for site in neighbour_sites:

            #print("site: ", site)

            if not (0 <= site[0] < self.xsize and 0 <= site[1] < self.ysize):
                print("neighbour_site: ", site, " - RUIM")
                continue
            print("neighbour_site: ", site, " - OK")

            # neighbouring_atoms_generator spits out atoms in the
            # vicinity of site, using our array of "SimCells".
            neighbouring_atoms_generator = self.sim_cells.neighbouring_atoms_generator(site)

            #print(len(neighbouring_atoms_generator))

            #raise Exception("")

            for other_atom in neighbouring_atoms_generator:         # TODO: 0.99 ?????

#                print()
#                print(0.99)
#                print(self.atom_diameter)
#                print(self.atom_diameter * 0.99)
#                print("zzz site: ", site)
                # print("zzz coords: ", other_atom.coords)
#                print("zzz distance: ", distance(site, other_atom.coords))
                # print("zzz seed_minimum_distance: ", self.seed_minimum_distance)

                #if 1==1:
                if distance(site, other_atom.coords) < self.atom_diameter * 0.99:
                    print("BREAKOUUUUUUUUUUUUUUUUUU: ")
                    break
            else:
                candidate_sites.append(site)
        #raise Exception("")
        return candidate_sites

    def save_atom_positions(self, filename='crystal.out'):
        """Save the atom diameter and all atom locations to filename."""

        with open(filename, 'w') as fo:
            print('d =', self.atom_diameter, file=fo)
            for atom in self.atoms:
                print(atom.coords[0], atom.coords[1], file=fo)

    def _get_patch_vertices(self, atom):
        return atom.coords + self.atom_diameter * atom.grain.patch_disp

    def plot_crystal(self, circular_atoms=True, colours=None, **kwargs):
    # def plot_crystal(self, filename='crystal_007.png', circular_atoms=True,
    #                  colours=None, **kwargs):
        """Create a Matplotlib image of the polycrystal as filename.

        If colours is None, use a single colour for all atoms; otherwise
        a sequence of colours to cycle through for each grain can be
        provided. Additional kwargs are passed straight to the PatchCollection
        call that controls the drawing style of the atoms.
        If circular_atoms is not True, each atom is represented by the shape of
        its lattice (square or hexagon).

        """

        if not colours:
            # Atoms are boring grey if no alternative is provided.
            #colours = ['#444444']
            colours = ['#000000']
        ncolours = len(colours)

        if not kwargs:
            kwargs = {'linewidth': 1, 'edgecolor': 'k'}

        MULTIPLIER = 500
        DPI = DEFAULT_DPI * MULTIPLIER

        fig, ax = plt.subplots(figsize=[self.xsize/DPI, self.ysize/DPI],
                                                                      dpi=DPI)

        # We have a bit of book-keeping to do: group the atoms into their
        # grains in this dictionary, keyed by the grain_id.
        grains = {}
        for atom in self.atoms:
            grains.setdefault(atom.grain.grain_id, []).append(atom)

        for j, atoms in grains.items():
            #print("j: ", j)

            if circular_atoms:
                # center = atom.coords
                #print(atom.coords)
                #patches = [Circle(atom.coords, radius=self.atom_diameter/2) for atom in atoms]
                patches = []
                for atom in atoms:
#                    print("atom.coords: ", atom.coords)
                    patches.append(Circle(atom.coords, radius=self.atom_diameter/2) )
            else:
                patches = [Polygon(self._get_patch_vertices(atom)) for atom in atoms]

            c = PatchCollection(patches, facecolor=colours[j % ncolours],
                                **kwargs)
            ax.add_collection(c)

        # Ensure the Axes are square and remove the spines, ticks, etc.

        ax.set_xlim((0.0, self.xsize))
        ax.set_ylim((0.0, self.ysize))

        #ax.set_aspect('equal', 'box')

        rect = [0.0, 0.0, 1.0, 1.0]
        ax.set_position(rect)
        plt.axis('off')

        # plt.savefig(filename)
        # plt.show()

        # From: https://stackoverflow.com/questions/7821518/matplotlib-save-plot-to-numpy-array
        io_buf = io.BytesIO()
        fig.savefig(io_buf, format='raw', dpi=DPI)
        io_buf.seek(0)
        img_arr = np.reshape(np.frombuffer(io_buf.getvalue(), dtype=np.uint8),
                     newshape=(int(fig.bbox.bounds[3]), int(fig.bbox.bounds[2]), -1))

        io_buf.close()

        return img_arr

# Lattice - arranjo
# ngrains = ngrains=5, seed_minimum_distance=0.2, lattice='hex',              atom_diameter=0.02

# crystal = Crystal(ngrains=1,
#                     seed_minimum_distance=0.01,
#                     lattice='hex',
#                     #lattice = 'square',
#                     atom_diameter=10,
#                     xsize=50,
#                     ysize=50)

# crystal = Crystal(ngrains=1,
#                     #lattice='hex',
#                     lattice = 'square',
#                     atom_diameter=0.1,
#                     xsize=1.0,
#                     ysize=1.0)

# number = 16

# #lattice = 'square'
# lattice='hex'

# crystal = Crystal(ngrains=1,
#                   lattice = lattice,
#                   atom_diameter=0.00296,
#                   xsize=256*0.000296,
#                   ysize=256*0.000296)

# crystal.grow_crystal()
# crystal.plot_crystal(linewidth=0, filename="crystal_" + str(number) + "_" + lattice + ".png")


from sklearn.model_selection import train_test_split
from fake2vec.utils.text_processor import WordsContainer
from fake2vec.utils.train_doc2vec import load_data
from fake2vec.utils.model import doc2vec, KerasClassifier

import numpy as np
import pandas as pd
import sys, re, os, argparse, pickle, functools, collections, warnings

from gensim.models.doc2vec import TaggedDocument

import keras
from keras.utils import np_utils
from keras.regularizers import l1, l2
from keras.optimizers import SGD, Adam
from keras.callbacks import Callback, ModelCheckpoint, CSVLogger, EarlyStopping
from keras.callbacks import ReduceLROnPlateau, LearningRateScheduler

from sklearn.utils import class_weight
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import classification_report, accuracy_score
from sklearn import utils

warnings.filterwarnings("ignore", category=FutureWarning)

top3_acc = functools.partial(keras.metrics.top_k_categorical_accuracy, k=3)
top3_acc.__name__ = 'top3_acc'
top5_acc = functools.partial(keras.metrics.top_k_categorical_accuracy, k=5)
top5_acc.__name__ = 'top5_acc'
top10_acc = functools.partial(keras.metrics.top_k_categorical_accuracy, k=10)
top10_acc.__name__ = 'top10_acc'

def CountFrequency(arr):
    return collections.Counter(arr)

def get_callbacks(WEIGHTS_FPATH, LOG_FPATH, monitor):
    callbacks = [
        ModelCheckpoint(
            WEIGHTS_FPATH, monitor=monitor, save_best_only=True, mode='auto'),
        EarlyStopping(monitor=monitor, patience=5),
        ReduceLROnPlateau(
            monitor=monitor, factor=0.2, patience=2, min_lr=1e-8, mode='auto'),
        CSVLogger(LOG_FPATH, separator=' ', append=True),
    ]
    return callbacks

def class_weight_dict(labels_dict, mu=0.15):
    # labels_dict : {ind_label: count_label}
    # mu : parameter to tune
    total = np.sum(list(labels_dict.values()))
    keys = list(labels_dict.keys())
    class_weight = dict()
    for key in keys:
        score = np.log(mu * total / float(labels_dict[key]))
        class_weight[key] = score if score > 1.0 else 1.0
    return class_weight

def class_report(X, y, model, outfile="class_report"):
    output_labels = {0: 'publisher', 1: 'fact', 2: 'bias'}
    y_pred = model.predict(X)
    for k, (_y, _y_pred) in enumerate(zip(y, y_pred)):
        report = classification_report(_y, _y_pred.round(), output_dict=True)
        report = pd.DataFrame(report).transpose()
        report.to_csv(outfile + ".{}.csv".format(output_labels[k]))

def load_cached_vectors(df,
                        model,
                        label_index,
                        encoders,
                        min_words=10,
                        num_classes=938,
                        cache_loc=None,
                        fit_encoder=False,
                        infer_steps=None,
                        infer_alpha=None,
                        reinfer_train=True):

    # If vectors already saved, load them --> infer step is slow.
    if os.path.isfile(cache_loc):
        with open(cache_loc, "rb") as fid:
            X, y1, y2, y3 = pickle.load(fid)
    else:
        # Tag the docs
        tagged = df.apply(
            lambda r: TaggedDocument(
                words=r['docu_text'],
                tags=[r.publisher, r.fact_score, r.bias_score]),
            axis=1)

        # Load the document vectors (using publisher label)
        X, y1, y2, y3 = model.doc_vectors(
            tagged,
            min_words=min_words,
            label_index=label_index,
            infer_steps=infer_steps,
            infer_alpha=infer_alpha,
            reinfer_train=reinfer_train)

        y1 = encoders[0].transform(y1)
        y2 = encoders[1].transform(y2)
        y3 = encoders[2].transform(y3)

        y1 = np_utils.to_categorical(y1, num_classes=num_classes)
        y2 = np_utils.to_categorical(y2, num_classes=3)
        y3 = np_utils.to_categorical(y3, num_classes=7)

        with open(cache_loc, "wb") as fid:
            pickle.dump([X, y1, y2, y3], fid)

    return X, y1, y2, y3

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--nb_epoch',
        type=int,
        default=100,
        help='Number of epochs to train for, default 100')
    parser.add_argument(
        '--batch_size', type=int, default=16, help='Batch size, default 16')
    parser.add_argument(
        '--hidden_dim',
        type=int,
        default=1000,
        help='Batch size, default 1000')
    parser.add_argument(
        '--min_doc_size',
        type=int,
        default=10,
        help='Minimum length of title, default 10')
    parser.add_argument(
        '--label_index',
        type=int,
        default=0,
        help='0: publishers, 1: fact, 2: bias. Default: 0')
    parser.add_argument(
        '--retrain',
        type=bool,
        default=False,
        help='Retrain with loaded weights, default False')
    parser.add_argument(
        '--l1',
        type=float,
        default=0,
        help='l1 regularization parameter for each Dense layer, default 0')
    parser.add_argument(
        '--l2',
        type=float,
        default=0,
        help='l2 regularization parameter for each Dense layer, default 0')
    parser.add_argument(
        '--lr', type=float, default=0.001, help='Learning rate, default 1e-3')
    parser.add_argument(
        '--docvec_size',
        type=int,
        default=1000,
        help='Document vector size, default 1000')
    parser.add_argument(
        '--infer_steps',
        type=int,
        default=20,
        help='Infer steps for document vectors, default 20')
    parser.add_argument(
        '--save_loc', type=str, default='./', help='Save output to dir')
    args = parser.parse_args()

    N_epochs = int(args.nb_epoch)
    batch_size = int(args.batch_size)
    hidden_dim = int(args.hidden_dim)
    vec_size = int(args.docvec_size)
    infer_steps = int(args.infer_steps)
    label_index = int(args.label_index)
    min_doc_size = int(args.min_doc_size)
    data_save_dir = str(args.save_loc)
    lr = float(args.lr)

    # Load doc2vec csv / pkl preprocessed data, used to get vectors
    joined_dir = os.path.join(data_save_dir, 'data')
    if not os.path.isdir(joined_dir):
        os.makedirs(joined_dir)
    doc2vec_training_csv = '{}/Doc2vecTrainingData.csv'.format(joined_dir)
    doc2vec_preprocessed = '{}/Doc2vecTrainingDataProcessed.pkl'.format(
        joined_dir)
    label_encoders = "{}/label_encoders.pkl".format(joined_dir)
    PLOT_DATA_LOC = "{}/plot_data.pkl".format(joined_dir)
    df = load_data(
        doc2vec_training_csv=doc2vec_training_csv,
        doc2vec_preprocessed=doc2vec_preprocessed)

    # Misc. filepaths for training and results data
    joined_dir = os.path.join(data_save_dir, 'models')
    if not os.path.isdir(joined_dir):
        os.makedirs(data_dir)
        os.makedirs(data_dir + '/doc2vec')
        os.makedirs(data_dir + '/classifier')

    DOC2VEC_MODEL = "{}/doc2vec/doc2vec-VecSize-{}_MinDoc-{}_Window-300.model".format(
        joined_dir, vec_size, min_doc_size)
    CACHE_VECTOR_LOC = "{}/doc2vec/cached_vectors_bulk.pkl".format(joined_dir)
    LOG_FPATH = '{}/classifier/classifier_training.txt'.format(joined_dir)
    WEIGHTS_FPATH = "{}/classifier/model.h5".format(joined_dir)

    # Load label encoders
    with open(label_encoders, "rb") as fid:
        encoders, classes_counter = pickle.load(fid)
        N_pubs, N_fact, N_bias = classes_counter

    # Load trained doc2vec model
    model = doc2vec(DOC2VEC_MODEL)

    # Number of unique labels
    N_vocab = len(model.model.wv.vocab)

    print("Training classifier to predict publishers given words")
    print("... loading doc2vec model")
    print("... length of vocabulary:", N_vocab)
    print("... number of pub labels:", N_pubs)
    print("... number of fact labels:", N_fact)
    print("... number of bias labels:", N_bias)

    # Get mapping from publisher to id
    X, y1, y2, y3 = load_cached_vectors(
        df,
        model,
        label_index,
        encoders,
        min_words=min_doc_size,
        num_classes=N_pubs,
        infer_steps=infer_steps,
        cache_loc=CACHE_VECTOR_LOC)

    # Set up class-imbalance weights using scheme
    freq1 = CountFrequency(np.argmax(y1, axis=1))
    freq2 = CountFrequency(np.argmax(y2, axis=1))
    freq3 = CountFrequency(np.argmax(y3, axis=1))
    class_weights = {
        'pub': class_weight_dict(freq1, mu=0.2),
        'fact': class_weight_dict(freq2, mu=0.2),
        'bias': class_weight_dict(freq3, mu=0.2)
    }

    # Split data (default set to be 70/30, ignoring 30 --> 15-15 plot)
    print("... loading training data")
    y_train = []
    y_test = []
    for y in [y1, y2, y3]:
        X_train, X_test, y_tr, y_te = train_test_split(
            X, y, test_size=0.3, random_state=42)
        y_train.append(y_tr)
        y_test.append(y_te)

    ###########################################################

    print("... fitting the classifier model")

    # Load neural classifier model
    classifier = KerasClassifier(vec_size, N_pubs).model()
    classifier.summary()

    # Load callbacks, optimizer, loss details
    callbacks = get_callbacks(WEIGHTS_FPATH, LOG_FPATH, "val_fact_loss")

    # Use adam optimer, clip
    adam = Adam(lr=lr, clipnorm=1.0)

    # Multi-head loss. Keras adds by default
    losses = {
        "pub": 'categorical_crossentropy',
        "fact": 'categorical_crossentropy',
        "bias": 'categorical_crossentropy'
    }

    lossWeights = {
        "pub": 1.0,
        "fact": np.log(N_pubs / 3),
        "bias": np.log(N_pubs / 7)
    }

    metrics = ['accuracy']  #, top3_acc, top5_acc, top10_acc]
    classifier.compile(
        loss=losses, loss_weights=lossWeights, optimizer=adam, metrics=metrics)

    # Train the model
    estimator = classifier.fit(
        X_train,
        y_train,
        validation_data=(X_test, y_test),
        epochs=N_epochs,
        callbacks=callbacks,
        shuffle=True,
        batch_size=batch_size,
        verbose=2,
        class_weight=class_weights,
    )

    print("... publisher: train accuracy: %.2f%% / val accuracy: %.2f%%" %
          (100 * estimator.history['pub_acc'][-1],
           100 * estimator.history['val_pub_acc'][-1]))
    print("... factual: train accuracy: %.2f%% / val accuracy: %.2f%%" %
          (100 * estimator.history['fact_acc'][-1],
           100 * estimator.history['val_fact_acc'][-1]))
    print("... bias: train accuracy: %.2f%% / val accuracy: %.2f%%" %
          (100 * estimator.history['bias_acc'][-1],
           100 * estimator.history['val_bias_acc'][-1]))

    # Breakdown of class accuracies, etc.
    #joined_dir = os.path.join(data_save_dir,'results')
    #if not os.path.isdir(joined_dir):
    #    os.makedirs(joined_dir)
    class_report(
        X_train,
        y_train,
        classifier,
        outfile=os.path.join(joined_dir, "classifier/class_report_train"))
    class_report(
        X_test,
        y_test,
        classifier,
        outfile=os.path.join(joined_dir, "classifier/class_report"))

    # Save model weights to h5
    classifier.save_weights(WEIGHTS_FPATH, overwrite=True)

    # Save model + weights to pkl for faster loading with app
    with open(WEIGHTS_FPATH + '.pkl', "wb") as fid:
        pickle.dump(classifier, fid)

    # Save results for making plots, reports, etc.
    with open(PLOT_DATA_LOC, "wb") as fid:
        pickle.dump([estimator, X_train, y_train, X_test, y_test], fid)


from torch.utils.data import Dataset
from PIL import Image
import os

'''
来自b站up主：我是土堆
b站视频：https://www.bilibili.com/video/BV1hE411t7RN?p=7

数据集：
链接：https://pan.baidu.com/s/1R5mBwBo-AGydrwZX0EDbCA
提取码：tkrp

PyTorch是一个开源的Python机器学习库
'''

class MyData(Dataset):

    def __init__(self, root_dir, label_dir):
        self.root_dir = root_dir
        self.label_dir = label_dir
        self.path = os.path.join(self.root_dir, self.label_dir)  # 拼起来就是图片文件夹的路径
        self.image_path = os.listdir(self.path)  # 图片文件夹下所有图片路径的列表

    def __getitem__(self, index):
        image_name = self.image_path[index]
        image_item_path = os.path.join(self.root_dir, self.label_dir, image_name)
        img = Image.open(image_item_path)
        label = self.label_dir
        return img, label

    def __len__(self):
        return len(self.image_path)

def main():
    root_dir = "E:\\code\\python_study\\dataset\\train"
    ants_label_dir = "ants_image"
    bees_label_dir = "bees_image"
    ants_dataset = MyData(root_dir, ants_label_dir)
    bees_dataset = MyData(root_dir, bees_label_dir)
    train_dataset = ants_dataset + bees_dataset
    print("蚂蚁数据集长度%d 蜜蜂数据集长度%d train_dataset长度%d" % (len(ants_dataset), len(bees_dataset),len(train_dataset)))
    img, label = train_dataset[124]  # 重写了__getitem__方法，通过[]取值时返回的是img,label
    img.show()

if __name__ == '__main__':
    main()


class Solution:
    def findOcurrences(self, text: str, first: str, second: str) -> List[str]:
        text = text.split()
        start = 0
        ans = []
        cf = text.count(first)
        l = len(text)
        for i in range(cf):
            cur = text.index(first, start)
            if cur + 2 < l and text[cur +1 ] == second:
                ans.append(text[cur+2])
            start = cur + 1
        return ans


l_size = 20000

def fraction(denom):
    f_digits = []
    base = 10
    for i in range(l_size):
        while base < denom:
            base *= 10
        f_digits.append(str(int(base / denom)))
        base -= denom * (base // denom)
        if base == 0:
            break
    return f_digits

def find_occurences(l_digits):
    super_key = ('', 0)
    if len(l_digits) < l_size:
        return super_key

    number = ''.join(l_digits)

    for length in range(3, l_size // 10):
        for offset in range(l_size // 10):
            key = ''.join(l_digits[offset:offset + length])

            if len(key) % 2 == 0 and key[:len(key) // 2] == key[-len(key) // 2:]:
                return key[:len(key) // 2], len(key) // 2

            if number.find(key, offset + 1) > 0:
                super_key = key, len(key)
                break
    return super_key

def solve():
    max_k, max_v = 0, 0
    for i in range(2, 1001):
        temp_k, temp_v = find_occurences(fraction(i))
        if temp_v > max_v:
            max_v = temp_v
            max_k = i
    return max_k


from django.urls import path, include, path
from rest_framework import routers

from . import views

router = routers.DefaultRouter()

router.register('category', views.CategoryView)
router.register('subscription', views.SubscriptionView)
router.register('history', views.HistoryView)

urlpatterns = [
    path('', include(router.urls))
]


import os
import json
import ipaddress

from datetime import datetime, timedelta
from dateutil import parser
from threading import Lock

from bluecat import util
from bluecat.util import safe_str
from bluecat.entity import Entity
from bluecat.api_exception import BAMException, PortalException

from sonar.sonarapi import SonarAPI
from dnsedge.edgeapi import EdgeAPI

#
# Should be in API
#
def denyMACAddress(configuration, macaddr):
    try:
        configuration._api_client.service.denyMACAddress(configuration.get_id(), macaddr)
    except WebFault as e:
        print('Exception at denyMACAddress(%s)' % util.safe_str(e))
        raise BAMException(safe_str(e))

class IsolatorWithSonarException(Exception): pass

class IsolatorWithSonar(object):
    _unique_instance = None
    _lock = Lock()
    _config_file = os.path.dirname(os.path.abspath(__file__)) + '/config.json'

    @classmethod
    def __internal_new__(cls):
        return super().__new__(cls)

    @classmethod
    def get_instance(cls, debug=False):
        if cls._unique_instance is None:
            with cls._lock:
                if cls._unique_instance is None:
                    cls._unique_instance = cls.__internal_new__()
                    cls._unique_instance._debug = debug
                    cls._unique_instance._nodes = []
                    cls._unique_instance._load()
        return cls._unique_instance

    def _load(self):
        with open(IsolatorWithSonar._config_file) as f:
            self._config = json.load(f)

    def get_value(self, key):
        value = None
        with IsolatorWithSonar._lock:
            if key in self._config.keys():
                value = self._config[key]
        return value

    def set_value(self, key, value):
        with IsolatorWithSonar._lock:
            self._config[key] = value

    def get_nodes(self):
        nodes = []
        with IsolatorWithSonar._lock:
            nodes = self._nodes
        return nodes

    def set_nodes(self, nodes):
        with IsolatorWithSonar._lock:
            self._nodes = nodes

    def clear_nodes(self):
        with IsolatorWithSonar._lock:
            self._nodes = []

    def save(self):
        with IsolatorWithSonar._lock:
            with open(IsolatorWithSonar._config_file, 'w') as f:
                json.dump(self._config, f, indent=4)

    def _get_assignable_name(self, node):
        assignalbe_name = ''
        try:
            ipaddress.IPv4Address(node['name'])
        except ipaddress.AddressValueError:
            assignalbe_name = node['name']
        return assignalbe_name

    def _construct_sonar_url(self, sonar_api, node):
        return sonar_api.get_node_detail_url(node['network_id'], node['id'])

    def _construct_linked_name(self, sonar_api, node):
        return "%s" % \
            (self._construct_sonar_url(sonar_api, node), node['name'])

    def _collect_nodes(self, configuration, sonar_api, network_id):
        nodes = []
        now = datetime.now()
        sonar_nodes = sonar_api.get_nodes(network_id)

        for sn in sonar_nodes:
            for ad in sn['addresses']:
                node = {}
                node['id'] = sn['managedNodeId']
                node['network_id'] = network_id
                node['order'] = util.ip42int(ad['addr'])
                node['name'] = sn['displayName']
                node['system'] = sn['system']['family']

                if node['system'] == '':
                    try:
                        node['system'] = ad['extraFields']['macaddr']['organizationName']
                    except:
                        pass

                node['ipaddr'] = ad['addr']
                node['macaddr'] = ad['macaddr'].upper().replace(':', '-')
                node['detail_link'] = self._construct_sonar_url(sonar_api, node)
                node['linked_name'] = self._construct_linked_name(sonar_api, node)

                node['last_found'] = sn['lastScanSucceededAt']
                lastfound = parser.parse(sn['lastScanSucceededAt'])
                lastfound = lastfound.replace(tzinfo=None)
                if (now - lastfound) < timedelta(days=30):
                    node['state'] = 'UNKNOWN'
                    nodes.append(node)
        nodes.sort(key = lambda node: node['order'])

        return nodes

    def _collect_ip4_networks(self, configuration, ip4_networks, ipaddr):
        pack_address = util.ip42int(ipaddr)
        for ip4_network in ip4_networks:
            cidr = ip4_network.get_property('CIDR')
            network = ipaddress.IPv4Network(cidr)
            start_address = util.ip42int(str(network.network_address))
            end_address = util.ip42int(str(network.broadcast_address))
            if start_address <= pack_address <= end_address:
                return

        try:
            found = configuration.get_ip_range_by_ip(Entity.IP4Network, ipaddr)
            if found is not None:
                ip4_networks.append(found)

        except PortalException as e:
            print(safe_str(e))

    def _compare_nodes(self, configuration, nodes):
        ip4_networks = []
        include_matches = self.get_value('include_matches')

        for node in nodes:
            self._collect_ip4_networks(configuration, ip4_networks, node['ipaddr'])

        for ip4_network in ip4_networks:
            ip4_addresses = ip4_network.get_children_of_type(Entity.IP4Address)
            for ip4_address in ip4_addresses:
                founds = [node for node in nodes if node['ipaddr'] == ip4_address.get_address()]
                if 0 < len(founds):
                    macaddress = ip4_address.get_property('macAddress')
                    found = founds[0]
                    if found['macaddr'] != macaddress:
                        found['state'] = 'MISMATCH'
                    else:
                        try:
                            mac_address = configuration.get_mac_address(macaddress)
                            source = mac_address.get_property('ImportedSource')
                            if source is not None and source != '':
                                found['state'] = 'MATCH'
                        except PortalException as e:
                            pass
                    if include_matches == False and found['state'] == 'MATCH':
                        nodes.remove(found)

        nodes.sort(key = lambda node: node['order'])

    def _update_mac_by_node(self, configuration, node):
        mac_address = None
        assignalbe_name = self._get_assignable_name(node)
        try:
            mac_address = configuration.get_mac_address(node['macaddr'])
            if mac_address.get_name() is None and assignalbe_name != '':
                mac_address.set_name(assignalbe_name)
        except PortalException as e:
            mac_address = configuration.add_mac_address(node['macaddr'], assignalbe_name)

        mac_address.set_property('DetailLink', node['detail_link'])
        mac_address.set_property('System', node['system'])
        mac_address.set_property('ImportedSource', 'Sonar')
        mac_address.update()

    def _assigne_by_node(self, configuration, node):
        try:
            iprange = configuration.get_ip_range_by_ip('DHCP4Range', node['ipaddr'])
        except PortalException as e:
            properties='name=' + self._get_assignable_name(node)
            ipaddress = \
                configuration.assign_ip4_address(node['ipaddr'], \
                    node['macaddr'], '', 'MAKE_STATIC', properties=properties)
        self._update_mac_by_node(configuration, node)

    def _update_by_node(self, configuration, node):
        try:
            ipaddress = configuration.get_ip4_address(node['ipaddr'])
            assignalbe_name = self._get_assignable_name(node)
            if ipaddress.get_name() is None and assignalbe_name != '':
                ipaddress.set_name(assignalbe_name)
            ipaddress.set_property('macAddress', node['macaddr'])
            ipaddress.update()
        except PortalException as e:
            if self._debug:
                print('DEBUG: Exceptin <%s>' % safe_str(e))

        self._update_mac_by_node(configuration, node)

    def _free_by_node(self, configuration, node):
        try:
            iprange = configuration.get_ip_range_by_ip('DHCP4Range', node['ipaddr'])
        except PortalException as e:
            try:
                ipaddress = configuration.get_ip4_address(node['ipaddr'])
                ipaddress.delete()
            except PortalException as e:
                if self._debug:
                    print('DEBUG: Exceptin <%s>' % safe_str(e))

    def collect_nodes(self, configuration):
        succeed = False
        try:
            sonar_api = SonarAPI(self.get_value('kompira_url'), self.get_value('api_token'), debug=True)
            if not sonar_api.validate_api_key():
                return succeed

            network = sonar_api.get_network_by_name(self.get_value('network_name'))
            if (network is not None) and (network['networkId'] != ''):
                nodes = self._collect_nodes(configuration, sonar_api, network['networkId'])
                self._compare_nodes(configuration, nodes)
                self.set_nodes(nodes)

        except Exception as e:
            if self._debug:
                print('DEBUG: Exceptin <%s>' % str(e))
        return succeed

    def isolate_nodes(self, configuration):
        succeed = False
        target_ips = []

        for node in self.get_nodes():
            denyMACAddress(configuration, node['macaddr'])
            target_ips.append(node['ipaddr'])

        try:
            edge_api = EdgeAPI(self.get_value('edge_url'), debug=True)
            if not edge_api.validate_edgeurl():
                return succeed

            if not edge_api.login(self.get_value('edge_client_id'), self.get_value('edge_secret')):
                return succeed

            policy = edge_api.get_policy_by_name(self.get_value('edge_policy_name'))
            if policy is None:
                return succeed

            id = policy.pop('id')
            del policy['timestamp']
            del policy['policyVersionId']

            policy['sourceIps']['ranges'].extend(target_ips)
            succeed = edge_api.update_policy(id, policy)

        except Exception as e:
            if self._debug:
                print('DEBUG: Exceptin <%s>' % str(e))

        self.clear_nodes()
        return succeed


from enum import Enum
from typing import Callable, Optional, Union

from storey import Flow
from storey.dtypes import Event, _termination_obj

class EmitPeriod(Enum):
    FIRST = 1
    LAST = 2

class SampleWindow(Flow):
    """
    Emits a single event in a window of `window_size` events, in accordance with `emit_period` and
    `emit_before_termination`.

    :param window_size: The size of the window we want to sample a single event from.
    :param emit_period: What event should this step emit for each `window_size` (default: EmitPeriod.First).
        Available options:
        1.1) EmitPeriod.FIRST - will emit the first event in a window `window_size` events.
        1.2) EmitPeriod.LAST - will emit the last event in a window of `window_size` events.
    :param emit_before_termination: On termination signal, should the step emit the last event it seen (default: False).
        Available options:
        2.1) True - The last event seen will be emitted downstream.
        2.2) False - The last event seen will NOT be emitted downstream.
    :param key: The key by which events are sampled. By default (None), events are not sampled by key.
        Other options may be:
        Set to '$key' to sample events by the Event.key property.
        set to 'str' key to sample events by Event.body[str].
        set a Callable[[Event], str] to sample events by a custom key extractor.
    """

    def __init__(
        self,
        window_size: int,
        emit_period: EmitPeriod = EmitPeriod.FIRST,
        emit_before_termination: bool = False,
        key: Optional[Union[str, Callable[[Event], str]]] = None,
        **kwargs,
    ):
        kwargs["full_event"] = True
        super().__init__(**kwargs)

        if window_size <= 1:
            raise ValueError(f"Expected window_size > 1, found {window_size}")

        if not isinstance(emit_period, EmitPeriod):
            raise ValueError(f"Expected emit_period of type `EmitPeriod`, got {type(emit_period)}")

        self._window_size = window_size
        self._emit_period = emit_period
        self._emit_before_termination = emit_before_termination
        self._per_key_count = dict()
        self._count = 0
        self._last_event = None
        self._extract_key: Callable[[Event], str] = self._create_key_extractor(key)

    @staticmethod
    def _create_key_extractor(key) -> Callable:
        if key is None:
            return lambda event: None
        elif callable(key):
            return key
        elif isinstance(key, str):
            if key == "$key":
                return lambda event: event.key
            else:
                return lambda event: event.body[key]
        else:
            raise ValueError(f"Unsupported key type {type(key)}")

    async def _do(self, event):
        if event is _termination_obj:
            if self._last_event is not None:
                await self._do_downstream(self._last_event)
            return await self._do_downstream(_termination_obj)
        else:
            key = self._extract_key(event)

            if key is not None:
                if key not in self._per_key_count:
                    self._per_key_count[key] = 1
                else:
                    self._per_key_count[key] += 1
                count = self._per_key_count[key]
            else:
                self._count += 1
                count = self._count

            if self._emit_before_termination:
                self._last_event = event

            if count == self._window_size:
                if key is not None:
                    self._per_key_count[key] = 0
                else:
                    self._count = 0
            if self._should_emit(count):
                self._last_event = None
                await self._do_downstream(event)

    def _should_emit(self, count):
        if self._emit_period == EmitPeriod.FIRST and count == 1:
            return True
        elif self._emit_period == EmitPeriod.LAST and count == self._window_size:
            return True
        return False


from django.core.management.base import BaseCommand, CommandError
from crypto.models import Crypto
import logging

log = logging.getLogger('service')

class Command(BaseCommand):
    help = 'Sign test'

    def add_arguments(self, parser):
        parser.add_argument('--sign', action='append', type=str)

    def handle(self, *args, **options):

        sign = ''
        if options['sign'] is not None:
            sign = options['sign'][0]

        if len(sign) > 2:
            log.info('string to sign: "%s"' % sign)
            crypto = Crypto(True)
            log.info(crypto.signEsiaString(sign))


import os
import sys
from dateutil import tz

sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../src")
from timespan import *

def run():
    calendar = 'mon,wed,fri may,jun'
    day_exceptions = [120, 344, 345]
    start = '3pm'
    end = '8pm'
    tzi = tz.gettz('America/Boise')

    ts, error_message = parse_timespan_text(calendar, day_exceptions, start, end, tzi)

    if error_message is None:
        print(ts.__repr__())
    else:
        print(error_message)

if __name__ == '__main__':
    run()
else:
    print('This script must be ran directly.')
    exit(1)


"""Support for Lennoxs30 ventilation and allergend defender switches"""
import asyncio
from typing import Any

from .base_entity import S30BaseEntity
from .const import (
    MANAGER,
    UNIQUE_ID_SUFFIX_PARAMETER_SAFETY_SWITCH,
    VENTILATION_EQUIPMENT_ID,
)
from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_FAHRENHEIT, CONF_NAME
from . import Manager
from homeassistant.core import HomeAssistant
import logging
from homeassistant.helpers.entity import Entity
from lennoxs30api import lennox_system
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.components.switch import SwitchEntity, PLATFORM_SCHEMA
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.entity import EntityCategory

_LOGGER = logging.getLogger(__name__)

DOMAIN = "lennoxs30"

async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> bool:
    _LOGGER.debug("switch:async_setup_platform enter")

    switch_list = []
    manager: Manager = hass.data[DOMAIN][entry.unique_id][MANAGER]
    for system in manager._api.getSystems():
        _LOGGER.info(
            f"async_setup_platform ventilation [{system.supports_ventilation()}]"
        )
        if system.supports_ventilation():
            _LOGGER.info(f"Create S30 ventilation switch system [{system.sysId}]")
            switch = S30VentilationSwitch(hass, manager, system)
            switch_list.append(switch)
        if manager._allergenDefenderSwitch == True:
            _LOGGER.info(f"Create S30 allergenDefender switch system [{system.sysId}]")
            switch = S30AllergenDefenderSwitch(hass, manager, system)
            switch_list.append(switch)
        if system.numberOfZones > 1:
            _LOGGER.info(f"Create S30 zoning switch system [{system.sysId}]")
            switch = S30ZoningSwitch(hass, manager, system)
            switch_list.append(switch)

        ma_switch = S30ManualAwayModeSwitch(hass, manager, system)
        switch_list.append(ma_switch)
        _LOGGER.info(f"Create S30ManualAwayModeSwitch system [{system.sysId}]")
        sa_switch = S30SmartAwayEnableSwitch(hass, manager, system)
        switch_list.append(sa_switch)
        _LOGGER.info(f"Create S30SmartAwayEnableSwitch system [{system.sysId}]")

        if manager._create_equipment_parameters == True:
            par_safety_switch = S30ParameterSafetySwitch(hass, manager, system)
            switch_list.append(par_safety_switch)

    if len(switch_list) != 0:
        async_add_entities(switch_list, True)
        _LOGGER.debug(
            f"switch:async_setup_platform exit - created [{len(switch_list)}] switch entitites"
        )
        return True
    else:
        _LOGGER.info(f"switch:async_setup_platform exit - no ventilators founds")
        return False

class S30VentilationSwitch(S30BaseEntity, SwitchEntity):
    """Class for Lennox S30 thermostat."""

    def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
        super().__init__(manager, system)
        self._hass = hass
        self._myname = self._system.name + "_ventilation"

    async def async_added_to_hass(self) -> None:
        """Run when entity about to be added to hass."""
        self._system.registerOnUpdateCallback(
            self.update_callback,
            [
                "ventilationRemainingTime",
                "ventilatingUntilTime",
                "diagVentilationRuntime",
                "ventilationMode",
            ],
        )
        await super().async_added_to_hass()

    def update_callback(self):
        _LOGGER.info(f"update_callback myname [{self._myname}]")
        self.schedule_update_ha_state()

    @property
    def unique_id(self) -> str:
        # HA fails with dashes in IDs
        return (self._system.unique_id() + "_VST").replace("-", "")

    @property
    def extra_state_attributes(self):
        """Return the state attributes."""
        attrs: dict[str, Any] = {}
        attrs["ventilationRemainingTime"] = self._system.ventilationRemainingTime
        attrs["ventilatingUntilTime"] = self._system.ventilatingUntilTime
        attrs["diagVentilationRuntime"] = self._system.diagVentilationRuntime
        attrs["alwaysOn"] = self._system.ventilationMode == "on"
        attrs["timed"] = self._system.ventilationRemainingTime != 0
        return attrs

    @property
    def name(self):
        return self._myname

    @property
    def is_on(self):
        return (
            self._system.ventilationMode == "on"
            or self._system.ventilationRemainingTime > 0
        )

    @property
    def device_info(self) -> DeviceInfo:
        """Return device info."""
        equip_device_map = self._manager.system_equip_device_map.get(self._system.sysId)
        if equip_device_map != None:
            device = equip_device_map.get(VENTILATION_EQUIPMENT_ID)
            if device != None:
                return {
                    "identifiers": {(DOMAIN, device.unique_name)},
                }
            _LOGGER.warning(
                f"Unable to find VENTILATION_EQUIPMENT_ID in device map, please raise an issue"
            )
        else:
            _LOGGER.error(
                f"No equipment device map found for sysId [{self._system.sysId}] equipment VENTILATION_EQUIPMENT_ID, please raise an issue"
            )
        return {
            "identifiers": {(DOMAIN, self._system.unique_id())},
        }

    async def async_turn_on(self, **kwargs):
        try:
            await self._system.ventilation_on()
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error("ventilation_on:async_turn_on - error:" + e.message)
            else:
                _LOGGER.error("ventilation_on:async_turn_on - error:" + str(e))

    async def async_turn_off(self, **kwargs):
        try:
            _LOGGER.debug("ventilation:async_turn_off")
            called = False
            if self._system.ventilationMode == "on":
                _LOGGER.debug("ventilation:async_turn_off calling ventilation_off")
                await self._system.ventilation_off()
                called = True
            if self._system.ventilationRemainingTime > 0:
                await self._system.ventilation_timed(0)
                _LOGGER.debug("ventilation:async_turn_off calling ventilation_timed(0)")
                called = True
            if called:
                self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error("ventilation_off:async_turn_off - error:" + e.message)
            else:
                _LOGGER.error("ventilation_off:async_turn_off - error:" + str(e))

class S30AllergenDefenderSwitch(S30BaseEntity, SwitchEntity):
    """Class for Lennox S30 thermostat."""

    def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
        super().__init__(manager, system)
        self._hass = hass
        self._myname = self._system.name + "_allergen_defender"

    async def async_added_to_hass(self) -> None:
        """Run when entity about to be added to hass."""
        self._system.registerOnUpdateCallback(
            self.update_callback, ["allergenDefender"]
        )
        await super().async_added_to_hass()

    def update_callback(self):
        _LOGGER.info(f"update_callback myname [{self._myname}]")
        self.schedule_update_ha_state()

    @property
    def unique_id(self) -> str:
        # HA fails with dashes in IDs
        return (self._system.unique_id() + "_ADST").replace("-", "")

    @property
    def extra_state_attributes(self):
        """Return the state attributes."""
        return {}

    def update(self):
        """Update data from the thermostat API."""
        return True

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        return self._myname

    @property
    def is_on(self):
        return self._system.allergenDefender == True

    @property
    def device_info(self) -> DeviceInfo:
        """Return device info."""
        return {"identifiers": {(DOMAIN, self._system.unique_id())}}

    async def async_turn_on(self, **kwargs):
        try:
            await self._system.allergenDefender_on()
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error("allergenDefender_on:async_turn_on - error:" + e.message)
            else:
                _LOGGER.error("allergenDefender_on:async_turn_on - error:" + str(e))

    async def async_turn_off(self, **kwargs):
        try:
            await self._system.allergenDefender_off()
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error(
                    "allergenDefender_off:async_turn_off - error:" + e.message
                )
            else:
                _LOGGER.error("allergenDefender_off:async_turn_off - error:" + str(e))

class S30ManualAwayModeSwitch(S30BaseEntity, SwitchEntity):
    """Class for Lennox S30 thermostat."""

    def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
        super().__init__(manager, system)
        self._hass = hass
        self._myname = self._system.name + "_manual_away_mode"

    async def async_added_to_hass(self) -> None:
        """Run when entity about to be added to hass."""
        self._system.registerOnUpdateCallback(
            self.update_callback,
            [
                "manualAwayMode",
            ],
        )
        await super().async_added_to_hass()

    def update_callback(self):
        _LOGGER.info(f"update_callback myname [{self._myname}]")
        self.schedule_update_ha_state()

    @property
    def unique_id(self) -> str:
        # HA fails with dashes in IDs
        return (self._system.unique_id() + "_SW_MA").replace("-", "")

    @property
    def extra_state_attributes(self):
        return {}

    @property
    def name(self):
        return self._myname

    @property
    def is_on(self):
        return self._system.get_manual_away_mode() == True

    @property
    def device_info(self) -> DeviceInfo:
        return {"identifiers": {(DOMAIN, self._system.unique_id())}}

    async def async_turn_on(self, **kwargs):
        try:
            await self._system.set_manual_away_mode(True)
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error(
                    "S30ManualAwayModeSwitch:async_turn_on - error:" + e.message
                )
            else:
                _LOGGER.error("S30ManualAwayModeSwitch:async_turn_on - error:" + str(e))

    async def async_turn_off(self, **kwargs):
        try:
            await self._system.set_manual_away_mode(False)
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error(
                    "S30ManualAwayModeSwitch:async_turn_off - error:" + e.message
                )
            else:
                _LOGGER.error(
                    "S30ManualAwayModeSwitch:async_turn_off - error:" + str(e)
                )

class S30SmartAwayEnableSwitch(S30BaseEntity, SwitchEntity):
    """Class for Lennox S30 thermostat."""

    def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
        super().__init__(manager, system)
        self._hass = hass
        self._myname = self._system.name + "_smart_away_enable"

    async def async_added_to_hass(self) -> None:
        """Run when entity about to be added to hass."""
        self._system.registerOnUpdateCallback(
            self.update_callback,
            [
                "sa_enabled",
            ],
        )
        await super().async_added_to_hass()

    def update_callback(self):
        _LOGGER.info(f"update_callback myname [{self._myname}]")
        self.schedule_update_ha_state()

    @property
    def unique_id(self) -> str:
        # HA fails with dashes in IDs
        return (self._system.unique_id() + "_SW_SAE").replace("-", "")

    @property
    def extra_state_attributes(self):
        return {}

    def update(self):
        return True

    @property
    def should_poll(self):
        return False

    @property
    def name(self):
        return self._myname

    @property
    def is_on(self):
        return self._system.sa_enabled == True

    @property
    def device_info(self) -> DeviceInfo:
        return {"identifiers": {(DOMAIN, self._system.unique_id())}}

    async def async_turn_on(self, **kwargs):
        try:
            await self._system.enable_smart_away(True)
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error(
                    "S30SmartAwayEnableSwitch:async_turn_on - error:" + e.message
                )
            else:
                _LOGGER.error(
                    "S30SmartAwayEnableSwitch:async_turn_on - error:" + str(e)
                )

    async def async_turn_off(self, **kwargs):
        try:
            await self._system.enable_smart_away(False)
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error(
                    "S30SmartAwayEnableSwitch:async_turn_off - error:" + e.message
                )
            else:
                _LOGGER.error(
                    "S30SmartAwayEnableSwitch:async_turn_off - error:" + str(e)
                )

class S30ZoningSwitch(S30BaseEntity, SwitchEntity):
    """Class for iHarmony Zoning"""

    def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
        super().__init__(manager, system)
        self._hass = hass
        self._myname = self._system.name + "_zoning_enable"

    async def async_added_to_hass(self) -> None:
        """Run when entity about to be added to hass."""
        self._system.registerOnUpdateCallback(
            self.update_callback,
            [
                "centralMode",
            ],
        )
        await super().async_added_to_hass()

    def update_callback(self):
        _LOGGER.info(f"update_callback myname [{self._myname}]")
        self.schedule_update_ha_state()

    @property
    def unique_id(self) -> str:
        # HA fails with dashes in IDs
        return (self._system.unique_id() + "_SW_ZE").replace("-", "")

    @property
    def extra_state_attributes(self):
        return {}

    def update(self):
        return True

    @property
    def should_poll(self):
        return False

    @property
    def name(self):
        return self._myname

    @property
    def is_on(self):
        return self._system.centralMode == False

    @property
    def device_info(self) -> DeviceInfo:
        return {"identifiers": {(DOMAIN, self._system.unique_id())}}

    async def async_turn_on(self, **kwargs):
        try:
            await self._system.centralMode_off()
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error("S30ZoningSwitch:async_turn_on - error:" + e.message)
            else:
                _LOGGER.error("S30ZoningSwitch:async_turn_on - error:" + str(e))

    async def async_turn_off(self, **kwargs):
        try:
            await self._system.centralMode_on()
            self._manager._mp_wakeup_event.set()
        except Exception as e:
            if hasattr(e, "message"):
                _LOGGER.error("S30ZoningSwitch:async_turn_off - error:" + e.message)
            else:
                _LOGGER.error("S30ZoningSwitch:async_turn_off - error:" + str(e))

class S30ParameterSafetySwitch(S30BaseEntity, SwitchEntity):
    def __init__(
        self,
        hass: HomeAssistant,
        manager: Manager,
        system: lennox_system,
        rearm_duration_sec=60.0,
    ):
        super().__init__(manager, system)
        self._hass = hass
        self._myname = self._system.name + "_parameter_safety"
        self._rearm_duration_sec = rearm_duration_sec
        manager.parameter_safety_turn_on(self._system.sysId)

    @property
    def unique_id(self) -> str:
        # HA fails with dashes in IDs
        return (
            f"{self._system.unique_id()}{UNIQUE_ID_SUFFIX_PARAMETER_SAFETY_SWITCH}"
        ).replace("-", "")

    @property
    def extra_state_attributes(self):
        return {}

    def update(self):
        return True

    @property
    def should_poll(self):
        return False

    @property
    def name(self):
        return self._myname

    @property
    def is_on(self):
        res = self._manager.parameter_safety_on(self._system.sysId)
        return res

    @property
    def device_info(self) -> DeviceInfo:
        return {"identifiers": {(DOMAIN, self._system.unique_id())}}

    async def async_turn_on(self, **kwargs):
        self._manager.parameter_safety_turn_on(self._system.sysId)
        self.schedule_update_ha_state()

    async def async_turn_off(self, **kwargs):
        self._manager.parameter_safety_turn_off(self._system.sysId)
        asyncio.create_task(self.async_rearm_task())
        self.schedule_update_ha_state()

    async def async_rearm_task(self):
        await asyncio.sleep(self._rearm_duration_sec)
        self._manager.parameter_safety_turn_on(self._system.sysId)
        self.schedule_update_ha_state()

    @property
    def entity_category(self):
        return EntityCategory.CONFIG


#!/usr/bin/env python3.4
# Client for Project 1, ECE 4564
# Author: John McDouall

import socket
import tweepy
import sys
import re
import time

USERNAME = 'Trambelus'
OAUTHFILE = 'oauth.txt'
STARTEDFILE = 'started.txt'
WATCHING = 'VTNetApps'
PORT = 45678

VALID_PAT = re.compile(r"#ECE4564_\d{1,3}_\d{1,3}_\d{1,3}_\d{1,3}_\d{1,5}_LED(OFF|ON|FLASH)")
IP_PAT = re.compile(r"_\d{1,3}_\d{1,3}_\d{1,3}_\d{1,3}_\d{1,5}")

LOGFILE = 'p1client.log'

def log(*msg):
	"""
	Prepends a timestamp and prints a message to the console and LOGFILE
	"""
	output = "%s:\t%s" % (time.strftime("%Y-%m-%d %X"), ' '.join(msg))
	print(output)
	with open(LOGFILE, 'a') as f:
		f.write(output + '\n')

def get_credentials():
	"""
	Get key, secret, token, and token secret from external file
	"""
	# (Not gonna hardwire them here)
	with open(OAUTHFILE,'r') as f:
		stuff = f.readlines()
		ret = [i.rstrip() for i in next(x[1:] for x in [t.split('\t') for t in stuff] if x[0] == USERNAME)]
		return ret

def process(command):
	"""
	Given a command in hashtag format (string), send the appropriate command
	to remote Pi and generate confirmation message.
	"""
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	ip_port = re.search(IP_PAT, command).group(0)
	ip = ip_port[:ip_port.rfind("_")].replace('_','.')[1:]
	port = int(ip_port[ip_port.rfind("_")+1:])
	led_on = 0
	if 'FLASH' in command:
		led_on = 2
	elif 'ON' in command:
		led_on = 1
	log("Attempting connection to %s on port %d" % (ip, port))
	sock.connect((ip, port))
	log("Connection successful")
	sock.send(bytes(chr(led_on), 'UTF-8'))
	resp = int.from_bytes(sock.recv(1), byteorder='little')
	log("Remote Pi responded with code %d" %  resp)
	return "ACK %s" % (command)

def monitor():
	"""
	Initializes tweepy; loops through and parses username mentions; calls process(); posts responses
	"""
	# Initialize
	cred = get_credentials()
	auth = tweepy.OAuthHandler(cred[0], cred[1])
	auth.set_access_token(cred[2], cred[3])
	api = tweepy.API(auth)
	log("Initialization successful")
	# Monitor
	with open(STARTEDFILE, 'r') as f:
		started = [int(s.strip()) for s in f.readlines()]

	while True:
		try:
			mentions = api.mentions_timeline(count=1)
			for mention in mentions:
				if mention.id in started:
					time.sleep(5)
					continue
				started.append(mention.id)
				with open(STARTEDFILE, 'a') as f:
					f.write('\n'+str(mention.id))
				log("%s: %s" % (mention.text, mention.user.screen_name))
				commands = re.search(VALID_PAT, mention.text)
				if commands:
					response = process(commands.group(0))
					status = "@%s %s" % (mention.user.screen_name, response)
					log("Posting status %s (len=%d)" % (status, len(status)))
					# This update_status call doesn't work 100% of the time.
					# Sometimes there are 403 or 429 responses.
					# Tweepy isn't the most robust library; nothing to be done for it.
					try:
						api.update_status(status=status)
					except tweepy.error.TweepError as ex:
						log("Tweepy error: %s" % str(ex))
		except tweepy.error.TweepError as ex:
			# Too many requests, probably
			if '429' in str(ex):
				log("Too many requests; sleeping")
			time.sleep(30)

def main():
	if len(sys.argv) == 1:
		monitor()

if __name__ == '__main__':
	main()


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

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

from ui_source.MetadataWidgetSetting import Ui_MetadataWidgetSetting

class MetadataSetting(QWidget, Ui_MetadataWidgetSetting):
    done_signal = pyqtSignal(dict)
    auto_signal = pyqtSignal(dict)

    def __init__(self, parent=None):
        super(MetadataSetting, self).__init__(parent)
        self.setupUi(self)
        self._init_signal()
        self.is_download_lrc_checkBox.setChecked(True)

    def _init_signal(self):
        self.sure_button.clicked.connect(self.done_event)
        self.auto_button.clicked.connect(lambda: self.done_event(is_auto=True))

    def done_event(self, is_auto=False):
        text = self.api_comboBox.currentText()
        if text == "酷狗api":
            mode = "kugou"
        elif text == "网易云api":
            mode = "cloud"
        elif text == "混合api":
            mode = "mixed"
        else:
            mode = ""

        setting_dict = {
            "mode": mode,
            "is_lyric": self.is_download_lrc_checkBox.isChecked()
        }
        if is_auto:
            self.auto_signal.emit(setting_dict)
        else:
            self.done_signal.emit(setting_dict)
        self.close()


import csv
import heapq
import os

import utils

LINES_PER_FILE = 50000
DATE_FORMAT = '%Y-%m-%d  %H:%M:%S\n'

def external_sort(local_file):
    def record_constructor(uploaded):
        def save_sorted(time_str_list, file_name):
            sorted_time_str = sort_string_list(time_str_list)
            with open(file_name, 'w') as f:
                f.writelines(sorted_time_str)
            return file_name

        with open(uploaded, 'rb') as f:
            csv_reader = csv.reader(f, delimiter='\t')
            entry_times = []
            exit_times = []
            file_index = 0
            entry_files = []
            exit_files = []
            for i, line in enumerate(csv_reader):
                if i > 0:
                    splited = line[0].split(',')
                    entry_time = '%s\n' % splited[0]
                    exit_time = '%s\n' % splited[1]
                    entry_times.append(entry_time)
                    exit_times.append(exit_time)
                    if i % LINES_PER_FILE == 0:
                        try:
                            entry_files.append(save_sorted(entry_times, 'entryTime%d.txt' % file_index))
                            exit_files.append(save_sorted(exit_times, 'exitTime%d.txt' % file_index))
                            file_index += 1
                        except IOError as e:
                            print('Operation failed: %s' % e.strerror)
                        entry_times = []
                        exit_times = []
            if len(entry_times) != 0:
                entry_files.append(save_sorted(entry_times, 'entryTime%d.txt' % file_index))
                exit_files.append(save_sorted(exit_times, 'exitTime%d.txt' % file_index))
            return entry_files, exit_files

    def sort_string_list(time_string_list):
        cache = {}

        def compare(left, right):
            left_time = utils.str_to_datetime(left, DATE_FORMAT, cache=cache)
            right_time = utils.str_to_datetime(right, DATE_FORMAT, cache=cache)
            if left_time > right_time:
                return 1
            elif left_time < right_time:
                return -1
            else:
                return 0

        sorted_list = sorted(time_string_list, cmp=compare)
        return sorted_list

    def merge_k_sorted_files(file_list, merged_file_name):
        with open(merged_file_name, 'w') as merged_file:
            file_readers = []
            try:
                for file_name in file_list:
                    f = open(file_name, 'r')
                    file_readers.append(f)
                heap = []
                for reader in file_readers:
                    line_read = reader.readline()
                    heap.append((utils.str_to_datetime(line_read, DATE_FORMAT), line_read, reader))
                heapq.heapify(heap)
                while heap:
                    pop = heapq.heappop(heap)
                    merged_file.write(pop[1])
                    line_read = pop[2].readline()
                    if line_read.strip() != '':
                        heapq.heappush(heap, (utils.str_to_datetime(line_read, DATE_FORMAT), line_read, pop[2]))
                merged_file.close()
                for reader in file_readers:
                    reader.close()
                for file_name in file_list:
                    os.remove(os.getcwd() + '/' + file_name)
                return merged_file_name
            except IOError as e:
                print('Operation failed: %s' % e.strerror)

    entry_file_list, exit_file_list = record_constructor(local_file)
    entries = merge_k_sorted_files(entry_file_list, 'entry_time.txt')
    exits = merge_k_sorted_files(exit_file_list, 'exit_time.txt')
    return entries, exits


# os 模块 用于提供系统级别的操作
""""""

"""
Python的标准库中的os模块包含普遍的操作系统功能。
这个模块的作用主要是提供与平台无关的功能。
也就是说os模块能够处理平台间的差异问题，
使得编写好的程序无需做任何改动就能在另外的平台上运行。
当然，这个模块只是提供了一个轻便的方法使用要依赖操作系统的功能。
有些特定的功能还得使用特定的模块
"""

# sys 用于提供对解释器相关的操作

# hashlib
# 用于加密相关的操作，代替了md5模块和sha模块，主
# 要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ，MD5 算法

import hashlib

h = hashlib.md5()
h.update(bytes('admin', encoding='utf-8'))  #对admin字符进行加密

print(h.hexdigest())

#  hmac 模块
# 它内部对我们创建 key 和 内容 再进行处理然后再加密

import  hmac

myhmac = hmac.new(b'key')
myhmac.update(b'message')

print(myhmac.hexdigest())

# json 和 pickle

"""
json，用于字符串 和 python数据类型间进行转换
ppickle，用于python特有的类型 和 python的数据类型间进行转换

dumps():把任意对象序列化成一个str
ddump() 直接把对象序列化后写入一个file-like Object：

反序列化:
loads()
load()

"""
"""
Python提供两个模块来实现序列化：cPickle和pickle。这两个模块功能是一样的，区别在于cPickle是C语言写的，速度快，pickle是纯Python写的，速度慢，
跟cStringIO和StringIO一个道理。
用的时候，先尝试导入cPickle，如果失败，再导入pickle：

try:
    import cPickle as pickle
except ImportError:
    import pickle

"""

"""
Python语言特定的序列化模块是pickle，
但如果要把序列化搞得更通用、更符合Web标准，
就可以使用json模块。

json模块的dumps()和loads()函数是定义得非常好的接口的典范。当我们使用时，只需要传入一个必须的参数。
但是，当默认的序列化或反序列机制不满足我们的要求时，
我们又可以传入更多的参数来定制序列化或反序列化的规则，
既做到了接口简单易用，又做到了充分的扩展性和灵活性。

"""

import json

class Student(object):
    def __init__(self):
        self.name = "Allan"
        self.age = 22

s = Student()

def student2dict(std):
    return {
        'name': std.name,
        'age': std.age

     }

print(json.dumps(s, default=student2dict))

"""
执行shell命令的相关的模块和函数的功能
均在 subprocess 模块中实现，并提供了更丰富的功能
"""


class Troop(object):
    def __init__(self, troop_id, class_id, loadout_id, skin_id):
        self.id = troop_id
        self.class_id = class_id
        self.troop_class = None
        self.skin_id = skin_id
        self.skin = None
        self.loadout_id = loadout_id
        self.loadout = None
        self.hp = 0
        self.dmg = 0
        self.atk_range = 0
        self.move_range = 0
        self.modifiers = None

    def populate(self):
        from db_access import db_troop

        db_troop.populate(self)

    def calculate_stats(self):
        self.populate()
        self.hp = self.troop_class.max_hp
        self.dmg = self.troop_class.dmg
        self.atk_range = self.troop_class.atk_range
        self.move_range = self.troop_class.move_range
        hp = 0
        dmg = 0
        atk_range = 0
        move_range = 0
        for i in self.modifiers:
            if i is not None:
                hp += i.max_hp
                dmg += i.dmg
                atk_range += i.atk_range
                move_range += i.move_range
        self.hp += round(max(((self.hp * hp)/100), 1))
        self.dmg += round(max(((self.dmg * dmg)/100), 0))
        self.atk_range += round(max(((self.atk_range * atk_range)/100), 1))
        self.move_range += round(max(((self.move_range * move_range)/100), 1))

    def get_stats(self):
        self.calculate_stats()
        return {"hp": self.hp, "dmg": self.dmg, "atk_range": self.atk_range, "move_range": self.move_range}


from django.contrib import admin
from .models import Article, Category

# change title admin page

admin.site.site_header = 'وبلاگ جنگویی من'

## action custom
def make_published(modeladmin, request, queryset):
    row_updated = queryset.update(status='p')
    if row_updated == 1:
        massage_bit = 'منتشر شد.'
    else:
        massage_bit = 'منتشر شدن.'

    modeladmin.message_user(request,"{} مقاله {}".format(row_updated,massage_bit))
make_published.short_description = 'انتشار مقالات انتخاب شده'

def make_drafted(modeladmin, request, queryset):
    row_updated = queryset.update(status='d')
    if row_updated == 1:
        massage_bit = 'پیش نویس شد.'
    else:
        massage_bit = 'پیش نویس شدن.'

    modeladmin.message_user(request,"{} مقاله {}".format(row_updated,massage_bit))
make_drafted.short_description = 'پیش نویس مقالات انتخاب شده'

class CategoryAdmin(admin.ModelAdmin):
    list_display = ('position', "title", "slug",'parent', "status")
    list_filter = (["status"])
    search_fields = ('title', 'slug')
    prepopulated_fields = {'slug': ('title', )}

admin.site.register(Category, CategoryAdmin),

class ArticleAdmin(admin.ModelAdmin):
    list_display = ("title",'thumbnail_tag' ,"slug", "jpublish", "status","category_to_str")
    list_filter = (
        "publish",
        "status",
    )
    search_fields = ('title', 'description')
    prepopulated_fields = {'slug': ('title', )}
    ordering = ['status', '-publish']
    actions = [make_published,make_drafted]

    def category_to_str(self,obj):
        return ' , '.join([category.title for category in obj.category_published()])
    category_to_str.short_description = 'دسته بندی'

admin.site.register(Article, ArticleAdmin),


from underthesea import word_tokenize, sent_tokenize
from rake_nltk import Rake, Metric

import string
from itertools import chain

class RakeVietNamese(Rake):

    def __init__(
        self,
        stopwordspath=None,
        punctuations=None,
        ranking_metric=Metric.DEGREE_TO_FREQUENCY_RATIO,
        max_length=100000,
        min_length=1,
    ):

        # By default use degree to frequency ratio as the metric.
        if isinstance(ranking_metric, Metric):
            self.metric = ranking_metric
        else:
            self.metric = Metric.DEGREE_TO_FREQUENCY_RATIO

        # vietnamese stopwords
        if stopwordspath:
            with open(stopwordspath,  encoding="utf8") as f:
                self.stopwords = f.read().splitlines()
        else:
            raise Exception('Missing stopwords')

        # If punctuations are not provided we ignore all punctuation symbols.
        self.punctuations = punctuations
        if self.punctuations is None:
            self.punctuations = string.punctuation

        # All things which act as sentence breaks during keyword extraction.
        self.to_ignore = set(chain(self.stopwords, self.punctuations))

        # Assign min or max length to the attributes
        self.min_length = min_length
        self.max_length = max_length

        # Stuff to be extracted from the provided text.
        self.frequency_dist = None
        self.degree = None
        self.rank_list = None
        self.ranked_phrases = None

    def extract_keywords_from_text(self, text):
        sentences = sent_tokenize(text)
        self.extract_keywords_from_sentences(sentences)

    def extract_keywords_from_sentences(self, sentences):
        phrase_list = self._generate_phrases(sentences)
        self._build_frequency_dist(phrase_list)
        self._build_word_co_occurance_graph(phrase_list)
        self._build_ranklist(phrase_list)

    def _generate_phrases(self, sentences):
        phrase_list = set()
        # Create contender phrases from sentences.
        for sentence in sentences:
            word_list = [word.lower() for word in word_tokenize(sentence)]
            phrase_list.update(self._get_phrase_list_from_words(word_list))
        return phrase_list

if __name__ == '__main__':
    # text = """
    # TÂY DU KÝ TRỞ LẠI VỚI PHIÊN BẢN MỸ - LỤC TIỂU LINH ĐỒNG TIẾP TỤC ĐẢM NHIỆM VAI TÔN NGỘ KHÔNG Ở ĐỘ TUỔI 60.
    # Tác phẩm phim điện ảnh mang tên Tây du ký: Mỹ Hầu Vương thật giả (西游记真假美猴王) do Hàn Đình làm đạo diễn đã chính thức bấm máy. Bộ phim này thật chất là Dám hỏi đường đi ở nơi nào (敢问路在何方) và cũng là tác phẩm Tây du ký do Mỹ - Trung hợp tác quay hình.
    # Được biết, bộ phim điện ảnh này đã mời hai diễn viên Lục Tiểu Linh Đồng và Mã Đức Hoa để đảm nhận vai Tôn Ngộ Không và Trư Bát Giới. Trước mắt, phiên bản điện ảnh chỉ mới công bố tên của hai diễn viên này, còn vị trí của các nhân vật khác vẫn chưa tìm được người thích hợp. Đạo diện Hàn Đình còn đăng bài viết trong vòng bạn bè để tìm kiếm diễn viên thích hợp.
    # Vì để đóng bộ phim Tây du ký: Mỹ Hầu Vương thật giả này mà Lục Tiểu Linh Đồng đã sửa kịch bản đến 3 lần.
    # """
    text = """
    Nhắc đến Tết không thể không nhắc tới hoa đào, hoa mai, quất cảnh. Tuy nhiên, thường vốn bỏ ra để kinh doanh các loại cây hoa này khá cao. Thế niên, chiến lược kinh doanh của chị Thu Giang, một giáo viên tiểu học tại Hà Nội là bán các loại hoa như hồng, cúc, ly, dơn, đồng tiền… với số vốn ít nhưng dễ tiêu thụ nên vẫn mang đến khả năng sinh lời cao.
    """
    r = RakeVietNamese(stopwordspath='vietnamese-stopwords.txt')
    r.extract_keywords_from_text(text)
    result = r.get_ranked_phrases_with_scores()
    from pprint import pprint
    pprint(result)


from typing import List

class Solution:
    """
    Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order,
    find two numbers such that they add up to a specific target number. Let these two numbers be
    numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length.
    Return the indices of the two numbers, index1 and index2, added by one as an integer array
    [index1, index2] of length 2.
    The tests are generated such that there is exactly one solution. You may not use the same
    element twice.
    Your solution must use only constant extra space.
    Constraints:
        2 <= numbers.length <= 3 * 10^4
        -1000 <= numbers[i] <= 1000
        numbers is sorted in non-decreasing order.
        -1000 <= target <= 1000
        The tests are generated such that there is exactly one solution.
    """

    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        # take values from left and right end
        l = 0
        r = len(numbers) - 1
        while l <= r:
            two_sum = numbers[l] + numbers[r]

            # if sum is too low, increase l, to increase next sum
            if two_sum < target:
                l += 1
            elif two_sum > target:
                # if sum to too high, decrease r, to decrease next sum
                r -= 1
            else:
                # target found, +1 as result should be 1-indexed
                return [l+1, r+1]

        # constraint states there should always be a pair
        assert(False)

Medium/167. Two Sum II - Input Array Is Sorted.py


# ---
# jupyter:
#   jupytext:
#     formats: ipynb,py:percent
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.10.2
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# %% [markdown]
# **Current log file**

# %%
# PACKAGES
import os
PROJECT_PATH = os.getcwd().replace("notebooks", "")
import sys
sys.path.append(PROJECT_PATH)
from src.data_representation.Examples import load_Examples_from_file
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
import src.model_training.clusters
from tqdm import tqdm

# %%
# running the project from here wont work since we demand to be in the main directory
# Display the log file:

log_file = open(PROJECT_PATH + "run.log", "r")
print(log_file.read())
log_file.close()

# %% [markdown]
# **Visualize/Analyse data_generation output**

# %%
# name of the folder where the output of the Example class file is located
DATA_GEN_FOLDER_NAME = "Feb-09-2021"
EXAMPLES_DATASET_PATH = PROJECT_PATH + "data/" + DATA_GEN_FOLDER_NAME + "/0"

snippets = load_Examples_from_file(EXAMPLES_DATASET_PATH)

# %%
print("Number train examples: " + str(len(snippets.train_data)))
print("Number test examples: " + str(len(snippets.test_data)))

# %%
#Display all snippets in one plot to identify maybe classes of errors
all_snippets = snippets.train_data + snippets.test_data
for snippet in tqdm(all_snippets):
    if snippet.scaler > 50000:
        print(f"Country: {snippet.country}")
        print(f"Standardized label: {snippet.label}")
        print(f"Unstandardized label: {snippet.original_label[0]}")
        plt.plot(snippet.time_series)
        plt.show()
        plt.plot(snippet.time_series*snippet.scaler)

        break
plt.show()

# %%

# %%
#get an overview over the values in all time series using pd hist()
values = []
for snippet in all_snippets:
    for value in snippet.time_series:
        values.append(value)
pd.DataFrame(values).hist(bins=101)
#closer look at smaller values (<bound)
bound = 10000
pd.DataFrame([x for x in values if (x <bound and x!=0)]).hist(bins=101)

#nr/proportion of zero entries:
zero_counter = len([i for i, x in enumerate(values) if x == 0])
print("Number zero entries: " + str(zero_counter) + " Proportion: " + str(zero_counter/len(values)))
print("Total number entries: " + str(len(values)))

# %%
#analyse the values itself a little bit:
print("mean: "  + str(np.mean(values)))
print("varianz: " + str(np.var(values)))
ten_quantiles =[np.quantile(values, (i+1)*.10) for i in range(10)]
print("quantiles (10%, 20% ...): " +str(ten_quantiles))
four_quantiles =[np.quantile(values, (i+1)*.25) for i in range(4)]
print("four quantiles: " + str(four_quantiles))

#test if there are negative values:
neg_values = [x for  x in values if x<0]
print("Number of negative values: " + str(len(neg_values)))
print("Negative values: " + str(neg_values))

# %% [markdown]
# # Forecast evaluation visual

# %%
# name of the folder where the output of the Example class file is located
DATA_GEN_FOLDER_NAME = "Feb-09-2021"
EXAMPLES_DATASET_PATH = PROJECT_PATH + "data/" + DATA_GEN_FOLDER_NAME + "/0_w_forecast_avg_perc_dist_forecasting_fct_naive_forecast"

examples = load_Examples_from_file(EXAMPLES_DATASET_PATH)
snippets = examples.train_data+examples.test_data
all_perc_list=[]
hundret_perc_list = []
thousend_perc_list = []
samples_count = 0
for snippet in snippets:
    inverted_label = round(snippet.invert_to_abs_cases(snippet.label))

    if inverted_label < 0:
        print(f"Snippet label: {snippet.label} Snippet forecast {snippet.forecast} and inverted label {inverted_label}")
    if inverted_label != 0:
        inverted_forecast = round(snippet.invert_to_abs_cases(snippet.forecast))
        if inverted_forecast < 0:
            print(f"Snippet label: {snippet.label} Snippet forecast {snippet.forecast} and inverted forecast {inverted_forecast}")

        perc_dist = abs(inverted_forecast-inverted_label)/inverted_label
        perc_list.append(perc_dist)
        if inverted_label >= 100:
            hundret_perc_list.append(perc_dist)
        if inverted_label >= 1000:
            thousend_perc_list.append(perc_dist)
        samples_count += 1

all_df = pd.DataFrame(perc_list, columns=["All Snippets"])
h_df = pd.DataFrame(hundret_perc_list, columns=["Label >= 100"])
t_df = pd.DataFrame(thousend_perc_list, columns=["Label >= 1000"])
print(np.var(perc_list))
print(np.var(hundret_perc_list))
print(np.var(thousend_perc_list))
all_df.boxplot(vert=False, figsize=(13,5))
plt.show()
h_df.boxplot(vert=False, figsize=(13,5))
plt.show()
t_df.boxplot(vert=False, figsize=(13,5))
plt.show()


import csv
from helpers import update_virtual_inventory

LOCATIONID = 55834411176

def read_csv():
    ID = []
    QUANT = []
    with open('ID.csv', newline='') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            ID.append(row)
    with open('QUANT.csv', newline='') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            QUANT.append(row)

    return ID , QUANT

def output_changes(ID,QUANT):
    changes = []
    for row in ID:
        for i in QUANT:
            if row[1] == i[1] and row[4] == i[4] and row[2] == i[2]:
                changes.append([row[-1],i[6]])
    for item in changes:
        if item[1] == "+10":
            item[1] = "10"
    return changes

if __name__ == "__main__":
    ID,QUANT = read_csv()
    changes = output_changes(ID,QUANT)
    for item in changes:
        update_virtual_inventory(item[0],item[1])


import tkinter as tk
import logging
from tkinter.scrolledtext import ScrolledText

logger = logging.getLogger('python')

class MiscLogger(ScrolledText):
    def append(self, msg):
        self.configure(state='normal')
        self.insert(tk.END, msg + '\n')
        self.configure(state='disabled')
        # Autoscroll to the bottom
        self.yview(tk.END)


import os
import yaml

def parse_platform_specific(cfg, is_linux):
    """Recursive function that will parse platform specific config
       This will move all children of matching platform keys to its parent
       I.e. if current platform is "linux" this config:
          nrf5:
             version: 15.3.0_59ac345
             windows:
                 install_dir: C:/ubxlib_sdks/nRF5_SDK_15.3.0_59ac345
             linux:
                 install_dir: ${HOME}/sdks/nRF5_SDK_15.3.0_59ac345
       will become:
          nrf5:
             version: 15.3.0_59ac345
             install_dir: ${HOME}/sdks/nRF5_SDK_15.3.0_59ac345
    """
    newcfg = cfg.copy()
    for key, value in cfg.items():
        if key in ("linux", "windows"):
            is_linux_setting = key == "linux"
            if is_linux == is_linux_setting:
                newcfg.update(value)
            del newcfg[key]
        elif isinstance(value, dict):
            newcfg[key] = parse_platform_specific(cfg[key], is_linux)

    return newcfg

def load_config_yaml(file_path, is_linux):
    """Load a yaml config file
    Notes:
    * If the yaml file contains environmental variables these will first be expanded.
    * The yaml file can also contain platform specific config.
      Please see parse_platform_specific() how these are handled."""
    with open(file_path, 'r') as file:
        cfg = yaml.safe_load(os.path.expandvars(file.read()))
    return parse_platform_specific(cfg, is_linux)


import numpy as np
from pyhdf.SD import SD, SDC
from osgeo import gdal
from osgeo import osr
import os

HDF_DIR_PATH = "D:\\study\\yanyi\\yaogan\\week2\\MOD09A1"  # path of hdf file directory
OUTPUT_PATH = ""  # path of the output directory
R = "sur_refl_b01"  # band name and its corresponding SDS name
NIR = "sur_refl_b02"
B = "sur_refl_b03"
SWIR = "sur_refl_b06"
QC = "sur_refl_qc_500m"  # 500m Reflectance Band Quality

def main():
    calculate_index(get_hdf_files())
    return

def get_hdf_files():
    """
    read hdf files from a specified directory and
    convert them into python hdf objects.

    :param:
      none.

    :return hdf_file_object_dict:
      a dictionary:
        keys: hdf file name without ".hdf"
        values: corresponding python hdf object
    """

    hdf_file_name_list = os.listdir(HDF_DIR_PATH)
    hdf_file_object_dict = {}
    for file_name in hdf_file_name_list:
        if file_name[-4:] == ".hdf":
            hdf_file_object_dict[file_name[:-4]] = SD(HDF_DIR_PATH + "\\" + file_name, SDC.READ)
    return hdf_file_object_dict

def calculate_index(hdf_file_object_dict, scale_factor=0.0001, offset=0):
    """
    calculate NDVI, EVI, EVI2, LSWI of each python hdf object and
    save the result to a specified directory.

    :param hdf_file_object_dict:
      a dictionary:
        keys: hdf file name without ".hdf"
        values: corresponding python hdf object

    :param scale_factor:
      scale factor of the science dataset.
      type: float

    :param offset:
      offset of the science dataset.
      type: float

    :return:
      none.
    """

    for hdf_file_name, hdf_object in hdf_file_object_dict.items():
        r = scale_factor * get_band_data_matrix(hdf_object, R) + offset
        n = scale_factor * get_band_data_matrix(hdf_object, NIR) + offset
        b = scale_factor * get_band_data_matrix(hdf_object, B) + offset
        swir = scale_factor * get_band_data_matrix(hdf_object, SWIR) + offset
        qc = get_quality_control_mask(hdf_object)

        # source: Development of a two-band enhanced vegetation index without a blue band
        ndvi = np.where(qc == 1, reasonable_divide((n - r), (n + r)), np.nan)
        # source: Development of a two-band enhanced vegetation index without a blue band
        evi = np.where(qc == 1, 2.5 * reasonable_divide((n - r), (n + 6 * r - 7.5 * b + 1)), np.nan)
        # source: Development of a two-band enhanced vegetation index without a blue band
        evi2 = np.where(qc == 1, 2.5 * reasonable_divide((n - r), (n + 2.4 * r + 1)), np.nan)
        # source: Mapping paddy rice agriculture in southern China using multi-temporal MODIS images
        lswi = np.where(qc == 1, reasonable_divide((n - swir), (n + swir)), np.nan)

        save_as_tiff(ndvi, "NDVI", hdf_file_name)
        save_as_tiff(evi, "EVI", hdf_file_name)
        save_as_tiff(evi2, "EVI2", hdf_file_name)
        save_as_tiff(lswi, "LSWI", hdf_file_name)

def get_band_data_matrix(hdf_object, band):
    """
    get data of a band, and convert it into numpy matrix.

    :param hdf_object:
      the python hdf object.

    :param band:
      which band's data need to convert.
      options:
         R(red)/NIR/B(blue)/SWIR/QC

    :return:
      a numpy matrix of data of a band.
    """
    band_object = hdf_object.select(band)
    band_data = band_object.get()
    return np.matrix(band_data)

def reasonable_divide(divisor, dividend):
    """
    a division that can avoid errors like divide by zero.

    :param divisor:
      type: numpy matrix

    :param dividend:
      type: numpy matrix

    :return:
      division result.
      type: numpy matrix
    """
    return np.divide(divisor, dividend, out=np.zeros_like(divisor, dtype=np.float64), where=dividend != 0)

def get_quality_control_mask(hdf_object):
    """
    get data of band quality matrix,
    and convert it into mask matrix.

    :param hdf_object:
      the python hdf object.

    :return quality_control_mask:
      quality control mask.
      type: numpy matrix.
    """

    band_quality_matrix = get_band_data_matrix(hdf_object, QC).tolist()
    quality_control_mask = []
    for row in band_quality_matrix:
        quality_control_mask.append([int(bin(num)[-2:] in ['00']) for num in row])
    return np.matrix(quality_control_mask)

def save_as_tiff(matrix, index_type, hdf_file_name):
    """
    save the calculated matrix as a tiff file.

    :param matrix:
      matrix that needs to be written to the tiff file.

    :param index_type:
      the index type.

    :param hdf_file_name:
      hdf file name without ".hdf"

    :return:
      none.

    todo: return a bool value and catch the error.
    """

    x_pixels = matrix.shape[1]  # number of pixels in x
    y_pixels = matrix.shape[0]  # number of pixels in y
    driver = gdal.GetDriverByName('GTiff')

    output_path = ""
    if OUTPUT_PATH == "":
        output_path = HDF_DIR_PATH + "\\" + index_type
    if not os.path.exists(output_path):
        os.mkdir(output_path)
    output_file_name = output_path + "\\" + hdf_file_name[0: -13] + index_type + ".tiff"
    created_temp = driver.Create(output_file_name, x_pixels, y_pixels, 1, gdal.GDT_Float32)
    created_temp.GetRasterBand(1).WriteArray(matrix)

def get_SDS_info(hdf_object, flag=0):
    """
    get the number and name of SDS.

    :param hdf_object:
      the python hdf object.

    :param flag:
      type: int
      when it is set to 0, print out SDS_info.

    :return SDS_info:
      a list:
        the first element is the number of SDS.
        the second element is a list of all SDS name(string).
    """

    sds_info = [hdf_object.info()[0], list(hdf_object.datasets().keys())]
    if flag == 0:
        print(sds_info)
    return sds_info

if __name__ == '__main__':
    main()