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

import numpy as np
import sklearn.metrics as metrics
import seaborn as sns

from mosaic import features
from mosaic import contexts
from mosaic import image_io
from mosaic import plots
from mosaic import data_utils
from mosaic.grid.image_grid import images_to_grid

__all__ = ['scatter_grid']

def images_to_scatter_grid(images, x_var, y_var, padding=None, **kwargs):
    """Creates a grid plot from a scatter plot.

    Parameters
    ----------
    images : list of length [n_samples,]
        A List of PIL Image objects. All images must be
        the same shape NxWx3.

    x_var : np.array of shape [n_samples,]
        The x-coordinate in euclidean space.

    y_var : np.array of shape [n_samples,]
        The y-coordinate in euclidean space.

    padding : int, optional
        The padding between images in the grid.

    Returns
    -------
    A properly shaped width x height x 3 PIL Image.
    """
    # scale the variables between 0-1 (subtract off min?)
    features.minmax_scale(x_var)
    features.minmax_scale(y_var)
    xy = np.c_[x_var, y_var]

    # make a grid of evenly spaced points on the grid.
    # The grid is of size sqrt(n_samples) x sqrt(n_samples)
    grid_size = int(np.ceil(np.sqrt(len(images))))
    grid_1d = np.linspace(0, 1, grid_size)
    grid_2d = np.dstack(np.meshgrid(grid_1d, grid_1d)).reshape(-1, 2)

    # distances between the evenly spaced grid and the points
    dist = metrics.euclidean_distances(grid_2d, xy)

    # determine order based on nearest neighbors
    image_order = []
    for i in range(grid_2d.shape[0]):
        index = np.argmin(dist[i, :])
        image_order.append(index)
        dist[:, index] = np.inf  # set to inf so we don't pick this point again
    images = [images[index] for index in image_order]

    grid = images_to_grid(images, padding=padding)
    return plots.pillow_to_matplotlib(grid, **kwargs)

def scatter_grid(x, y,
                  images=None,
                  data=None,
                  hue=None,
                  image_dir='',
                  image_size=None,
                  padding=None,
                  n_jobs=1,
                  **kwargs):
    """Draw a plot ordering images in a regularly spaced 2-d grid
    based on their distance in the x-y plane. The distance between
    points is assumed to be euclidean.

    Parameters
    ----------
    x, y : str or array-like
        Data or names of variables in `data`.
        These variables correspond to the x-y coordinates
        in the euclidean space.

    images : str or array-like
        Image arrays or names of the column pointing to the
        image paths within `data`.

    data : pd.DataFrame
        Pandas dataframe holding the dataset.

    hue : str or array-like
        Data or the name of the variable to use to color
        the individual images on the grid.

    image_dir : str (default='')
        The location of the image files on disk.

    image_size : int
        The size of each image in the scatter plot.

    padding : int, optional
        The padding between images in the grid.

    n_jobs : int (default=1)
        The number of parallel workers to use for loading
        the image files.

    Returns
    -------
    A properly shaped NxWx3 image with any necessary padding.

    Examples
    --------

    Create a grid plot with hue labels.

    .. plot:: ../examples/scatter_grid.py
    """
    x_var = data_utils.get_variable(data, x)
    y_var = data_utils.get_variable(data, y)

    # TODO (seaborn is only required for a color palette. Remove this)
    if hue is not None:
        images = data_utils.get_images(
            data, images,
            image_dir=image_dir,
            as_image=False,
            image_size=image_size,
            n_jobs=n_jobs)

        hue = data_utils.get_variable(data, hue)
        values, value_map = np.unique(hue, return_inverse=True)
        palette = sns.husl_palette(len(values))
        images = [features.color_image(img, hue=palette[val]) for
                  img, val in zip(images, value_map)]
        images = [image_io.to_pillow_image(img) for img in images]
    else:
        # load images
        images = data_utils.get_images(
            data, images,
            image_dir=image_dir,
            as_image=True,
            image_size=image_size,
            n_jobs=n_jobs)

    return images_to_scatter_grid(images, x_var, y_var, padding=padding, **kwargs)


import os
import numpy as np
import pickle
from dataclasses import dataclass
import itertools
from multiprocessing import Pool
import PIL

from noise_reducers.grayscale_gibbs_noise_reducer import GrayscaleGibbsNoiseReducer
from noise_reducers.grayscale_gradient_noise_reducer import GrayscaleGradientNoiseReducer
from noise_reducers import image_utils

@dataclass
class Experiment(object):
    experiment_name: str
    noise_level: float

EXPERIMENTS = [
    Experiment(experiment_name="size800_noise10_flipped", noise_level=0.1),
    Experiment(experiment_name="size800_noise20_flipped", noise_level=0.2),
]
IMAGES_PATH = "../grayscale_images"
IMAGES_PER_EXPERIMENT = 20
ITERATIONS_PER_EXPERIMENT = 300_000
ITERATIONS_PER_EVALUATION = 6000

@dataclass
class ImagePair(object):
    image_id: int
    ground_truth: np.ndarray
    observation: np.ndarray

def get_image_pairs_to_evaluate(experiment_name):
    images_path = os.path.join(IMAGES_PATH, experiment_name)
    image_pairs = []
    for image_id in range(IMAGES_PER_EXPERIMENT):
        ground_truth_path = os.path.join(images_path, f"image_{image_id}_ground_truth.png")
        observation_path = os.path.join(images_path, f"image_{image_id}_observation.png")
        image_pairs.append(ImagePair(
            image_id=image_id,
            ground_truth=image_utils.load_grayscale_image_as_numpy_array(ground_truth_path),
            observation=image_utils.load_grayscale_image_as_numpy_array(observation_path),
        ))
    return image_pairs

def run_with_reducer(reducer, experiment_name, storage_folder):
    os.makedirs(storage_folder, exist_ok=True)
    for image_pair in get_image_pairs_to_evaluate(experiment_name):
        reduction_result = reducer.reduce_noise(
            original_image=image_pair.ground_truth, observation=image_pair.observation,
        )
        reduced_image = PIL.Image.fromarray(reduction_result.reduced_image.astype(np.uint8))
        reduced_image.save(os.path.join(storage_folder, f"reduced_image_{image_pair.image_id}.png"), format="PNG")
    with open(os.path.join(storage_folder, "average_statistics.pickle"), mode="wb") as file_stream:
        pickle.dump(reducer.average_statistics, file_stream)

def run_with_gibbs_reducer(experiment):
    print(f"Gibbs sampling for experiment {experiment.experiment_name} started!")
    reducer = GrayscaleGibbsNoiseReducer(
        noise_level_prior=experiment.noise_level, observation_strength=1.0, coupling_strength=4.0,
        iterations_count=ITERATIONS_PER_EXPERIMENT, iterations_per_evaluation=ITERATIONS_PER_EVALUATION,
    )
    storage_folder = os.path.join(
        IMAGES_PATH, experiment.experiment_name, f"grayscale_gibbs_reducer_{round(experiment.noise_level * 100)}"
    )
    run_with_reducer(reducer, experiment.experiment_name, storage_folder)
    print(f"Gibbs sampling for experiment {experiment.experiment_name} done!")

def run_with_gradient_reducer(experiment):
    print(f"Gradient-based sampling for experiment {experiment.experiment_name} started!")
    reducer = GrayscaleGradientNoiseReducer(
        noise_level_prior=experiment.noise_level, observation_strength=1.0, coupling_strength=4.0, temperature=2.0,
        iterations_count=ITERATIONS_PER_EXPERIMENT, iterations_per_evaluation=ITERATIONS_PER_EVALUATION,
    )
    storage_folder = os.path.join(
        IMAGES_PATH, experiment.experiment_name, f"grayscale_gradient_reducer_{round(experiment.noise_level * 100)}"
    )
    run_with_reducer(reducer, experiment.experiment_name, storage_folder)
    print(f"Gradient-based sampling for experiment {experiment.experiment_name} done!")

def run_with_reducer_type(experiment, reducer_type):
    if reducer_type == "gibbs":
        run_with_gibbs_reducer(experiment)
    elif reducer_type == "gradient":
        run_with_gradient_reducer(experiment)
    else:
        raise ValueError("Invalid type of reducer")

def run_script():
    arguments_to_run = list(itertools.chain(
        zip(EXPERIMENTS, ["gibbs"] * len(EXPERIMENTS)),
        zip(EXPERIMENTS, ["gradient"] * len(EXPERIMENTS)),
    ))
    with Pool(processes=6) as pool:
        pool.starmap(run_with_reducer_type, arguments_to_run)

if __name__ == "__main__":
    run_script()


"""By: Xiaochi (George) Li: github.com/XC-Li"""
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import ParseError
from bs4 import BeautifulSoup

def bs_parser(file_name, target_id):
    """
    XML Parser implemented by Beautiful Soup Package
        Args:
        file_name(str): path to the document
        target_id(str): the person_id of speaker of target document
    Returns:
        speech(str): the speech of the speaker
    """
    text_list = []
    with open(file_name, encoding='utf-8') as file:
        soup = BeautifulSoup(file, 'xml')
        target_speech = soup.find_all('speaker', personId=target_id)
        if len(target_speech) > 1:
            pass
            # print('multiple speech:', target_id, file_name)
        for item in target_speech:
            # s = item.get_text(strip=False)  # this will cause the string in subtag concatenated together
            for s in item.stripped_strings:  # bug fix: fix the problem on previous line
                text_list.append(s)
    return ' '.join(text_list)

def xml_parser(file_name, target_id):
    """
    XML Parser implemented by xml package
    Args:
        file_name(str): path to the document
        target_id(str): the person_id of speaker of target document
    Returns:
        speech(str): the speech of the speaker
    """
    try:
        tree = ET.parse(file_name, ET.XMLParser(encoding='utf-8'))
        root = tree.getroot()
    except ParseError:
        with open(file_name, encoding='utf-8') as temp:
            file_data = temp.read()
            file_data = file_data.replace('&', 'and')
            root = ET.fromstring(file_data)

    text_list = []
    for child in root[0]:
        if child.tag == 'speaker':
            if 'personId' in child.attrib:  # contain person ID
                person_id = child.attrib['personId']
            else:
                continue
            if str(person_id) != str(target_id):  # multiple speaker in a document, not target speaker
                continue
            for item in child.findall('p'):
                if len(item) == 0:
                    text_list.append(item.text)
                else:  # multiple sub tag inside 'p' tag
                    if item.text is not None:
                        text_list.append(item.text)
                        text_list.append(' ')
                    for i in item:
                        if i.text is not None:
                            text_list.append(i.text)
                            text_list.append(' ')
                        if i.tail is not None:
                            text_list.append(i.tail)
                            text_list.append(' ')

    return ''.join(text_list)

def xml_to_person_id(file_name):
    """
    NO LONGER USEFUL
    XML parser to get the person_ids from given XML file
    Args:
        file_name(str): file name
    Returns:
        person_ids(set[int]): a set of person ids
    """
    person_ids = set()
    with open(file_name, encoding='utf-8') as file:
        soup = BeautifulSoup(file, 'xml')
        all_speech = soup.find_all('speaker')
        for single_speech in all_speech:
            try:
                person_ids.add(single_speech['personId'])
            except KeyError:
                continue
    return person_ids

def get_person_speech_pair(file_name):
    """
    XML parser to get the person_ids from given XML file
    Args:
        file_name(str): file name
    Returns:
        person_id_speech_pair(dict): Dict[person_id(int) -> speech(str)]
    """
    person_id_speech_dict = dict()
    with open(file_name, encoding='utf-8') as file:
        soup = BeautifulSoup(file, 'xml')
        all_speech = soup.find_all('speaker')
        for single_speech in all_speech:
            try:  # newer format
                person_id = single_speech['personId']
            except KeyError:
                try:  # older format
                    person_id = single_speech['person']
                except KeyError:
                    continue
            single_speech_list = []
            for s in single_speech.stripped_strings:
                single_speech_list.append(s)
            processed_speech = ' '.join(single_speech_list)
            #             print(parsed_speech, '\n')
            if person_id not in person_id_speech_dict:
                person_id_speech_dict[person_id] = []
            person_id_speech_dict[person_id].append(processed_speech)

    for person_id in person_id_speech_dict:
        person_id_speech_dict[person_id] = ' '.join(person_id_speech_dict[person_id])
    return person_id_speech_dict

if __name__ == '__main__':
    # Sample: multiple sub-tag inside p tag
    # print(xml_parser('../opinion_mining/cr_corpus/160/8/E63-E64/4407923.xml', '404'))
    # print(bs_parser('../opinion_mining/cr_corpus/160/8/E63-E64/4407923.xml', '404'))
    print(get_person_speech_pair("D:\\Github\\FN-Research-GW-Opinion-Mining\\opinion_mining\\cr_corpus\\146\\4\\E8-E10\\27718.xml"))


from api.core.workflow import workflow
from flask import request

import api.DAL.data_context.admin.user_update as user_update
import api.DAL.data_context.admin.user_insert as user_insert
import api.DAL.data_context.admin.user_select as user_select

from api.core.admin.credentials import Credentials
from api.core.admin.token import Token

from api.core.admin.validate import InvalidCredential
import api.core.admin.validate as validate

import api.core.response as response
import api.core.sanitize as sanitize

import json

@workflow.route('/admin/register', methods = ['POST'])
def register_user():

    '''Called when adding a new user to the database. Makes sure that all information
    provided is valid(see individual validations for details) and hashes the password for storage'''

    credentials_form = json.loads(request.form['payload'])
    credentials_form = sanitize.form_keys(credentials_form)

    credentials = Credentials.map_from_form(credentials_form)

    try:
        validate.email(credentials.email)
        validate.name(credentials.first_name)
        validate.name(credentials.last_name)
        validate.password(credentials.password)

    except InvalidCredential as invalid:
        return response.error(invalid.args[0])

    credentials.hash_password()

    user_insert.new_user(credentials)

    return login()

@workflow.route('/admin/login', methods = ['POST'])
def login():

    '''Called when a user is loging in (shocker)
    Checks the provided email and password with the values stored in the database'''

    credentials_form = json.loads(request.form['payload'])
    credentials_form = sanitize.form_keys(credentials_form)

    provided_credentials = Credentials.map_from_form(credentials_form)
    stored_credentials = user_select.login_credentials(provided_credentials)

    try:
        validate.login(stored_credentials, provided_credentials)

    except InvalidCredential as invalid:
        return response.error(invalid.args[0])

    token = Token()
    token.user_id = stored_credentials.id
    token.update()

    user_update.token(token)

    return response.add_token(token = token)


# -*- coding: utf-8 -*-
# @Author  : Devin Yang(pistonyang@gmail.com), Gary Lai (glai9665@gmail.com)
__all__ = ['CosineWarmupLr', 'get_cosine_warmup_lr_scheduler', 'get_layerwise_decay_params_for_bert']

from math import pi, cos
from torch.optim.optimizer import Optimizer
from torch.optim.lr_scheduler import LambdaLR

class Scheduler(object):
  def __init__(self):
    raise NotImplementedError

  def get_lr(self):
    raise NotImplementedError

  def state_dict(self):
    """Returns the state of the scheduler as a :class:`dict`.

    It contains an entry for every variable in self.__dict__ which
    is not the optimizer.
    """
    return {key: value for key, value in self.__dict__.items() if key != 'optimizer'}

  def load_state_dict(self, state_dict):
    """Loads the schedulers state.

    Arguments:
        state_dict (dict): scheduler state. Should be an object returned
            from a call to :meth:`state_dict`.
    """
    self.__dict__.update(state_dict)

class CosineWarmupLr(Scheduler):
    """Cosine lr decay function with warmup.

    Lr warmup is proposed by `
        Accurate, Large Minibatch SGD:Training ImageNet in 1 Hour`
        `https://arxiv.org/pdf/1706.02677.pdf`

    Cosine decay is proposed by `
        Stochastic Gradient Descent with Warm Restarts`
        `https://arxiv.org/abs/1608.03983`

    Args:
        optimizer (Optimizer): optimizer of a model.
        batches_per_epoch (int): batches per epoch.
        epochs (int): epochs to train.
        base_lr (float): init lr.
        target_lr (float): minimum(final) lr.
        warmup_epochs (int): warmup epochs before cosine decay.
        warmup_lr (float): warmup starting lr.
        last_iter (int): init iteration.

    Attributes:
        niters (int): number of iterations of all epochs.
        warmup_iters (int): number of iterations of all warmup epochs.

    """
    def __init__(self,
                 optimizer,
                 batches: int,
                 epochs: int,
                 base_lr: float,
                 target_lr: float = 0,
                 warmup_epochs: int = 0,
                 warmup_lr: float = 0,
                 last_iter: int = -1):
        if not isinstance(optimizer, Optimizer):
            raise TypeError('{} is not an Optimizer'.format(type(optimizer).__name__))
        self.optimizer = optimizer
        if last_iter == -1:
            for group in optimizer.param_groups:
                group.setdefault('initial_lr', group['lr'])
            last_iter = 0
        else:
            for i, group in enumerate(optimizer.param_groups):
                if 'initial_lr' not in group:
                    raise KeyError("param 'initial_lr' is not specified "
                                   "in param_groups[{}] when resuming an optimizer".format(i))
        self.baselr = base_lr
        self.learning_rate = base_lr
        self.total_iters = epochs * batches
        self.targetlr = target_lr
        self.total_warmup_iters = batches * warmup_epochs
        self.total_cosine_iters = self.total_iters - self.total_warmup_iters
        self.total_lr_decay = self.baselr - self.targetlr
        self.warmup_lr = warmup_lr
        self.last_iter = last_iter
        self.step()

    def get_lr(self):
        if self.last_iter < self.total_warmup_iters:
            return self.warmup_lr + \
                (self.baselr - self.warmup_lr) * self.last_iter / self.total_warmup_iters
        else:
            cosine_iter = self.last_iter - self.total_warmup_iters
            cosine_progress = cosine_iter / self.total_cosine_iters
            return self.targetlr + self.total_lr_decay * \
                (1 + cos(pi * cosine_progress)) / 2

    def step(self, iteration=None):
        """Update status of lr.

        Args:
            iteration(int, optional): now training iteration of all epochs.
                Usually no need to set it manually.
        """
        if iteration is None:
            iteration = self.last_iter + 1
        self.last_iter = iteration
        self.learning_rate = self.get_lr()
        for param_group in self.optimizer.param_groups:
            param_group['lr'] = self.learning_rate

def get_cosine_warmup_lr_scheduler(optimizer : Optimizer,
                 batches_per_epoch: int,
                 epochs: int,
                 warmup_epochs: int = 0,
                 last_epoch: int = -1):
  """Similar to CosineWarmupLr, with support for different learning rate for different parameter groups as well as better compatibility with current PyTorch API

  Args:
        optimizer (Optimizer): optimizer of a model.
        batches_per_epoch (int): batches per epoch.
        epochs (int): epochs to train.
        warmup_epochs (int): warmup epochs before cosine decay.
        last_epoch (int): the index of the last epoch when resuming training.

  Example:
    ```
    batches_per_epoch = 10
    epochs = 5
    warmup_epochs = 1
    params = get_layerwise_decay_params_for_bert(model)
    optimizer = optim.SGD(params, lr=3e-5)
    lr_scheduler = get_cosine_warmup_lr_scheduler(optimizer, batches_per_epoch, epochs, warmup_epochs=warmup_epochs)
    ```
  """
  total_steps = epochs * batches_per_epoch
  # warmup params
  total_warmup_steps = batches_per_epoch * warmup_epochs
  # cosine params
  total_cosine_steps = total_steps - total_warmup_steps

  def lr_lambda(current_step):
    # lr_lambda should return current lr / top learning rate
    if current_step < total_warmup_steps:
      warmup_progress = current_step / total_warmup_steps
      return warmup_progress
    else:
      cosine_step = current_step - total_warmup_steps
      cosine_progress = cosine_step / total_cosine_steps
      return (1 + cos(pi * cosine_progress)) / 2
  return LambdaLR(optimizer, lr_lambda, last_epoch)

def get_differential_lr_param_group(param_groups, lrs):
  """Assigns different learning rates to different parameter groups.

  Discriminative fine-tuning, where different layers of the network have different learning rates, is first proposed in
  `Jeremy Howard and Sebastian Ruder. 2018. Universal language model fine-tuning for text classification.
  https://arxiv.org/pdf/1801.06146.pdf.` It has been found to stabilize training and speed up convergence.

  Args:
    param_groups: a list of parameter groups (each of which is a list of parameters)
        param group should look like:
        [
          [param1a, param1b, ..]  <-- parameter group 1
          [param2a, param2b, ..]  <-- parameter group 2
          ...
        ]
    lrs: a list of learning rates you want to assign to each of the parameter groups
        lrs should look like
        [
          lr1, <-- learning rate for parameter group 1
          lr2, <-- learning rate for parameter group 2
          ...
        ]

  Returns:
    parameter groups with different learning rates that you can then pass into an optimizer
  """
  assert len(param_groups) == len(lrs), f"expect the learning rates to have the same lengths as the param_group length, instead got {len(param_groups)} and {len(lrs)} as lengths respectively"

  param_groups_for_optimizer = []
  for i in range(len(param_groups)):
    param_groups_for_optimizer.append({
      'params': param_groups[i],
      'lr': lrs[i]
    })
  return param_groups_for_optimizer

def get_layerwise_decay_param_group(param_groups, top_lr=2e-5, decay=0.95):
  """Assign layerwise decay learning rates to parameter groups.

  Layer-wise decay learning rate is used in `Chi Sun, Xipeng Qiu, Yige Xu, and Xuanjing Huang. 2019.
  How to fine-tune BERT for text classification? https://arxiv.org/abs/1905.05583` to improve convergence
  and prevent catastrophic forgetting.

  Args:
    param_groups: a list of parameter groups
        param group should look like:
        [
          [param1a, param1b, ..]  <-- parameter group 1
          [param2a, param2b, ..]  <-- parameter group 2
          ..
        ]
    top_lr: learning rate of the top layer
    decay: decay factor. When decay < 1, lower layers have lower learning rates; when decay == 1, all layers have the same learning rate

  Returns:
    parameter groups with layerwise decay learning rates that you can then pass into an optimizer

  Examples:
    ```
    param_groups = get_layerwise_decay_params_group(model_param_groups, top_lr=2e-5, decay=0.95)
    optimizer = AdamW(param_groups, lr = 2e-5)
    ```
  """
  lrs = [top_lr * pow(decay, len(param_groups)-1-i) for i in range(len(param_groups))]
  return get_differential_lr_param_group(param_groups, lrs)

def get_layerwise_decay_params_for_bert(model, number_of_layer=12, top_lr=2e-5, decay=0.95):
  """Assign layerwise decay learning rates to parameter groups of BERT.

  Layer-wise decay learning rate is used in `Chi Sun, Xipeng Qiu, Yige Xu, and Xuanjing Huang. 2019.
  How to fine-tune BERT for text classification? https://arxiv.org/abs/1905.05583` to improve convergence
  and prevent catastrophic forgetting.

  Args:
    model: your BERT model
    number_of_layer: number of layers your BERT has
    top_lr: learning rate of the top layer
    decay: decay factor. When decay < 1, lower layers have lower learning rates; when decay == 1, all layers have the same learning rate

  Returns:
    BERT parameter groups with different learning rates that you can then pass into an optimizer

  Example:
    ```
    param_groups = get_layerwise_decay_params_for_bert(model, number_of_layer=12, top_lr=2e-5, decay=0.95)
    optimizer = AdamW(param_groups, lr = 2e-5)
    ```
  """
  param_groups = get_param_group_for_bert(model, number_of_layer=number_of_layer, top_lr=top_lr, decay=decay)
  param_groups_for_optimizer = get_layerwise_decay_param_group(param_groups, top_lr=top_lr, decay=decay)
  return param_groups_for_optimizer

def get_param_group_for_bert(model, number_of_layer=12, top_lr=2e-5, decay=0.95):
  """separate each layer of a BERT models into a parameter group

  Args:
    model: your BERT model
    number_of_layer: number of layers your BERT has
    top_lr: learning rate of the top layer
    decay: decay factor. When decay < 1, lower layers have lower learning rates; when decay == 1, all layers have the same learning rate

  Returns:
    a param group that should look like:
        [
          ...
          [param1a, param1b, ..]  <-- parameter group 1, layer 1 of BERT
          [param2a, param2b, ..]  <-- parameter group 2, layer 2 of BERT
          ...
        ]
  """
  param_groups_for_optimizer = [[] for _ in range(number_of_layer+2)] # tail, layer0, layer1 ...., layer11, head
  head = {'pooler', 'norm', 'relative_attention_bias'}
  tail = {'embeddings',}
  layers = [f'layer.{i}.' for i in range(number_of_layer)]

  for name, param in model.named_parameters():
    if belongs(name, tail):
      param_groups_for_optimizer[0].append(param)
    elif belongs(name, head):
      param_groups_for_optimizer[-1].append(param)
    else:
      for i, layer in enumerate(layers):
        if layer in name:
          param_groups_for_optimizer[i+1].append(param)
  return param_groups_for_optimizer

def belongs(name, groups):
    """ checks if name belongs to any of the group
    """
    for group in groups:
      if group in name:
        return True
    return False


import gevent

def eat(name):
    print('%s start task' % name)
    gevent.sleep(2)
    print('%s end task' % name)
    return name + " finished callback"

def play(name):
    print('%s start task' % name)
    gevent.sleep(1)
    print('%s end task' % name)
    return name + " finished callback"

def callback(greenlet):
    print("callback successfully: " + greenlet.value)

g1 = gevent.spawn(eat, 'marcia')
g1.link(callback)
g2 = gevent.spawn(play, name='joe')
g2.link(callback)
gevent.joinall([g1, g2])
print('主')

# import gevent
# from gevent import Greenlet
#
#
# def callback_func():
#     print("callback successfully")
#
#
# class MyGreenlet(Greenlet):
#     def __init__(self, timeout, msg):
#         Greenlet.__init__(self)
#         self.timeout = timeout
#         self.msg = msg
#
#     def _run(self):
#         print("I'm from subclass of Greenlet and want to say: %s" % (self.msg,))
#         gevent.sleep(self.timeout)
#         print("done after sleep %s" % self.timeout)
#
#
# greenlet1 = MyGreenlet(2, 'hello')
# greenlet2 = MyGreenlet(1, 'world')
# greenlet1.start()
# greenlet2.start()
# greenlet1.rawlink(callback_func())
#
# gevent.joinall([greenlet1, greenlet2])
# print("main")
#


import logging

from dcs.point import MovingPoint
from dcs.task import EngageTargets, EngageTargetsInZone, Targets

from game.ato.flightplans.cas import CasFlightPlan
from game.utils import nautical_miles
from .pydcswaypointbuilder import PydcsWaypointBuilder

class CasIngressBuilder(PydcsWaypointBuilder):
    def add_tasks(self, waypoint: MovingPoint) -> None:
        if isinstance(self.flight.flight_plan, CasFlightPlan):
            patrol_center = (
                self.flight.flight_plan.layout.patrol_start.position
                + self.flight.flight_plan.layout.patrol_end.position
            ) / 2
            waypoint.add_task(
                EngageTargetsInZone(
                    position=patrol_center,
                    radius=int(self.flight.flight_plan.engagement_distance.meters),
                    targets=[
                        Targets.All.GroundUnits.GroundVehicles,
                        Targets.All.GroundUnits.AirDefence.AAA,
                        Targets.All.GroundUnits.Infantry,
                    ],
                )
            )
        else:
            logging.error("No CAS waypoint found. Falling back to search and engage")
            waypoint.add_task(
                EngageTargets(
                    max_distance=int(nautical_miles(10).meters),
                    targets=[
                        Targets.All.GroundUnits.GroundVehicles,
                        Targets.All.GroundUnits.AirDefence.AAA,
                        Targets.All.GroundUnits.Infantry,
                    ],
                )
            )


import numpy as np
from ..patch import Patch
from ..parcel import Parcel

class PropertyDeveloper:
    def __init__(self, world, agent_type, view_radius=5, memory=100):
        self.world = world
        self.view_radius = view_radius
        self.memory = memory
        self.position = np.random.choice(world.patches.flatten()) # Starts in a random patch of the map
        self.dev_sites = [] # TO DO: initialize dev_sites using starting position
        self.dev_patches = []
        self.considered_patches = []
        self.agent_type = agent_type

        # Weights for each type of developer
        ##        eh  ev  epv  dw   dr  di  dpk dpr dm   x
        self.W = {
            "r": [.1, .2,  0,  .1,  .4,  0,  0,  .2,  0,  0],
            "c": [ 0, .2,  0, .15, .15,  0,  0,  0, .4,  0],
            "i": [ 0, .5,  0,  .3,   0, .1,  0, .1,  0,  0],
            "p": [ 0,  0, .2,  .1,  .1,  0, .4,  0,  0, .2]
        }

    def getRegion(self, i, j):
        region = self.world.patches[max(1,i-self.view_radius):i+self.view_radius, # Adding padding of 1 patch
                         max(1, j-self.view_radius):j+self.view_radius].flatten()
        region = [p for p in region if p.developable] # Selecting only developable patches (excludes water, etc)

        region_parcels = []
        region_patches = []
        for patch in region:
            if (patch.parcel == None):
                region_patches.append(patch)
            elif ( patch.parcel not in region_parcels and patch.parcel.development_type != self.agent_type): # Excludes parcels of same development type as the agent (TO DO: provisory)
                region_parcels.append(patch.parcel)

        return region_patches, region_parcels

    # Searches for suitable locations in its surroundings
    def prospect(self, dev_sites):
        i, j = [self.position.i, self.position.j]
        region_patches, region_parcels = self.getRegion(i, j)
        patch_values, parcel_values = [self.world.patch_values, self.world.parcel_values]
        values = patch_values | parcel_values
        combined_region = region_patches + region_parcels

        if (len(dev_sites)!=0 and (self.last_commit>0 or self.last_relocate>0)): # Move to a seen location
            combined_region = combined_region + dev_sites # Searching in union of region and memory
            region_values = [values[p][self.agent_type] for p in combined_region]
            next_location = combined_region[np.argmax(region_values)]
        else: # Relocate globlally
            self.last_relocate = 5 # Resets relocation counter

            # Selecting all empty patches from the world
            world_patches = [p for p in self.world.patches.flatten() if p.undeveloped and p.developable]
            world_parcels = [p for p in self.world.parcels if p.development_type != self.agent_type] # TO DO: check if conversion to agent_type is possible

            world_sites = world_patches + world_parcels
            sorted_idx = np.argsort([values[p][self.agent_type] for p in world_sites])[::-1]
            world_sites = np.array(world_sites)[sorted_idx]

            # Move to a random site in the top 5 best for the agent
            try:
                next_location = np.random.choice(world_sites[:5])
            except: # No more areas to develop
                return []
            self.dev_patches = []
        self.position = next_location

        #region_patches, region_parcels = self.getRegion() # NOTE: maybe have to be updated after relocation

        # TO DO / NOTE : Check this implementation better later

        dev_parcels = region_parcels

        dev_patches = []
        for patch in self.dev_patches + region_patches:
            if patch not in dev_patches and patch.undeveloped:
                dev_patches.append(patch)
        dev_patches_sorted_idx = np.argsort([values[p][self.agent_type] for p in dev_patches])[::-1]
        dev_patches = np.array(dev_patches)[dev_patches_sorted_idx]
        self.dev_patches = list(dev_patches[:int(0.9*len(dev_patches))]) # Selecting only the 90% best patches

        dev_sites = list(dev_patches) + dev_parcels
        return dev_sites

    # Returns True if as build successfully and False otherwise
    def build(self, site):
        if (isinstance(site, Patch)): # Building in patch is direct
            self.considered_patches.append(site)
            new_parcel = self.world.createParcel(site, development_type=self.agent_type) # TO DO: expand to create parcels of multiple patches
            if (new_parcel == None):
                return False

            for patch in new_parcel.patches:
                # Preventing roads to be built on top of this patch
                self.world.addBlockedPatch(patch)

            return True
        return False

    def getScore(self, patch):
        i, j = [patch.i, patch.j]
        region_patches, region_parcels = self.getRegion(i, j)

        eh = patch.get_eh(self.world.patches)
        ev, epv = patch.get_ev(self.world.patches)
        dpr = patch.get_dpr()
        dw = patch.get_dw()
        dr = patch.get_dr(region_patches, region_parcels)
        dc = patch.get_dc(region_patches, region_parcels)
        di = patch.get_di(region_patches, region_parcels)
        dm = patch.get_dm(self.world.parcels)
        dpk = patch.get_dm(self.world.parcels)

        A = [eh, ev, epv, dw, dr, di, dpk, dpr, dm, 0]
        W = [self.W['r'], self.W['i'], self.W['i'], self.W['p']]

        Vr, Vc, Vi, _= np.dot(W, A)
        Vp = (1/Vr + 1/Vc + 1/Vi) * self.W['p'][-1] # Anti-worth

        return {'Vr': Vr, 'Vc': Vc, 'Vi': Vi, 'Vp': Vp}

    def prospectNew(self):
        i, j = [self.position.i, self.position.j]
        region_patches, region_parcels = self.getRegion(i, j)

        avaliable_patches = self.dev_patches + region_patches # Memory + new
        avaliable_patches = [p for p in avaliable_patches if p not in self.considered_patches and self.world.isAccessible(p)]

        # No more avaliable patches, relocate globaly
        while len(avaliable_patches) == 0:
            self.position = np.random.choice(self.world.patches.flatten())
            i, j = [self.position.i, self.position.j]
            region_patches, region_parcels = self.getRegion(i, j)
            avaliable_patches = [p for p in region_patches if p not in self.considered_patches and self.world.isAccessible(p)]

        scores = [self.getScore(patch)[self.agent_type] for patch in avaliable_patches]

        idx_best = np.argmax(scores)
        best_patch = avaliable_patches[idx_best]

        #print(f"Selected patch: ({best_patch.i}, {best_patch.j}), undeveloped={best_patch.undeveloped}")

        if (self.position == best_patch):
            self.build(self.position)
            print("Building")
        else:
            self.position = best_patch
            print("Relocating")

        return avaliable_patches

    def buildNew(self):
        avaliable_patches = [p for p in self.world.patches.flatten() if p.developable and p.undeveloped and p not in self.considered_patches]

        # Scoring all patches and sorting them by score
        scores = [self.getScore(p)[self.agent_type] for p in avaliable_patches]
        sorted_idx = np.argsort(scores)[::-1]
        sorted_patches = np.array(avaliable_patches)[sorted_idx]

        # Triyng to build in the best score avaliable
        built = False
        for patch in sorted_patches:
            # Checks if a patch is accessible
            if(self.build(patch)):
                break

    # Interacts with the environment
    def interact(self):
        self.dev_patches = self.prospectNew()
        self.dev_patches = self.dev_patches[:min(len(self.dev_patches), self.memory)]

        # Removing already developed patched from the list
        self.dev_patches = [p for p in self.dev_patches if p.developable]

        '''
        self.build(self.position) # My version

        #for site in self.dev_sites: # Paper implementation
        #    self.build(site)

        # Decreases counters
        self.last_commit -= 1
        self.last_relocate -= 1
        '''

        #print(f"Current position: {self.position.i}, {self.position.j}")


import pygame as pg

from gui.widgets.animated_widget import AnimatedWidget
from data.constants import *

class BackgroundImage(AnimatedWidget):
    def __init__(self, x, y, w, h, image):
        super().__init__()
        self.pos = x, y
        self.image = pg.transform.smoothscale(pg.image.load(image).convert_alpha(), (w, h))

    def update(self, dt, animation_state=WAIT, time_elapsed=0.0):
        if animation_state == WAIT and self.image.get_alpha() !=255:
            self.image.set_alpha(255)
        elif animation_state == OPEN:
            self.image.set_alpha(round(255 * time_elapsed))
        elif animation_state == CLOSE:
            self.image.set_alpha(round(255 * (1 - time_elapsed)))

    def draw(self, screen, animation_state=WAIT):
        screen.blit(self.image, self.pos)

__all__ = ["BackgroundImage"]


"""Assorted algorithms to verify end-to-end compiler functionality.

These tests include:
 - Sum of array of integers
 - Recursive Fibonacci sum
"""

import pytest
import tempfile
import functools
import os

from acctools import compilers

ACC_PATH=os.environ.get("ACC_PATH", os.path.join(os.path.dirname(__file__), "../build/acc"))

COMPILERS = [
    compilers.GccCompiler,
    functools.partial(compilers.AccIrCompiler, ACC_PATH, regalloc=False),
    functools.partial(compilers.AccIrCompiler, ACC_PATH, regalloc=True),
    functools.partial(compilers.AccAsmCompiler, ACC_PATH)
]

@pytest.fixture(params=COMPILERS)
def cc(request):
    with tempfile.NamedTemporaryFile() as temp_file:
        return request.param(temp_file.name)

CALCULATE_SUM = """
int calc_sum(unsigned char * arr, int n)
{
    int i = 0, tot = 0;
    while(i < n)
    {
        tot += arr[i++];
    }
    return tot;
}
int main()
{
    unsigned char arr[7];
    arr[0] = 1;
    arr[1] = 2;
    arr[2] = 4;
    arr[3] = 8;
    arr[4] = 16;
    arr[5] = 32;
    arr[6] = 64;

    return calc_sum(arr, 7);
}
"""

def test_calculate_array_sum(cc):
    cc.program(CALCULATE_SUM, returncode=127);

FIBONACCI = """
int fib(int n)
{
    if(n == 0) return 1;
    if(n == 1) return 1;
    return fib(n-1) + fib(n-2);
}
int main()
{
    int i = 0, tot = 0;
    while(i < 10)
    {
        tot += fib(i);
        i++;
    }
    return tot;
}
"""

def test_fibonacci(cc):
    cc.program(FIBONACCI, returncode=143)

INSERTION_SORT = """
int sort(int * arr, int n)
{
    int i = 1;
    while(i < n)
    {
        int t = arr[i];
        int j = i - 1;
        while((t < arr[j]) & (j != -1))
        {
            arr[j+1] = arr[j];
            j--;
        }
        arr[j+1] = t;
        i++;
    }
}
int main()
{
    int l[10];
    l[0] = 3;
    l[1] = 8;
    l[2] = 9;
    l[3] = 121;
    l[4] = 28;
    l[5] = 1;
    l[6] = 89;
    l[7] = 90;
    l[8] = 104;
    l[9] = 101;

    sort(l, 10);
    return (l[0] != 1) | (l[9] != 121);
}
"""

def test_sort(cc):
    cc.program(INSERTION_SORT)


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

import logging
import time
import gzip
import random

from six.moves.urllib.error import URLError
from six.moves.urllib.request import Request, build_opener, HTTPCookieProcessor
from six.moves.urllib.parse import urlencode
from six.moves.http_cookiejar import CookieJar
from six.moves import StringIO

# pysocks
import socks
from sockshandler import SocksiPyHandler

logger = logging.getLogger(__name__)

def get_user_agent(idx=-1):
    user_agent = [
        'Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130619 Firefox/17.0',
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36',
    ]
    if idx < 0:
        idx = random.randint(0, len(user_agent) - 1)
    return user_agent[idx]

def url_downloader(url, data=None, path=None, cookie=None,
                   timeout=5, retry=1, retry_ivl=5,
                   referer=None, agent=None, proxy=None):
    """Download URL link
    url:    url to download
    data:   post data
    path:   download to local file
    timeout:    socket timeout
    retry:  retry times to download url
    retry_ivl:  interval time when retry
    agent:  http user agent
    proxy:  socks5://127.0.0.1:1080
    """
    while True:
        try:
            if isinstance(data, dict):
                data = urlencode(data).encode('ascii')
            request = Request(url, data=data)
            request.add_header('User-Agent', agent or get_user_agent())
            if referer:
                request.add_header('Referer', referer)
            if data:
                request.add_header(
                    'Content-Type',
                    'application/x-www-form-urlencoded;charset=utf-8')
            response = None
            handlers = []
            if proxy:
                scheme, host, port = proxy.split(':')
                host = host.strip('/')
                proxy_handler = SocksiPyHandler(
                    socks.PROXY_TYPES[scheme.upper()], host, int(port)
                )
                handlers.append(proxy_handler)
            if cookie is None:
                cookie = CookieJar()
            cookie_handler = HTTPCookieProcessor(cookie)
            handlers.append(cookie_handler)

            opener = build_opener(*handlers)
            response = opener.open(request, timeout=timeout)
            content_encoding = response.info().get('content-encoding')
            if content_encoding:
                with gzip.GzipFile(fileobj=StringIO(response.read())) as f:
                    r_data = f.read()
            else:
                r_data = response.read()
            if path:
                with open(path, 'wb') as f:
                    f.write(r_data)
                r_data = None
            response.close()
            mime = response.info().get('content-type')
            real_url = response.geturl()
            err_msg = 'Ok'
            break
        except (URLError, IOError, OSError) as err:
            response and response.close()
            retry -= 1
            err_msg = str(err)
            if retry > 0:
                logger.debug('Error: %s... Try again after %s seconds' % (
                    retry_ivl, err_msg))
                time.sleep(retry_ivl)
                retry_ivl += retry_ivl
                timeout += timeout
            else:
                path = mime = r_data = real_url = None
                break
    return {
        'mime': mime,
        'path': path,
        'data': r_data,
        'url': real_url,
        'cookie': cookie,
        'error': err_msg,
    }


from setuptools import setup
# To use a consistent encoding
from codecs import open
from os import path

with open('README.rst') as f:
    long_desc = f.read()

setup(name='glucid',
      version='0.5.0',
      description='Configure the Lucid 8824 AD/DA Audio Interface via \
             a Serial Connection',
      url='http://github.com/danmechanic/glucid',
      author='Daniel R Mechanic',
      author_email='dan.mechanic@gmail.com',
      license='GPL V3',
      zip_safe=False,
#      scripts=['bin/glucid','bin/xglucid'],
      entry_points={  # Optional
          'console_scripts': [
              'glucid=glucid.glucid_cli:main',
              'xglucid=glucid.xglucid:main'
          ],
      },
      long_description=long_desc,
      keywords='lucid 8824 audio converter',
      packages=['glucid'],
#      py_modules=['glucid.glucid'],
      python_requires=">=3",
      package_dir={ 'glucid8824' : 'glucid',
                    'xglucid' : 'glucid',
                    'Glucid8824_UI' : 'glucid',
                    'Glucid8824' : 'glucid',
                    'xglucidUIWidgets' : 'glucid',
      },
      long_description_content_type='text/x-rst',
      classifiers=[
          'Development Status :: 3 - Alpha',
          'Programming Language :: Python :: 3',
          'Programming Language :: Python :: 3.2',
          'Programming Language :: Python :: 3.3',
          'Programming Language :: Python :: 3.4',
          'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
          'Topic :: Multimedia :: Sound/Audio :: Conversion',
          'Topic :: Multimedia :: Sound/Audio :: Capture/Recording',
      ],
      project_urls={
          'Author': 'http://www.danmechanic.com/',
          'Source': 'https://github.com/danmechanic/glucid/',
      },
      install_requires=[
          'PyQt5>=5.9',
	  'PySerial',
      ]
      )


import logging
import warnings
import torch
import numpy as np

from data import data_utils
from data.ofa_dataset import OFADataset

logger = logging.getLogger(__name__)
warnings.filterwarnings("ignore", "(Possibly )?corrupt EXIF data", UserWarning)

def collate(samples, pad_idx, eos_idx):
    if len(samples) == 0:
        return {}

    def merge(key):
        return data_utils.collate_tokens(
            [s[key] for s in samples],
            pad_idx,
            eos_idx=eos_idx,
        )

    src_tokens = merge("source")
    src_lengths = torch.LongTensor([s["source"].ne(pad_idx).long().sum() for s in samples])

    prev_output_tokens = None
    target = None
    if samples[0].get("target", None) is not None:
        target = merge("target")
        tgt_lengths = torch.LongTensor(
            [s["target"].ne(pad_idx).long().sum() for s in samples]
        )
        ntokens = tgt_lengths.sum().item()

        if samples[0].get("prev_output_tokens", None) is not None:
            prev_output_tokens = merge("prev_output_tokens")
    else:
        ntokens = src_lengths.sum().item()

    target_strs = np.array([s["target_str"] for s in samples])

    batch = {
        "nsentences": len(samples),
        "ntokens": ntokens,
        "net_input": {
            "src_tokens": src_tokens,
            "src_lengths": src_lengths,
            "prev_output_tokens": prev_output_tokens
        },
        "target": target,
        "target_strs": target_strs
    }

    return batch

class SummaryDataset(OFADataset):
    def __init__(
            self,
            split,
            dataset,
            bpe,
            src_dict,
            tgt_dict=None,
            code_dict_size=8192,
            num_bins=1000,
            max_src_length=512,
            max_tgt_length=128,
            noise_ratio=0.0,
            description='base'
    ):
        super().__init__(split, dataset, bpe, src_dict, tgt_dict)
        self.max_src_length = max_src_length
        self.max_tgt_length = max_tgt_length
        self.code_dict_size = code_dict_size
        self.num_bins = num_bins
        self.noise_ratio = noise_ratio
        self.description = description
        if type(bpe).__name__ == 'GPT2BPE':
            if self.description == 'base':
                self.prompt = ' what is the summary of article " {} "?'
            elif self.description == 'tep':
                self.prompt = 'Dataset description: Gigaword is a large-scale dataset for natural language processing tasks, such as language modeling and machine translation. It contains over 5 billion words of text, drawn from a variety of sources, including news articles, books, and websites.The annotation process for Gigaword involves collecting text from a variety of sources and ensuring that it is accurately' \
                              ' transcribed and formatted. The text is then divided into smaller units, such as sentences or paragraphs, and annotated with additional information, such as part-of-speech tags or named entity tags. ' \
                              'Input format: Text' \
                              'Output format: Text' \
                              'Output description: summary of input text' \
                              'prompt: what is the summary of article " {} "? '

            elif self.description == 'wiki-tep':
                self.prompt = 'Given a document, selecting a subset of the words or sentences which best represents a summary of the document.' \
                              'Dataset description: Gigaword is a large-scale dataset for natural language processing tasks, such as language modeling and machine translation. It contains over 5 billion words of text, drawn from a variety of sources, including news articles, books, and websites.The annotation process for Gigaword involves collecting text from a variety of sources and ensuring that it is accurately' \
                              ' transcribed and formatted. The text is then divided into smaller units, such as sentences or paragraphs, and annotated with additional information, such as part-of-speech tags or named entity tags. ' \
                              'Input format: Text' \
                              'Output format: Text' \
                              'Output description: summary of input text' \
                              'prompt: what is the summary of article " {} "? '

            elif self.description == 'annotation':
                self.prompt = \
                    'Dataset description: Gigaword is a large-scale dataset for natural language processing tasks, such as language modeling and machine translation. It contains over 5 billion words of text, drawn from a variety of sources, including news articles, books, and websites.The annotation process for Gigaword involves collecting text from a variety of sources and ensuring that it is accurately' \
                    ' transcribed and formatted. The text is then divided into smaller units, such as sentences or paragraphs, and annotated with additional information, such as part-of-speech tags or named entity tags. ' \
                    'Input format: Text' \
                    'Output format: Text' \
                    'Output description: summary of input text' \
                    'prompt: what is the summary of article " {} "? '

            elif self.description == 'wiki':
                self.prompt = \
                    'Given a document, selecting a subset of the words or sentences which best represents a summary of the document.' \
                    'prompt: what is the summary of article " {} "? '

            elif description == 'onehot':
                self.prompt = '1000000 {}'

        elif type(bpe).__name__ == 'BertBPE':

            self.prompt = "{} 请用一个句子简单总结上文："

    def __getitem__(self, index):
        source, target = self.dataset[index]
        target_str = target.lower()

        source = self.pre_caption(source, max_words=self.max_src_length)
        target = self.pre_caption(target, max_words=self.max_tgt_length)
        source = source.replace('<unk>', 'unk')
        target = target.replace('<unk>', 'unk')

        src_item = self.encode_text(
            self.prompt.format(source),
            length=self.max_src_length
        )
        tgt_item = self.encode_text('{}'.format(target))
        noise_tgt_item = self.add_noise_to_tgt(tgt_item.clone(), self.noise_ratio)

        src_item = torch.cat([self.bos_item, src_item, self.eos_item])
        target_item = torch.cat([tgt_item, self.eos_item])
        prev_output_item = torch.cat([self.bos_item, noise_tgt_item])

        example = {
            "source": src_item,
            "target": target_item,
            "prev_output_tokens": prev_output_item,
            "target_str": target_str
        }
        return example

    def add_noise_to_tgt(self, target, p):
        noise_indices = torch.FloatTensor(target.size(0)).uniform_() < p
        target[noise_indices] = torch.randint(
            4, len(self.src_dict) - self.code_dict_size - self.num_bins, size=(noise_indices.sum(),)
        )
        return target

    def collater(self, samples, pad_to_length=None):
        """Merge a list of samples to form a mini-batch.
        Args:
            samples (List[dict]): samples to collate
        Returns:
            dict: a mini-batch containing the data of the task
        """
        return collate(samples, pad_idx=self.pad, eos_idx=self.eos)


'''
商品详情页面
'''
from common.base import Base

good_url ='http://ecshop.itsoso.cn/goods.php?id=304'

class Buy_Good(Base):
    '''页面点击立即购买'''
    # 商品名字
    good_name_loc=('class name','goods_style_name')
    # 商品牌子
    good_brand_loc=('css selector','a[href="brand.php?id=20"]')
    # 购买数量框
    number_loc=('id','number')
    # 立即购买框
    libuy_loc=('css selector','img[src="themes/default/images/buybtn1.png"]')
    # 收藏按钮
    collect_loc=('css selector','img[src="themes/default/images/bnt_colles.gif"]')
    # 分享按钮
    share_loc =('css selector','img[src="themes/default/images/bnt_recommend.gif"]')
    # 价格
    price_loc=('id','ECS_RANKPRICE_6')

    # 前台商品货号
    front_good_no_loc=('css selector','li.clearfix:nth-child(1)>dd:nth-child(1)')

    # 点击商品牌子
    def click_brand(self):
        self.click(self.good_brand_loc)

    # 购买数量输入
    def send_number(self,num):

        self.double_click(self.number_loc)
        self.send_keys(self.number_loc,num)
        self.click(self.price_loc)
    # 点击立即购买
    def click_libuy(self):
        self.click(self.libuy_loc)

    # 点击收藏按钮
    def click_collect(self):
        self.click(self.collect_loc)

    # 点击分享按钮
    def click_share(self):
        self.click(self.share_loc)

    # 获取商品名称
    def get_good_name(self,locator):
        element =self.find_element(locator)
        text = element.text
        return text

    # 前台商品详情页面获取商品货号
    def get_front_good_no(self):
        element=self.find_element(self.front_good_no_loc)
        content =element.text.split('：')
        text =content[1]   # ECS000304
        # print(content)  商品货号：ECS000304
        return text

if __name__ == '__main__':
    from common.base import open_browser
    from time import sleep
    driver = open_browser('chrome')
    libuy = Buy_Good(driver)  # 实例化Buy_Good
    libuy.open_url(good_url)
    good_name_loc = ('class name', 'goods_style_name')
    print(libuy.get_good_name(good_name_loc))

    # 前台商品货号
    front_good_no_loc = ('css selector', 'li.clearfix:nth-child(1)>dd:nth-child(1)')
    num =libuy.get_front_good_no()
    print(num)
    # sleep(2)
    # libuy.send_number(3)
    # sleep(3)
    #
    #
    # libuy.click_libuy()


import logging

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Logger(object):
    __metaclass__ = Singleton

    def __init__(self):
        self._logger = logging.getLogger('[WikiTopK]')
        self._logger.setLevel(logging.INFO)
        formatter1 = logging.Formatter('%(name)s - %(message)s')
        fh = logging.FileHandler('log/debug.log',mode='w')
        fh.setLevel(logging.ERROR)
        fh.setFormatter(formatter1)
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(formatter1)

        self._logger.addHandler(fh)
        self._logger.addHandler(ch)


import argparse as _argparse
import os as _os
import sys as _sys

from colorama import Fore as _Fore
from colorama import init as _colorama_init
from contexttimer import Timer as _Timer

from src import merge as _merge
from src import parse as _parse

if __name__ == '__main__':
    """
        Example: python merge.py --in pss_api_ios_v0.989.9402_anonymized.json pss_api_steam_v0.991.4_anonymized.json --out examples
    """

    # enable Windows support of colors
    _colorama_init()

    ERR_INPUT_NOT_FOUND = 1

    parser = _argparse.ArgumentParser()
    parser.add_argument('--in', dest='in_', type=str, nargs='+', required=True, help='Path(s) to the flows file(s) to be merged')
    parser.add_argument('--overrides', type=str, required=False, help='Path to the overrides file')
    parser.add_argument('--outfile', type=str, required=True, help='Target file path for the merged flows file')
    parser.add_argument('--uncompressed', action='store_true', help='Preserve whitespace in the output file')
    args = parser.parse_args()

    error = False
    for file_path in args.in_:
        if not _os.path.isfile(file_path):
            print(f'{_Fore.RED}ERROR: Specified flows JSON file does not exist: {file_path}{_Fore.RESET}')
    if error:
        _sys.exit(ERR_INPUT_NOT_FOUND)

    with _Timer() as t:
        print(f'{_Fore.YELLOW} >>>{_Fore.RESET} Input files:')
        for in_ in args.in_:
            print(f'{_Fore.YELLOW} >>> -{_Fore.RESET} {in_}')
        print(f'{_Fore.YELLOW} >>>{_Fore.RESET} Output file: {args.outfile}')
        print(f'{_Fore.YELLOW} >>>{_Fore.RESET} Compressed storage: {"No" if args.uncompressed else "Yes"}')
        print(f'{_Fore.BLUE} >>>{_Fore.RESET} Merging parsed flows...')

        result = _merge.read_structure_json(args.in_[0])
        for merge_with in args.in_[1:]:
            result = _merge.merge_api_structures(
                result,
                _merge.read_structure_json(merge_with)
            )
        if args.overrides:
            overrides = _merge.read_structure_json(args.overrides)
            result = _merge.apply_overrides(result, overrides)
        _parse.store_structure_json(
            args.outfile,
            result,
            (not args.uncompressed)
        )

        print(f'{_Fore.BLUE} >>>{_Fore.RESET} Done in {t.elapsed}s')
        _sys.exit(0)


import anki
from aqt import mw
import re

col = anki.collection.Collection('C:/Users/clept/AppData/Roaming/Anki2/Iván/collection.anki2')

deck_name = 'Seguridad social test'

search_query = '"deck:' + deck_name + '"'

cards = col.find_cards(search_query)

for card_id in cards:

    # Get the card
    card = col.get_card(card_id)

    # Get the note associated with the card
    note = card.note()

    # bb = 'd (artículo 76.0)'
    text = note['Back']

    try:

        #  matches 54.2, 2.b.0, índice
        match = re.search(r'\">[a-záéíóú ]*(\d+\.\d+|índice|\d+\.[a-z]\.\d+|\d+)', text)

        text_sort = match.group(1)

        if text_sort == 'índice':
            text_sort = '9999'

        text_sort = re.sub('(\d+)(\.[a-z])(\.\d+)', '\\1\\3', text_sort)

        if '.' not in text_sort:

            text_sort += '.99'

        if text_sort[-2] == '.':

            text_sort = text_sort[:-1] + '0' + text_sort[-1:]

        note['Sort'] = text_sort

    except:

        note['Sort'] = '9998.99'

    note.flush()

# Synchronize the collection to save changes to the Anki database
col.autosave()


import math

import torch
import torch.nn as nn

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

        position = torch.arange(max_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))
        pe = torch.zeros(max_len, 1, d_model)
        pe[:, 0, 0::2] = torch.sin(position * div_term)
        pe[:, 0, 1::2] = torch.cos(position * div_term)
        self.register_buffer("pe", pe)

    def forward(self, x):
        x = x + self.pe[: x.size(0)]
        return self.dropout(x)

class TransformerNet(nn.Module):
    def __init__(
        self,
        d_model=512,
        nhead=8,
        num_encoder_layers=6,
        num_decoder_layers=6,
        dim_feedforward=2048,
        dropout=0.1,
        batch_size=512,
    ):
        super().__init__()
        self.l1 = nn.Linear(1, d_model)
        self.l2 = nn.Linear(1, d_model)
        self.positional_encoder = PositionalEncoding(d_model, max_len=batch_size)
        self.transformer = nn.Transformer(
            d_model,
            nhead,
            num_encoder_layers,
            num_decoder_layers,
            dim_feedforward,
            dropout,
            batch_first=True,
        )
        self.l3 = nn.Linear(d_model, 1)

    def forward(self, enc_x, dec_x):
        mask = nn.Transformer.generate_square_subsequent_mask(dec_x.shape[-1]).cuda()
        enc_x = enc_x.unsqueeze(-1)  # [N, x_seq, 1]
        enc_x = self.l1(enc_x)  # [N, x_seq, d_model]
        enc_x = self.positional_encoder(enc_x)
        dec_x = dec_x.unsqueeze(-1)  # [N, t_seq, 1]
        dec_x = self.l2(dec_x)  # [N, t_seq, d_model]
        dec_x = self.positional_encoder(dec_x)
        y = self.transformer(enc_x, dec_x, tgt_mask=mask)  # [N, t_seq, d_model]
        y = self.l3(y).squeeze(-1)  # [N, t_seq]
        return y

    def test(self, enc_x, dec_x, t_seq):
        dec_x = dec_x[:, [0]]  # [N, 1]
        with torch.no_grad():
            encoder = self.transformer.encoder
            decoder = self.transformer.decoder
            enc_x = enc_x.unsqueeze(-1)
            enc_x = self.l1(enc_x)
            enc_x = self.positional_encoder(enc_x)
            enc_y = encoder(enc_x)
            for i in range(1, t_seq + 1):
                dec_x2 = dec_x.unsqueeze(-1)  # [N, i, 1]
                dec_x2 = self.l2(dec_x2)  # [N, i, d_model]
                dec_x2 = self.positional_encoder(dec_x2)  # [N, i, d_model]
                y = decoder(dec_x2, enc_y)  # [N, i, d_model]
                y = self.l3(y).squeeze(-1)  # [N, 1]
                dec_x = torch.cat([dec_x, y[:, [-1]]], dim=-1)  # [N, i + 1]
        return dec_x[:, 1:]

class LSTMNet(nn.Module):
    def __init__(self, d_model=512, num_layers=1, dropout=0.1, bidirectional=False):
        super().__init__()
        self.l1 = nn.Linear(1, d_model)
        self.l2 = nn.Linear(1, d_model)
        self.enc_lstm = nn.LSTM(
            d_model, d_model, num_layers, dropout=dropout, bidirectional=bidirectional, batch_first=True
        )
        self.dec_lstm = nn.LSTM(
            d_model, d_model, num_layers, dropout=dropout, bidirectional=bidirectional, batch_first=True
        )
        self.l3 = nn.Linear(2 * d_model, 1) if bidirectional else nn.Linear(d_model, 1)

    def forward(self, enc_x, dec_x):
        enc_x = enc_x.unsqueeze(-1)  # [N, x_seq, 1]
        enc_x = self.l1(enc_x)  # [N, x_seq, d_model]
        _, hc = self.enc_lstm(enc_x)
        dec_x = dec_x.unsqueeze(-1)  # [N, t_seq, 1]
        dec_x = self.l2(dec_x)  # [N, t_seq, d_model]
        y, _ = self.dec_lstm(dec_x, hc)  # [N, t_seq, d_model]
        y = self.l3(y).squeeze(-1)  # [N, t_seq]
        return y

    def test(self, enc_x, dec_x, t_seq):
        dec_x = dec_x[:, [0]]  # [N, 1]
        with torch.no_grad():
            enc_x = enc_x.unsqueeze(-1)  # [N, x_seq, 1]
            enc_x = self.l1(enc_x)  # [N, x_seq, d_model]
            _, hc = self.enc_lstm(enc_x)
            for i in range(1, t_seq + 1):
                dec_x2 = dec_x[:, [-1]].unsqueeze(-1)  # [N, 1, 1]
                dec_x2 = self.l2(dec_x2)  # [N, 1, d_model]
                y, hc = self.dec_lstm(dec_x2, hc)  # [N, i, d_model], ...
                y = self.l3(y).squeeze(-1)  # [N, 1]
                dec_x = torch.cat([dec_x, y[:, [-1]]], dim=-1)  # [N, i + 1]
        return dec_x[:, 1:]


import os
import sys
from PyQt5 import QtGui, QtWidgets

"""
from datetime import datetime,timedelta
from threading import Timer
"""
print('poggo')
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
    def __init__(self,icon,parent=None):
        QtWidgets.QSystemTrayIcon.__init__(self,icon,parent)
        self.setToolTip('TimeUp')
        menu = QtWidgets.QMenu(parent)

        exitApp = menu.addAction('Exit')
        #t.cancel()
        exitApp.triggered.connect(lambda:sys.exit())

        self.setContextMenu(menu)
        self.activated.connect(self.trayActivate)

    def trayActivate(self, reason):
        if reason == self.DoubleClick:
            window = startWindow()

def startWindow():
    from mainmenu4 import Ui_MainWindow
    import sys
    global daWindow
    global ui
    daWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(daWindow)
    ui.refreshList()
    daWindow.show()

    return daWindow

def trayMain():
    from mainmenu4 import Ui_MainWindow
    trayApp = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QWidget()
    trayApp.setQuitOnLastWindowClosed(False)

    dirName=os.path.dirname(os.path.abspath(__file__))
    iconPath = os.path.join(dirName, 'icon.png')
    trayIcon = SystemTrayIcon(QtGui.QIcon(iconPath),w)
    trayIcon.show()
    """
    print ('setting up main window and hiding it.')
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    ui.refreshList()
    MainWindow.hide()
    """
    #mainmenu4.runMain()

    sys.exit(trayApp.exec_())

if __name__ == '__main__':

    trayMain()

"""
xdate=datetime.today()
ydate=timedelta(0,10)

print (xdate)
print (ydate)
delta_t=xdate + ydate

print (delta_t)
secs= delta_t - xdate

def hello_world():
    print ('hello world')

#print (secs)

t = Timer(5,hello_world())
"""