import math
import random
import string

import cv2
import mmcv
import numpy as np
import Polygon as plg
import pyclipper
import torch
import torchvision.transforms as transforms
from PIL import Image
from torch.utils import data

ic15_root_dir = './data/ICDAR2015/Challenge4/'
ic15_train_data_dir = ic15_root_dir + 'ch4_training_images/'
ic15_train_gt_dir = ic15_root_dir + \
                    'ch4_training_localization_transcription_gt/'
ic15_test_data_dir = ic15_root_dir + 'ch4_test_images/'
ic15_test_gt_dir = ic15_root_dir + \
                   'ch4_test_localization_transcription_gt/'

vin_root_dir =  '../../../../Databases/VinText/vietnamese_original/vietnamese/'

vin_train_data_dir  = vin_root_dir +    'train_images/'
vin_train_gt_dir    = vin_root_dir +    'labels/'
vin_test_data_dir   = vin_root_dir +    'test_images/'
vin_test_gt_dir     = vin_root_dir +    'labels/'

dictionary = "aàáạảãâầấậẩẫăằắặẳẵAÀÁẠẢÃĂẰẮẶẲẴÂẦẤẬẨẪeèéẹẻẽêềếệểễEÈÉẸẺẼÊỀẾỆỂỄoòóọỏõôồốộổỗơờớợởỡOÒÓỌỎÕÔỒỐỘỔỖƠỜỚỢỞỠiìíịỉĩIÌÍỊỈĨuùúụủũưừứựửữƯỪỨỰỬỮUÙÚỤỦŨyỳýỵỷỹYỲÝỴỶỸ"

def make_groups():
    groups = []
    i = 0
    while i < len(dictionary) - 5:
        group = [c for c in dictionary[i : i + 6]]
        i += 6
        groups.append(group)
    return groups

groups = make_groups()

TONES = ["", "ˋ", "ˊ", "﹒", "ˀ", "˜"]
SOURCES = ["ă", "â", "Ă", "Â", "ê", "Ê", "ô", "ơ", "Ô", "Ơ", "ư", "Ư", "Đ", "đ"]
TARGETS = ["aˇ", "aˆ", "Aˇ", "Aˆ", "eˆ", "Eˆ", "oˆ", "o˒", "Oˆ", "O˒", "u˒", "U˒", "D^", "d^"]

def parse_tone(word):
    res = ""
    tone = ""
    for char in word:
        if char in dictionary:
            for group in groups:
                if char in group:
                    if tone == "":
                        tone = TONES[group.index(char)]
                    res += group[0]
        else:
            res += char
    res += tone
    return res

def full_parse(word):
    word = parse_tone(word)
    res = ""
    for char in word:
        if char in SOURCES:
            res += TARGETS[SOURCES.index(char)]
        else:
            res += char
    return res

def correct_tone_position(word):
    word = word[:-1]
    first_ord_char = ""
    second_order_char = ""
    for char in word:
        for group in groups:
            if char in group:
                second_order_char = first_ord_char
                first_ord_char = group[0]
    if word[-1] == first_ord_char and second_order_char != "":
        pair_chars = ["qu", "Qu", "qU", "QU", "gi", "Gi", "gI", "GI"]
        for pair in pair_chars:
            if pair in word and second_order_char in ["u", "U", "i", "I"]:
                return first_ord_char
        return second_order_char
    return first_ord_char

def decoder(recognition):
    for char in TARGETS:
        recognition = recognition.replace(char, SOURCES[TARGETS.index(char)])
    replace_char = correct_tone_position(recognition)
    if recognition[-1] in TONES:
        tone = recognition[-1]
        recognition = recognition[:-1]
        for group in groups:
            if replace_char in group:
                recognition = recognition.replace(replace_char, group[TONES.index(tone)])
    return recognition

#print(decoder(full_parse("Rồng")))

def get_img(img_path, read_type='pil'):
    try:
        if read_type == 'cv2':
            img = cv2.imread(img_path)
            img = img[:, :, [2, 1, 0]]
        elif read_type == 'pil':
            img = np.array(Image.open(img_path))
    except Exception:
        print('Cannot read image: %s.' % img_path)
        raise
    return img

def get_ann(img, gt_path):
    h, w = img.shape[0:2]
    #lines = mmcv.list_from_file(gt_path,encoding='utf-8')
    with open(gt_path, 'r',encoding='utf-8') as f:
        lines=[ x for x in f]
    bboxes = []
    words = []
    for line in lines:
        #line = line.decode('utf-8-sig')
        line = line.replace('\xef\xbb\xbf', '')
        gt = line.split(',')
        word= gt[8] if len(gt) ==9 else ','.join(gt[8:])
        word = word.replace('\r', '').replace('\n', '')
        word = full_parse(word)
        if len(word)==0:
            word ="###"
        if word[0] == '#':
            words.append('###')
        else:
            words.append(word)

        bbox = [int(gt[i]) for i in range(8)]
        bbox = np.array(bbox) / ([w * 1.0, h * 1.0] * 4)
        bboxes.append(bbox)
    return np.array(bboxes), words

def random_horizontal_flip(imgs):
    if random.random() < 0.5:
        for i in range(len(imgs)):
            imgs[i] = np.flip(imgs[i], axis=1).copy()
    return imgs

#Augument
def random_rotate(imgs):
    max_angle = 10
    angle = random.random() * 2 * max_angle - max_angle
    for i in range(len(imgs)):
        img = imgs[i]
        w, h = img.shape[:2]
        rotation_matrix = cv2.getRotationMatrix2D((h / 2, w / 2), angle, 1)
        img_rotation = cv2.warpAffine(img,
                                      rotation_matrix, (h, w),
                                      flags=cv2.INTER_NEAREST)
        imgs[i] = img_rotation
    return imgs

#Augument
def scale_aligned(img, h_scale, w_scale):
    h, w = img.shape[0:2]
    h = int(h * h_scale + 0.5)
    w = int(w * w_scale + 0.5)
    if h % 32 != 0:
        h = h + (32 - h % 32)
    if w % 32 != 0:
        w = w + (32 - w % 32)
    img = cv2.resize(img, dsize=(w, h))
    return img

#Augument
def scale_aligned_short(img, short_size=736):
    h, w = img.shape[0:2]
    scale = short_size * 1.0 / min(h, w)
    h = int(h * scale + 0.5)
    w = int(w * scale + 0.5)
    if h % 32 != 0:
        h = h + (32 - h % 32)
    if w % 32 != 0:
        w = w + (32 - w % 32)
    img = cv2.resize(img, dsize=(w, h))
    return img

#Augument
def random_scale(img, short_size=736):
    h, w = img.shape[0:2]

    scale = np.random.choice(np.array([0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3]))
    scale = (scale * short_size) / min(h, w)

    aspect = np.random.choice(np.array([0.9, 0.95, 1.0, 1.05, 1.1]))
    h_scale = scale * math.sqrt(aspect)
    w_scale = scale / math.sqrt(aspect)

    img = scale_aligned(img, h_scale, w_scale)
    return img

#Augument
def random_crop_padding(imgs, target_size):
    h, w = imgs[0].shape[0:2]
    t_w, t_h = target_size
    p_w, p_h = target_size
    if w == t_w and h == t_h:
        return imgs

    t_h = t_h if t_h < h else h
    t_w = t_w if t_w < w else w

    if random.random() > 3.0 / 8.0 and np.max(imgs[1]) > 0:
        # make sure to crop the text region
        tl = np.min(np.where(imgs[1] > 0), axis=1) - (t_h, t_w)
        tl[tl < 0] = 0
        br = np.max(np.where(imgs[1] > 0), axis=1) - (t_h, t_w)
        br[br < 0] = 0
        br[0] = min(br[0], h - t_h)
        br[1] = min(br[1], w - t_w)

        i = random.randint(tl[0], br[0]) if tl[0] < br[0] else 0
        j = random.randint(tl[1], br[1]) if tl[1] < br[1] else 0
    else:
        i = random.randint(0, h - t_h) if h - t_h > 0 else 0
        j = random.randint(0, w - t_w) if w - t_w > 0 else 0

    n_imgs = []
    for idx in range(len(imgs)):
        if len(imgs[idx].shape) == 3:
            s3_length = int(imgs[idx].shape[-1])
            img = imgs[idx][i:i + t_h, j:j + t_w, :]
            img_p = cv2.copyMakeBorder(img,
                                       0,
                                       p_h - t_h,
                                       0,
                                       p_w - t_w,
                                       borderType=cv2.BORDER_CONSTANT,
                                       value=tuple(0
                                                   for i in range(s3_length)))
        else:
            img = imgs[idx][i:i + t_h, j:j + t_w]
            img_p = cv2.copyMakeBorder(img,
                                       0,
                                       p_h - t_h,
                                       0,
                                       p_w - t_w,
                                       borderType=cv2.BORDER_CONSTANT,
                                       value=(0, ))
        n_imgs.append(img_p)
    return n_imgs

def update_word_mask(instance, instance_before_crop, word_mask):
    labels = np.unique(instance)

    for label in labels:
        if label == 0:
            continue
        ind = instance == label
        if np.sum(ind) == 0:
            word_mask[label] = 0
            continue
        ind_before_crop = instance_before_crop == label
        # print(np.sum(ind), np.sum(ind_before_crop))
        if float(np.sum(ind)) / np.sum(ind_before_crop) > 0.9:
            continue
        word_mask[label] = 0

    return word_mask

def dist(a, b):
    return np.linalg.norm((a - b), ord=2, axis=0)

def perimeter(bbox):
    peri = 0.0
    for i in range(bbox.shape[0]):
        peri += dist(bbox[i], bbox[(i + 1) % bbox.shape[0]])
    return peri

def shrink(bboxes, rate, max_shr=20):
    rate = rate * rate
    shrinked_bboxes = []
    for bbox in bboxes:
        area = plg.Polygon(bbox).area()
        peri = perimeter(bbox)

        try:
            pco = pyclipper.PyclipperOffset()
            pco.AddPath(bbox, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
            offset = min(int(area * (1 - rate) / (peri + 0.001) + 0.5),
                         max_shr)

            shrinked_bbox = pco.Execute(-offset)
            if len(shrinked_bbox) == 0:
                shrinked_bboxes.append(bbox)
                continue

            shrinked_bbox = np.array(shrinked_bbox)[0]
            if shrinked_bbox.shape[0] <= 2:
                shrinked_bboxes.append(bbox)
                continue

            shrinked_bboxes.append(shrinked_bbox)
        except Exception:
            print('area:', area, 'peri:', peri)
            shrinked_bboxes.append(bbox)

    return shrinked_bboxes

def get_vocabulary(voc_type, EOS='EOS', PADDING='PAD', UNKNOWN='UNK'):
    if voc_type == 'LOWERCASE':
        voc = list(string.digits + string.ascii_lowercase)
    elif voc_type == 'ALLCASES':
        voc = list(string.digits + string.ascii_letters)
    elif voc_type == 'ALLCASES_SYMBOLS':
        voc = list(string.printable[:-6])
    elif voc_type =='VIETCASE':
        tones =[' ','ˋ', 'ˊ', '﹒', 'ˀ', '˜', 'ˇ', 'ˆ', '˒', '‑']

        voc = list(string.printable[:-6])
        voc+= tones
    else:
        raise KeyError('voc_type must be one of "LOWERCASE", '
                       '"ALLCASES", "ALLCASES_SYMBOLS" ,"VIETCASE"')

    # update the voc with specifical chars
    voc.append(EOS)
    voc.append(PADDING)
    voc.append(UNKNOWN)

    char2id = dict(zip(voc, range(len(voc))))
    id2char = dict(zip(range(len(voc)), voc))

    return voc, char2id, id2char

class PAN_PP_IC15(data.Dataset):
    def __init__(self,
                 split='train',
                 is_transform=False,
                 img_size=None,
                 short_size=736,
                 kernel_scale=0.5,
                 with_rec=False,
                 read_type='pil',
                 report_speed=False):
        self.split = split
        self.is_transform = is_transform

        self.img_size = img_size if (
            img_size is None or isinstance(img_size, tuple)) else (img_size,
                                                                   img_size)
        self.kernel_scale = kernel_scale
        self.short_size = short_size
        self.with_rec = with_rec
        self.read_type = read_type

        if split == 'train':
            data_dirs = [ vin_train_data_dir]
            gt_dirs = [vin_train_gt_dir]
        elif split == 'test':
            data_dirs = [vin_test_data_dir]
            gt_dirs = [vin_test_gt_dir]
        else:
            print('Error: split must be train or test!')
            raise

        self.img_paths = []
        self.gt_paths = []

        count=0
        for data_dir, gt_dir in zip(data_dirs, gt_dirs):
            img_names = [
                img_name for img_name in mmcv.utils.scandir(data_dir, '.jpg')
            ]
            img_names.extend([
                img_name for img_name in mmcv.utils.scandir(data_dir, '.png')
            ])

            img_names.extend([
                img_name for img_name in mmcv.utils.scandir(data_dir, '.jpge')
            ])

            img_paths = []
            gt_paths = []
            if count ==1:
                for idx, img_name in enumerate(img_names):

                    gt_name = 'gt_' + img_name.split('.')[0] + '.txt'
                    gt_path = gt_dir + gt_name
                    # with open(gt_path,'r') as f:
                    #     k = [x for x in f]
                    #     if len(k) > 10:
                    #         pass
                    gt_paths.append(gt_path)
                    img_path = data_dir + img_name
                    img_paths.append(img_path)

                print('Found {} images,gt in {}'.format((len(img_paths)), data_dir))

                self.img_paths.extend(img_paths)
                self.gt_paths.extend(gt_paths)
            else:
                for idx, img_name in enumerate(img_names):

                    gt_name = img_name.split('.')[0][2:]
                    gt_name= str(int(gt_name))
                    gt_name = 'gt_' + gt_name + '.txt'
                    gt_path = gt_dir + gt_name

                    # with open(gt_path,'r') as f:
                    #     k = [x for x in f]
                    #     if len(k) > 10:
                    #         pass
                    gt_paths.append(gt_path)
                    img_path = data_dir + img_name
                    img_paths.append(img_path)
                    print('Found {} images,gt in {}'.format((len(img_paths)), data_dir))

                self.img_paths.extend(img_paths)
                self.gt_paths.extend(gt_paths)

            count+=1

        print("Found {} image and ground truth!".format(len(self.img_paths)))

        if report_speed:
            target_size = 3000
            extend_scale = (target_size + len(self.img_paths) - 1) // len(
                self.img_paths)
            self.img_paths = (self.img_paths * extend_scale)[:target_size]
            self.gt_paths = (self.gt_paths * extend_scale)[:target_size]

        self.voc, self.char2id, self.id2char = get_vocabulary('VIETCASE')
        self.max_word_num = 200
        self.max_word_len = 32
        print('reading type: %s.' % self.read_type)

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

    def prepare_train_data(self, index):

        #init path
        img_path = self.img_paths[index]
        gt_path = self.gt_paths[index]

        #read image, bboxes, annotation
        img = get_img(img_path, self.read_type)
        bboxes, words = get_ann(img, gt_path)

        #fit count box == count word
        if bboxes.shape[0] > self.max_word_num:
            bboxes = bboxes[:self.max_word_num]
            words = words[:self.max_word_num]

        #embding char to int
        #   setup
        gt_words = np.full((self.max_word_num + 1, self.max_word_len),
                           self.char2id['PAD'],
                           dtype=np.int32)
        word_mask = np.zeros((self.max_word_num + 1, ), dtype=np.int32)

        #   convert
        for i, word in enumerate(words):
            if word == '###':
                continue
            #word = word.lower()
            gt_word = np.full((self.max_word_len, ),
                              self.char2id['PAD'],
                              dtype=np.int)
            for j, char in enumerate(word):
                if j > self.max_word_len - 1:
                    break
                if char in self.char2id:
                    gt_word[j] = self.char2id[char]
                else:
                    gt_word[j] = self.char2id['UNK']
            if len(word) > self.max_word_len - 1:
                gt_word[-1] = self.char2id['EOS']
            else:
                gt_word[len(word)] = self.char2id['EOS']
            gt_words[i + 1] = gt_word
            word_mask[i + 1] = 1

        #transform? Why do it transform here? It can make mistake bboxes
        if self.is_transform:
            #pass
            img = random_scale(img, self.short_size)

        #draw gt_mask with 4 corner (if ### draw into traning_mask (for detection))
        gt_instance = np.zeros(img.shape[0:2], dtype='uint8')
        training_mask = np.ones(img.shape[0:2], dtype='uint8')
        if bboxes.shape[0] > 0:
            bboxes = np.reshape(bboxes * ([img.shape[1], img.shape[0]] * 4),
                                (bboxes.shape[0], -1, 2)).astype('int32')
            for i in range(bboxes.shape[0]):
                cv2.drawContours(gt_instance, [bboxes[i]], -1, i + 1, -1)
                if words[i] == '###':
                    cv2.drawContours(training_mask, [bboxes[i]], -1, 0, -1)

        #init kernels from bboxes
        gt_kernels = []
        for rate in [self.kernel_scale]:
            gt_kernel = np.zeros(img.shape[0:2], dtype='uint8')
            kernel_bboxes = shrink(bboxes, rate)
            for i in range(bboxes.shape[0]):
                cv2.drawContours(gt_kernel, [kernel_bboxes[i]], -1, 1, -1)
            gt_kernels.append(gt_kernel)

        #transform
        if self.is_transform:
            imgs = [img, gt_instance, training_mask]
            imgs.extend(gt_kernels)

            if not self.with_rec:
                imgs = random_horizontal_flip(imgs)
            imgs = random_rotate(imgs)
            gt_instance_before_crop = imgs[1].copy()
            imgs = random_crop_padding(imgs, self.img_size)
            img, gt_instance, training_mask, gt_kernels = imgs[0], imgs[1], imgs[2], imgs[3:]
            #update word and mask because transformation can lose box
            word_mask = update_word_mask(gt_instance, gt_instance_before_crop,
                                         word_mask)

        gt_text = gt_instance.copy()
        gt_text[gt_text > 0] = 1
        gt_kernels = np.array(gt_kernels)

        #get bounding box after transformation
        max_instance = np.max(gt_instance)
        gt_bboxes = np.zeros((self.max_word_num + 1, 4), dtype=np.int32)
        for i in range(1, max_instance + 1):
            ind = gt_instance == i
            if np.sum(ind) == 0:
                continue
            points = np.array(np.where(ind)).transpose((1, 0))
            tl = np.min(points, axis=0)
            br = np.max(points, axis=0) + 1
            gt_bboxes[i] = (tl[0], tl[1], br[0], br[1])

        img = Image.fromarray(img)
        img = img.convert('RGB')
        if self.is_transform:
            img = transforms.ColorJitter(brightness=32.0 / 255,
                                         saturation=0.5)(img)

        img = transforms.ToTensor()(img)
        img = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                   std=[0.229, 0.224, 0.225])(img)
        gt_text = torch.from_numpy(gt_text).long()
        gt_kernels = torch.from_numpy(gt_kernels).long()
        training_mask = torch.from_numpy(training_mask).long()
        gt_instance = torch.from_numpy(gt_instance).long()
        gt_bboxes = torch.from_numpy(gt_bboxes).long()
        gt_words = torch.from_numpy(gt_words).long()
        word_mask = torch.from_numpy(word_mask).long()

        data = dict(
            imgs=img,
            gt_texts=gt_text,
            gt_kernels=gt_kernels,
            training_masks=training_mask,
            gt_instances=gt_instance,
            gt_bboxes=gt_bboxes,
        )
        if self.with_rec:
            data.update(dict(gt_words=gt_words, word_masks=word_mask))

        return data

    def prepare_test_data(self, index):
        img_path = self.img_paths[index]

        img = get_img(img_path, self.read_type)
        img_meta = dict(org_img_size=np.array(img.shape[:2]))

        img = scale_aligned_short(img, self.short_size)
        img_meta.update(dict(img_size=np.array(img.shape[:2])))

        img = Image.fromarray(img)
        img = img.convert('RGB')
        img = transforms.ToTensor()(img)
        img = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                   std=[0.229, 0.224, 0.225])(img)

        data = dict(imgs=img, img_metas=img_meta)

        return data

    def __getitem__(self, index):
        if self.split == 'train':
            return self.prepare_train_data(index)
        elif self.split == 'test':
            return self.prepare_test_data(index)

# input --image
#       --bboxes
#       --instance mask
#       --annotation

# out   --Image
#       --bboxes
#       --text_mask (for dectection)
#       --instance_mask (for recognition)
#       --kernels_mask (like anchor or bezier method)
#       --gt_word (after embding)
#       --word_mask (?)


import bisect
import codecs
import io
import weakref
import re

DEFAULT_BUFSIZE = 4 * 1024

class UnicodeStreamer(object):
    """
    Class in charge of input byte stream. Input is converted to unicode,
    split in chunks, which are registered in a weakref dictionary.
    """

    def __init__(self, stream, encoding='utf-8', bufsize=None):
        if bufsize is None:
            bufsize = DEFAULT_BUFSIZE
        self.bufsize = bufsize
        self.lines = 0
        self.buffers = 0
        self.store = weakref.WeakValueDictionary()

        # We need to get a unicode stream, because otherwise dealing with
        # offsets, marks and errors will be a pain.

        # noinspection PyPep8Naming
        ReaderClass = codecs.getreader(encoding)
        if isinstance(stream, unicode):
            self.stream = io.StringIO(stream)
        elif isinstance(stream, str):
            self.stream = ReaderClass(io.BytesIO(stream))
        # TODO: coverage - test for stream created with codecs.open()
        elif getattr(stream, 'encoding', None):
            # This is a file opened using codecs.open() with an encoding
            # specified. It produces unicode output by itself, no wrapping
            # necessary.
            self.stream = stream
        else:
            self.stream = ReaderClass(stream)

    def _add_buffer(self, data):
        buf = Buffer(self.lines, data)
        self.store[self.buffers] = buf
        self.buffers += 1
        self.lines += len(buf.lines)
        return buf

    def chunks3(self):
        """
        Cut stream into chunks, register then in weakref dictionary and
        yield as  3-tuples: (previous, current, next).

        This way, a strong reference to current and surrounding chunks can be
        acquired for marks and such.
        """
        prev = None

        def next_buffer():
            data = read(self.bufsize)
            if data:
                return self._add_buffer(data)

        read = self.stream.read
        current = next_buffer()
        while current:
            next_ = next_buffer()
            yield prev, current, next_
            prev, current = current, next_

def find_newlines(s):
    """ Find locations of all newlines in the string """
    return [m.start() for m in re.finditer(u'\n', s)]

class Buffer(object):

    def __init__(self, start_line, data):
        assert isinstance(data, unicode)
        self.start_line = start_line
        self.data = data
        self.bytes_cnt = data.encode('utf-8')

        # Accumulated line lengths
        self.lines = find_newlines(data)
        # Don't forget the last line if it doesn't end in newline
        if self.data[-1] != u'\n':
            self.lines.append(len(self.data))

    def line_and_col(self, offset):
        """ Return line and column numbers given the offset """
        line = bisect.bisect_left(self.lines, offset)
        col = offset
        if line > 0:
            col -= self.lines[line - 1] + 1

        return line + self.start_line, col

class Mark(object):
    """
    Marks a position in the input character (or, more precisely,
    codepoint) stream. Holds a strong reference for the buffer it points to,
    and maybe some others as requested.
    """

    @property
    def pos(self):
        return "%s:%s" % (self.line, self.col)

    def __init__(self, manager, bufno, buf_offset, keep_buffers=()):
        self.manager = manager
        self.bufno = bufno
        self.buf = buf = manager.store[bufno]

        self.offset = bufno * manager.bufsize + buf_offset
        self.line, self.col = buf.line_and_col(buf_offset)

        # Keep the buffers from being garbage-collected
        self._kept_buffers = set()
        keep_buffers = set(keep_buffers).union({bufno - 1, bufno + 1})
        for x in keep_buffers:
            if not isinstance(x, Buffer):
                x = self.manager.store.get(x)
            if x:
                self._kept_buffers.add(x)


"""
EuropaEU spider created on the top of ATSSpider

scrapy crawl europa_eu -a mining_job_id=9999 -a iteration=1 -a extract=1 -a url="https://ec.europa.eu/eures/eures-searchengine/page/main#/simpleSearch"

Sample URL:
    https://ec.europa.eu/eures/eures-searchengine/page/main#/simpleSearch
"""

from json import dumps, loads
from logging import log, INFO
from scrapy.http import Request
from scrapy.selector import Selector
from urlparse import urljoin

from brightcorp.base.incrementalatsspider import IncrementalATSSpider
from brightcorp.items import BrightcorpItemLoader
from brightcorp.processors import NormalizedJoin, Prefix

class EuropaEU(IncrementalATSSpider):

    disable_default_field_extractors = True
    name = 'europa_eu'
    headers = {
        'Content-Type': 'application/json;charset=utf-8',
    }
    page = 1
    total_pages = 0
    params = {
        "keywords": [{
            "keyword": "",
            "specificSearchCode": "EVERYWHERE"
        }],
        "locationCriteriaBean": {
            "selectedNuts": [],
            "notSpecifiedInCountry": []
        },
        "selectedOccupations": [],
        "contractTypeCodes": [],
        "contractDurationCodes": [],
        "contractTypeCodes": [],
        "experienceCodes": [],
        "educationLevelCodes": [],
        "euresFlagCodes": [],
        "page": 1,
        "resultsPerPage": 50,
    }

    def parse(self, response):
        sel = Selector(response)
        yield Request(
            callback=self.parse_jobs_list,
            body=dumps(self.params),
            headers=self.headers,
            method='POST',
            url=urljoin(
                response.url,
                '/eures/eures-searchengine/page/jvSearch/fullSearch?lang=en&app=1.2.1-build-1'
            )
        )

    def parse_jobs_list(self, response):
        try:
            jsonResponse = loads(response.body)
        except:
            return
        searchResults = jsonResponse.get('searchResults')
        if searchResults:
            # set expected job count
            if not self.expected_job_count_set:
                self.expected_job_count = searchResults.get('matchingJobVacanciesNumber', 0)
                self.total_pages = searchResults.get('totalPageCount', 0)

            jvSummaries = searchResults.get('jvSummaries')
            if jvSummaries:
                for item in jvSummaries:
                    uuid = item['abstractJV']['id']
                    pesid = item['abstractJV']['pesId']
                    uniqueJVId = item['abstractJV']['uniqueJvId']
                    body_data = {
                        'jobVacancyId': uniqueJVId,
                        'pesId': pesid,
                        'uuId': uuid,
                    }
                    request = Request(
                        body=dumps(body_data),
                        callback=self.parse_job_callback(),
                        headers=self.headers,
                        meta=body_data,
                        method='POST',
                        url=urljoin(
                            response.url,
                            '/eures/eures-searchengine/page/jvSearch/showJVDetails?lang=en&app=1.2.1-build-1'
                        )
                    )
                    fields_to_hash = {'jobVacancyId': uniqueJVId}
                    incremental_crawler_hash = self.hash_fields(fields_to_hash)
                    yield self.is_new_job_request(incremental_crawler_hash, request)

            # pagination
            if self.page <= self.total_pages:
                self.page += 1
                self.params.update({
                    "page": self.page,
                })
                yield Request(
                    callback=self.parse_jobs_list,
                    body=dumps(self.params),
                    headers=self.headers,
                    method='POST',
                    url=urljoin(
                        response.url,
                        '/eures/eures-searchengine/page/jvSearch/fullSearch?lang=en&app=1.2.1-build-1'
                    )
                )

    def parse_job(self, response):
        """
        Extract all required information.
        """
        error_msg = [
            'no longer available',
            'please try again later'
        ]
        for error in error_msg:
            if error in response.body:
                log(INFO, 'Invalid Job URL: %s' % response.url)
                return

        jsonResponse = loads(response.body)
        jvSummary = jsonResponse.get('jvSummary')
        if jvSummary:
            loader = BrightcorpItemLoader(selector=jvSummary)
            url = urljoin(
                response.url,
                '/eures/eures-searchengine/page/main?lang=en#/fullscreenJvView?uuId=%(uuid)s&jvId=%(jvId)s&pesId=%(pesid)s' % {
                    'uuid': response.meta.get('uuId'),
                    'jvId': response.meta.get('jobVacancyId'),
                    'pesid': response.meta.get('pesId'),
                }
            )
            abstractJV = jvSummary.get('abstractJV')
            if abstractJV:
                loader.add_value(
                    'title',
                    abstractJV.get('title')
                )
                loader.add_value(
                    'company',
                    abstractJV.get('empName')
                )
                loader.add_value(
                    'description',
                    abstractJV.get('description')
                )
                loader.add_value(
                    'workhours',
                    abstractJV.get('hoursPerWeek')
                )
                baseSalary = filter(
                    None,
                    [
                        abstractJV.get('minimumSalary'),
                        abstractJV.get('maximumSalary')
                    ]
                )
                # int, float to str
                loader.add_value(
                    'baseSalary',
                    [str(item) for item in baseSalary],
                    NormalizedJoin(' - ')
                )
            searchTranslation = jvSummary.get('searchTranslation')
            if searchTranslation:
                loader.add_value(
                    'location',
                    [
                        searchTranslation.get('countryName'),
                        searchTranslation.get('nutsName')
                    ],
                    NormalizedJoin(', ')
                )
                loader.add_value(
                    'jobtype',
                    [
                        searchTranslation.get('contractDurationName'),
                        searchTranslation.get('contractTypeName')
                    ],
                    NormalizedJoin(', ')
                )
                loader.add_value(
                    'jobcategory',
                    searchTranslation.get('iscoName')
                )
                loader.add_value(
                    'educationrequirements',
                    searchTranslation.get('requiredEducationName')
                )
                loader.add_value(
                    'experiencerequirements',
                    searchTranslation.get('experienceName')
                )
                loader.add_value(
                    'salaryCurrency',
                    searchTranslation.get('salaryCurrencyName')
                )
            loader.add_value(
                'referencenumber',
                response.meta.get('jobVacancyId'),
                Prefix('%s-' % self.name)
            )
            loader.add_value('url', url)
            loader.add_value('apply_url', url)

            fields_to_hash = {'jobVacancyId': response.meta.get('jobVacancyId')}
            incremental_crawler_hash = self.hash_fields(fields_to_hash)
            loader.add_value('incremental_crawler_hash', incremental_crawler_hash)

            yield loader.load_item()


# -*- coding: utf-8 -*-
#@Author: Lidong Yu
#@Date: 2019-11-29 00:58:39
#@Last Modified by: Lidong Yu
#@Last Modified time: 2019-11-29 02:28:39

import numpy as np
import torch
import os
import time
import json
import cv2
from IO import *
import mmcv
import matplotlib.pyplot as plt
def bbox_overlaps(bboxes1, bboxes2):
    bboxes1 = bboxes1.astype(np.float32)
    bboxes2 = bboxes2.astype(np.float32)
    rows = bboxes1.shape[0]
    cols = bboxes2.shape[0]
    ious = np.zeros((rows, cols), dtype=np.float32)
    if rows * cols == 0:
        return ious
    exchange = False
    if bboxes1.shape[0] > bboxes2.shape[0]:
        bboxes1, bboxes2 = bboxes2, bboxes1
        ious = np.zeros((cols, rows), dtype=np.float32)
        exchange = True
    area1 = (bboxes1[:, 2] - bboxes1[:, 0] + 1) * (
        bboxes1[:, 3] - bboxes1[:, 1] + 1)
    area2 = (bboxes2[:, 2] - bboxes2[:, 0] + 1) * (
        bboxes2[:, 3] - bboxes2[:, 1] + 1)
    for i in range(bboxes1.shape[0]):
        x_start = np.maximum(bboxes1[i, 0], bboxes2[:, 0])
        y_start = np.maximum(bboxes1[i, 1], bboxes2[:, 1])
        x_end = np.minimum(bboxes1[i, 2], bboxes2[:, 2])
        y_end = np.minimum(bboxes1[i, 3], bboxes2[:, 3])
        overlap = np.maximum(x_end - x_start + 1, 0) * np.maximum(
            y_end - y_start + 1, 0)
        union = area1[i] + area2 - overlap
        ious[i, :] = overlap / union
    if exchange:
        ious = ious.T
    return ious
def box2center(bbox):

	# center=[]
	# for i in bbox:
	# 	left_top = np.array(i[0], i[1])
	# 	right_bottom = np.array(i[2], i[3])
	# 	center.append((left_top+right_bottom)/2)
	# return np.array(center)
	return (bbox[:,:2]+bbox[:,-2:])/2
def get_transform(flow,bbox):
	transform=flow[np.floor(c0[:,1]).astype(np.int),np.floor(c0[:,0]).astype(np.int)]
	return transform
def center_dist(c0,c1):
	dist=np.sqrt(np.sum(np.square(c0[:,None,:]-c1[None,:,:]),axis=-1))
	return dist
def bbox_select(flow0,bbox):
	#flow0 is the origin flow, we check the warp flow and compute the largest overlap
	#with the detection bbox
	return 0
def trackiou(iou,max_id):
	idx=np.arange(iou.shape[0])
	idc=np.arange(iou.shape[1])
	id=np.argmax(iou,axis=1)
	value=np.max(iou,axis=1)
	id_check=np.argmax(iou,axis=0)
	if (id_check[id]==idx).all() and (id[id_check]==idc).all():
		id=np.where(value<0.3,-1,id)
		return id
	else:
		count=np.bincount(id)
		while(np.max(count)>1):
			for i in range(np.min(id),np.max(id)+1):
				if count[i]<=1:
					continue
				ids=np.where(id==i)[0]
				iou[ids,i]=0
				iou[ids[np.argmax(value[ids])],i]=value[ids[np.argmax(value[ids])]]
			id=np.argmax(iou,axis=1)
			if (np.max(iou,axis=1)==value).all():
				count=np.bincount(id)
				for i in range(np.min(id),np.max(id)+1):
					if count[i]<=1:
						continue
					ids=np.where(id==i)[0]
					id[ids]=-1
					id[ids[np.argmax(value[ids])]]=i
				id=np.where(value<0.3,-1,id)
				return id
			else:
				value=np.max(iou,axis=1)
				count=np.bincount(id)
		id=np.where(value<0.3,-1,id)
		return id

def trackcd(cd,max_id):
	idx=np.arange(cd.shape[0])
	idc=np.arange(cd.shape[1])
	id=np.argmin(cd,axis=1)
	value=np.min(cd,axis=1)
	id_check=np.argmin(cd,axis=0)
	if (id_check[id]==idx).all() and (id[id_check]==idc).all():
		id=np.where(value>50,-1,id)
		return id
	else:
		count=np.bincount(id)
		while(np.max(count)>1):
			for i in range(np.min(id),np.max(id)+1):
				if count[i]<=1:
					continue
				ids=np.where(id==i)[0]
				cd[ids,i]=0
				cd[ids[np.argmin(value[ids])],i]=value[ids[np.argmin(value[ids])]]
				id=np.argmin(cd,axis=1)
			if (np.min(cd,axis=1)==value).all:
				count=np.bincount(id)
				for i in range(np.min(id),np.max(id)+1):
					if count[i]<=1:
						continue
					ids=np.where(id==i)[0]
					id[ids]=-1
					id[ids[np.argmin(value[ids])]]=i
				id=np.where(value>50,-1,id)
				return id
			else:
				value=np.min(cd,axis=1)
				count=np.bincount(id)
		id=np.where(value>50,-1,id)
		return id
def iou_cd(iou_id,cd_id,refer_id,max_id):
	# print(iou_id,cd_id,len(refer_id))
	iou_id=np.array(iou_id).astype(np.int)
	cd_id=np.array(cd_id).astype(np.int)
	refer_id=np.array(refer_id).astype(np.int)
	new_id=np.where(iou_id==-1)[0]
	#print(refer_id,iou_id)
	iou_id=refer_id[iou_id]
	iou_id[new_id]=-1
	new_id=np.where(cd_id==-1)[0]
	cd_id=refer_id[cd_id]
	cd_id[new_id]=-1
	if (iou_id==cd_id).all():
		id=iou_id
		new_id=np.array(new_id)
		for i in range(new_id.shape[0]):
			max_id+=1
			iou_id[new_id[i]]=max_id
		return id
	else:
		id=np.where(iou_id==cd_id,iou_id,-1)
		check=np.where(id==-1)[0]
		for i in check:
			if iou_id[i]==-1 or cd_id[i]==-1:
				max_id+=1
				id[i]=max_id
			else:
				if iou_id[i]==-1:
					max_id+=1
					id[i]=max_id
				else:
					id[i]=iou_id[i]

		return id

data_path='/backdata01/KITTI/kitti/tracking'
# ['calib', 'disparity',  'label_02', 'splits', 'velodyne', 'velodyne_img',
# 'Flow', 'Inv_Flow', 'trackinglabel_02', 'kitti.json', 'shuffle data', 'kitti_train.json'
#  'kitti_val.json']
jsonfile_name='kitti_val_3class.json'
with open(os.path.join(data_path,jsonfile_name),'r',encoding='utf-8') as f:
	data=json.load(f)
video_name=None
video_length=0
json_data_iou=[]
json_data_flow=[]
for i in range(len(data)):
	print(i,'in',len(data))
	info=data[i]
	if info['filename'].split('/')[0]!=video_name:
		video_length=1
		video_name=info['filename'].split('/')[0]
		max_id=-1
		max_id_iou=-1
		max_id_flow=-1
	else:
		video_length+=1
	print('video_name',video_name,'image_name',info['filename'],'processing frame',video_length)
	image_name=os.path.join(data_path,info['filename'])
	flow_name=os.path.join(data_path,data[i-1]['flow_name'])
	# image = mmcv.imread(image_name)
	flow=np.array(readFlow(flow_name))
	# color=flow_to_color(flow,convert_to_bgr=True)
	# plt.imshow(color)
	# plt.show()
	print('dection result:',np.array(info['ann']['track_id']))
	if np.array(info['ann']['bboxes']).shape[0]==0:
		result={"video_id":info['video_id'],"filename":os.path.join(info['filename']), \
			"ann":{"bboxes":[],"labels":[], \
				"track_id":[]}}
		json_data_iou.append(result)
		json_data_flow.append(result)
		print('no detection')
		continue
	elif np.array(data[i-1]['ann']['bboxes']).shape[0]==0:
		boxid=[]
		for j in range(np.array(info['ann']['bboxes']).shape[0]):
			boxid.append(j)
		boxid=np.array(boxid)
		result={"video_id":info['video_id'],"filename":os.path.join(info['filename']), \
			"ann":{"bboxes":info['ann']['bboxes'],"labels":[], \
				"track_id":(boxid+max_id_iou+1).tolist()}}
		json_data_iou.append(result)
		result={"video_id":info['video_id'],"filename":os.path.join(info['filename']), \
			"ann":{"bboxes":info['ann']['bboxes'],"labels":[], \
				"track_id":(boxid+max_id_flow+1).tolist()}}
		json_data_flow.append(result)
		print('first detection')
		continue
	if video_length==1 or max_id==-1:
		print('first frame')
		boxid=[]
		boxt0=np.array(info['ann']['bboxes'])
		for j in range(boxt0.shape[0]):
			boxid.append(j)
		if len(boxid)>0:
			max_id_iou=np.max(boxid)
			max_id_flow=np.max(boxid)
			max_id=1
		else:
			max_id_iou=-1
			max_id_flow=-1
		result={"video_id":info['video_id'],"filename":os.path.join(info['filename']), \
			"ann":{"bboxes":boxt0.tolist(),"labels":info['ann']['labels'], \
				"track_id":boxid}}
		json_data_iou.append(result)
		json_data_flow.append(result)
	else:
		refer_id=json_data_iou[-1]['ann']['track_id']
		boxt1=np.array(info['ann']['bboxes'])
		boxt0=np.array(data[i-1]['ann']['bboxes'])
		c0=box2center(boxt0)
		c1=box2center(boxt1)
		iou=bbox_overlaps(boxt1,boxt0)
		cd=center_dist(c1,c0)
		iou_id=trackiou(iou,max_id_iou)
		cd_id=trackcd(cd,max_id_iou)
		boxid=iou_cd(iou_id,cd_id,refer_id,max_id_iou)
		max_id_iou=np.max(np.maximum(boxid,max_id_iou))
		print('iou id:',boxid,boxid.shape)
		result={"video_id":info['video_id'],"filename":os.path.join(info['filename']), \
			"ann":{"bboxes":boxt1.tolist(),"labels":info['ann']['labels'], \
				"track_id":boxid.tolist()}}
		json_data_iou.append(result)
		#check the flow_result
		refer_id=json_data_flow[-1]['ann']['track_id']
		transform=get_transform(flow,c0)
		c1t=c0+transform
		boxt1t=boxt0+0
		boxt1t[:,::2]+=transform[:,0][:,None]
		boxt1t[:,1::2]+=transform[:,1][:,None]
		iou=bbox_overlaps(boxt1,boxt1t)
		cd=center_dist(c1,c1t)
		iou_id=trackiou(iou,max_id_flow)
		cd_id=trackcd(cd,max_id_flow)
		boxid=iou_cd(iou_id,cd_id,refer_id,max_id_flow)
		max_id_flow=np.max(np.maximum(boxid,max_id_flow))
		print('flow id:',boxid,boxid.shape)
		result={"video_id":info['video_id'],"filename":os.path.join(info['filename']), \
			"ann":{"bboxes":boxt1.tolist(),"labels":info['ann']['labels'], \
				"track_id":boxid.tolist()}}
		json_data_flow.append(result)

with open(os.path.join('./result/','iou_'+jsonfile_name),'w+',encoding='utf-8') as f:
	data=json.dump(json_data_iou,f)
with open(os.path.join('./result/','flow_'+jsonfile_name),'w+',encoding='utf-8') as f:
	data=json.dump(json_data_flow,f)


import uuid
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from werobot.contrib.flask import make_view

from app import robot

from config import QR_SCENE, QR_EXP, PUSH_TEMPLATE_ID
from redis_util import redis_client

app = Flask(__name__)
app.config.from_object("config")

db = SQLAlchemy(app)

app.add_url_rule(
    rule='/robot/',
    endpoint='werobot',
    view_func=make_view(robot),
    methods=['GET', 'POST']
)

@app.route('/push')
def push():
    args = request.args
    push_token = args["token"]

    from models import PushMap
    push_map = PushMap.query.filter(PushMap.push_token == push_token).first()
    if not push_map:
        return jsonify({
            "code": 404,
            "message": "未找到 token 对应的绑定记录！"
        })

    new_down_link = args.get("new_down_link")
    down_link_count = args.get("down_link_count")
    down_answer = args.get("down_answer")
    new_down_answer = args.get("new_down_answer")
    coupon_down_link = args.get("coupon_down_link")

    robot.client.send_template_message(
        user_id=push_map.openid,
        template_id=PUSH_TEMPLATE_ID,
        data={
            "new_down_link": {
                "value": new_down_link,
            },
            "down_link_count": {
                "value": down_link_count,
            },
            "down_answer": {
                "value": down_answer,
            },
            "new_down_answer": {
                "value": new_down_answer,
            },
            "coupon_down_link": {
                "value": coupon_down_link,
            },
        }
    )
    return jsonify({
        "code": 200
    })

@app.route('/check_scan')
def check_scan():
    unique_id = request.args["unique_id"]
    open_id = redis_client.get_scened_flag(unique_id)
    if open_id:
        from models import PushMap
        push_token = str(uuid.uuid3(uuid.NAMESPACE_DNS, unique_id))
        PushMap.insert_or_update({
            "push_token": push_token,
            "openid": open_id,
        })
        return jsonify({
            "code": 200,
            "token": push_token
        })
    return jsonify({
        "code": 404
    })

@app.route("/get_qrcode")
def get_qr_code():
    unique_id = request.args["unique_id"]
    qr_data = robot.client.create_qrcode(
        data={"expire_seconds": QR_EXP, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": QR_SCENE}}}
    )
    ticket = qr_data["ticket"]
    redis_client.set_ticket_unique(ticket, unique_id, QR_EXP)
    return jsonify(qr_data)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081, debug=True)


from django.http import response
from django.http.response import HttpResponse
from django.shortcuts import render

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

def analyze(request):

    # Get the text
    djtext = request.POST.get('text', 'default')
    removepunc1 = request.POST.get('removepunc1', 'off')
    fullcaps = request.POST.get('fullcaps', 'off')
    nlr = request.POST.get('nlr', 'off')
    extraspace = request.POST.get('extraspace', 'off')
    charcount = request.POST.get('charcount', 'off')

    # analyzed = djtext
    # print(analyzed)

    if removepunc1 == "on":
        punctuations = ''' !"#$%&'()*+, -./:;<=>?@[\]^_`{|}~ '''
        analyzed = ""

        for char in djtext:
            if char not in punctuations:
                analyzed = analyzed+char

        params = {'purpose': 'Removed Punctuations', 'analyzed_text': analyzed}
        djtext = analyzed
        # return render(request, 'analyze.html', params)

    if (fullcaps == "on"):
        analyzed = ""
        for char in djtext:
            analyzed = analyzed+char.upper()

        params = {'purpose': 'changed to UpperCase Character',
                  'analyzed_text': analyzed}
        djtext = analyzed
        # return render(request, 'analyze.html', params)

    if (nlr == "on"):
        analyzed = ""

        for char in djtext:
            if char != "\n" and char != "\r":
                analyzed = analyzed+char.upper()

        params = {'purpose': 'Removed NewLines',
                  'analyzed_text': analyzed}
        djtext = analyzed
        # return render(request, 'analyze.html', params)

    if (extraspace == "on"):
        analyzed = ""

        for char in djtext:
            if char != " ":
                analyzed = analyzed+char

        params = {'purpose': 'Removed Extra Space',
                  'analyzed_text': analyzed}
        djtext = analyzed
        # return render(request, 'analyze.html', params)

    if (charcount == "on"):
        count = 0

        for char in djtext:
            count = count+1

        params = {'purpose': 'No of characters in text',
                  'analyzed_text': count}
        #djtext = analyzed
        # return render(request, 'analyze.html', params)
    if (charcount != "on" and extraspace != "on" and nlr != "on" and removepunc1 != "on" and fullcaps != "on"):
        return HttpResponse("
Please select anyone option:
 ")

    return render(request, 'analyze.html', params)

def removepunc(request):
    return HttpResponse("remove punc")

def capitalisefirst(request):
    return HttpResponse("capitalize first")

def NewLineremove(request):
    return HttpResponse("capitalize first")

def spaceRemover(request):
    return HttpResponse("space remover")

def characterCounter(request):
    return HttpResponse("charcount ")


import math
from chapter_28_29.classtools import AttrDisplay

class Person(AttrDisplay):

    num_of_persons = 0

    def __init__(self, name, job=None, pay=0):
        self.name = name
        self.job = job
        self.pay = pay
        Person.num_of_persons += 1

    def lastName(self):  # Behavior methods
        return self.name.split()[-1]  # self is implied subject

    def giveRaise(self, percent):
        self.pay = self.pay * (1 + percent)  #

    # def __repr__(self):
    #     return ("Person:\nName={}, Job={}, Pay={:.2f}".format(self.name, self.job, self.pay))

class Manager(Person):

    num_of_managers = 0
    def __init__(self, name, pay):
        Person.__init__(self=self, name=name, job='Manager', pay=pay)
        Manager.num_of_managers += 1

    def giveRaise(self, percent, bonus=0.10):
        # Person.giveRaise(self, percent + bonus)
        super(Manager, self).giveRaise(percent + bonus)

class Department:

    def __init__(self, *staff):
        self.staff = list(staff)

    def add_employee(self, person):
        self.staff.append(person)

    def display_staff(self):
        for member in self.staff:
            print(member)

    def give_raise_to_all(self, percent):
        for member in self.staff:
            member.giveRaise(percent)

if __name__ == '__main__':
    bob = Person(name="Bob Jones")
    print("Number of instances of Person = {}, Manager = {}".format(Person.num_of_persons, Manager.num_of_managers))
    sue = Person(name="Suesane Smith", job="DBA", pay=100000)
    print("Number of instances of Person = {}, Manager = {}".format(Person.num_of_persons, Manager.num_of_managers))
    tom = Manager(name="Tom Logan", pay=110000)
    print("Number of instances of Person = {}, Manager = {}".format(Person.num_of_persons, Manager.num_of_managers))
    akshay = Manager(name='Akshay Shah', pay=150000)
    print("Number of instances of Person = {}, Manager = {}".format(Person.num_of_persons, Manager.num_of_managers))
    department = Department(bob, sue, tom, akshay)
    department.display_staff()
    department.give_raise_to_all(.05)
    department.display_staff()
    print("Number of instances of Person = {}, Manager = {}".format(Person.num_of_persons, Manager.num_of_managers))


from argparse import ArgumentParser
from .commands import commands
from .constants import ReturnCodes

parser = ArgumentParser(
    description='Lock and convert dependencies between formats.',
)
parser.add_argument('command', choices=commands.keys(), help='command to execute')

def main(argv):
    args = parser.parse_args(argv[:1])
    if args.command is None:
        parser.parse_args('--help')
    command = commands[args.command]
    task = command(argv[1:])

    is_valid = task.validate()
    if not is_valid:
        return ReturnCodes.INVALID_CONFIG.value

    result = task()
    if not result:
        return ReturnCodes.COMMAND_ERROR.value
    return ReturnCodes.OK.value


"""This modules contains quadrature methods."""
from grid import Grid
from legendre_functions import legendre_rec
import numpy as np

def quad_glob(fs, a, b, n):
    """Gauss Lobatto quadrature I(f(x)) = ∑ w_i(ξ_i) f_i(ξ_i).

    The weights are indicated by w_i (source worlfram).
    The nodal point ξ_i are the nodal points of gauss lobatto "grid".
    Error term ∝ f^{2n-2}
    Exact for p ∈ P_{2n-1}.

    Args:
        fs (list) = list of functions (if more than one is present they are multiplied pointwise).
        a (float) = start domain.
        b (float) = end domain.
        n (int) = degree of quadrature.

    Return:
        value (float) = value of the integral over the interval [a,b].
    """
    # Exact up to polinomial in P_(2n-1)
    # init grid
    grid = Grid(a, b, n)
    grid.gauss_lobatto()
    # init value of the integral
    value = 0
    for i in range(n + 1):
        if i == 0 or i == n:
            # weight for starting and ending point
            w_i = 2 / (n * (n + 1))
            value_partial = w_i
            for f in fs:
                value_partial *= f(grid.nodal_pts[i])
            value += value_partial
        else:
            # weights for the nodes
            w_i = 2 / (n * (n + 1) * legendre_rec(grid.nodal_pts[i], n) ** 2)
            value_partial = w_i
            for f in fs:
                value_partial *= f(grid.nodal_pts[i])
            value += value_partial
    # TODO(scaling to arbitrary interval)
    return value

def quad_trap(a, b, n, f, exact_int=0):
    """Trapezoid quadrature method.

        Args:
            a (float) = integration interval start
            b (float) = integration interval end
            n (int) = number of subintervals of integration
            f (obj func) = function to be integrated.
            exact_int (float : optional) = exact integral value

        Returns:
            integral_value (float) = value of the integral_value.
            error (float) = error of integration if available
    """
    # subintervals
    x = np.linspace(a, b, n + 1)
    # spacing
    h = (b - a) / n
    # trap quadrature
    num_int = h / 2 * (f(x) + f(x + h))
    # sum value of subintervals
    integral_value = np.sum(num_int[:-1])
    return integral_value, integral_value - exact_int

def quad_gauss(a, b, n, f, exact_int=0):
    """Gauss quadrature.
        Args:
            a (float) = integration interval start
            b (float) = integration interval end
            n (int) = number of subintervals of integration
            f (obj func) = function to be integrated.
            exact_int (float : optional) = exact integral value

        Returns:
            integral_value (float) = value of the integral_value.
            error (float) = error of integration if available
    """
    x = np.linspace(a, b, n + 1)
    h = (b - a) / n
    num_int = h / 2 * (f(x + h * ((-1 / 3 ** 0.5 + 1) / 2)) +
                       f(x + h * ((1 / 3 ** 0.5 + 1) / 2)))
    integral_value = np.sum(num_int[:-1])
    return integral_value, integral_value - exact_int

def quad_simpson(a, b, n, f, exact_int=0):
    """Simpson quadrature.

        Args:
            a (float) = integration interval start
            b (float) = integration interval end
            n (int) = number of subintervals of integration
            f (obj func) = function to be integrated.
            exact_int (float : optional) = exact integral value

        Returns:
            integral_value (float) = value of the integral_value.
            error (float) = error of integration if available
    """
    x = np.linspace(a, b, n + 1)
    h = (b - a) / n
    num_int = h / 2 * (1 / 3 * f(x) + 4 / 3 * f(x + h / 2) + 1 / 3 * f(x + h))
    integral_value = np.sum(num_int[:-1])
    return integral_value, integral_value - exact_int


# Given a binary tree, determine if it is height-balanced.
# For this problem, a height-balanced binary tree is defined as:
# a binary tree in which the left and right subtrees of every node differ in height by no more than 1.

class TreeNode:
    def __init__(self,x):
        self.val = x
        self.left = self.right = None

# class BinarySearchTree(object):
#     def __init__(self):
#         self.root = None
#
#     def insert(self, data):
#         self.root = self._insert_value(self.root, data)
#         return self.root is not None
#
#     def _insert_value(self, node, data):
#         if node is None:
#             node = TreeNode(data)
#         else:
#             if data <= node.data:
#                 node.left = self._insert_value(node.left, data)
#             else:
#                 node.right = self._insert_value(node.right, data)
#         return node

class Solution:

    class BalancedStatusWithHeight:
        isBalanced = True
        height = 0

        def __init__(self, isBalanced :bool, height: int):
            self.isBalanced = isBalanced
            self.height = height

    def isBalanced(self, root: TreeNode) -> bool:
        return self.checkBalanced(root).isBalanced

    def checkBalanced(self, root) -> BalancedStatusWithHeight:
        if root is None:
            return self.BalancedStatusWithHeight(True, -1)

        leftResult = self.checkBalanced(root.left)
        if leftResult.isBalanced is False:
            return leftResult

        rightResult = self.checkBalanced(root.right)
        if rightResult.isBalanced is False:
            return rightResult

        subtreesAreBalanced = abs(leftResult.height - rightResult.height) <= 1
        height = max(leftResult.height, rightResult.height) +1

        return self.BalancedStatusWithHeight(subtreesAreBalanced, height)

Algorithms/inwu/Trees, Biinary Trees, & Binary Search Trees/110.Balanced_Binary_Tree.py


# encoding: UTF-8

import psutil
import traceback

from vnpy.trader.vtFunction import loadIconPath
from vnpy.trader.vtGlobal import globalSetting

from uiCryptoWidget import *

########################################################################
class MainWindow(QtWidgets.QMainWindow):
    """主窗口"""

    signalStatusBar = QtCore.Signal(type(Event()))

    #----------------------------------------------------------------------
    def __init__(self, mainEngine, eventEngine):
        """Constructor"""
        super(MainWindow, self).__init__()

        self.mainEngine = mainEngine
        self.eventEngine = eventEngine

        l = self.mainEngine.getAllGatewayDetails()
        self.gatewayNameList = [d['gatewayName'] for d in l]

        self.widgetDict = {}    # 用来保存子窗口的字典

        # 获取主引擎中的上层应用信息
        self.appDetailList = self.mainEngine.getAllAppDetails()

        self.initUi()
        self.loadWindowSettings('custom')

    #----------------------------------------------------------------------
    def initUi(self):
        """初始化界面"""
        self.setWindowTitle('VnTrader')
        self.initCentral()
        self.initMenu()
        self.initStatusBar()

    #----------------------------------------------------------------------
    def initCentral(self):
        """初始化中心区域"""
        widgetTradingW, dockTradingW = self.createDock(TradingWidget, vtText.TRADING, QtCore.Qt.RightDockWidgetArea)
        widgetMarketM, dockMarketM = self.createDock(MarketMonitor, vtText.MARKET_DATA, QtCore.Qt.LeftDockWidgetArea)

        widgetOrderM, dockOrderM = self.createDock(OrderMonitor, vtText.ORDER, QtCore.Qt.LeftDockWidgetArea)
        widgetWorkingOrderM, dockWorkingOrderM = self.createDock(WorkingOrderMonitor, vtText.WORKING_ORDER, QtCore.Qt.LeftDockWidgetArea)
        widgetTradeM, dockTradeM = self.createDock(TradeMonitor, vtText.TRADE, QtCore.Qt.LeftDockWidgetArea)

        widgetAccountM, dockAccountM = self.createDock(AccountMonitor, vtText.ACCOUNT, QtCore.Qt.RightDockWidgetArea)
        widgetPositionM, dockPositionM = self.createDock(PositionMonitor, vtText.POSITION, QtCore.Qt.RightDockWidgetArea)
        widgetLogM, dockLogM = self.createDock(LogMonitor, vtText.LOG, QtCore.Qt.RightDockWidgetArea)

        self.tabifyDockWidget(dockOrderM, dockWorkingOrderM)
        self.tabifyDockWidget(dockPositionM, dockAccountM)

        # 保存默认设置
        self.saveWindowSettings('default')

    #----------------------------------------------------------------------
    def initMenu(self):
        """初始化菜单"""
        # 创建菜单
        menubar = self.menuBar()

        # 设计为只显示存在的接口
        gatewayDetails = self.mainEngine.getAllGatewayDetails()

        sysMenu = menubar.addMenu(vtText.SYSTEM)

        for d in gatewayDetails:
            if d['gatewayType'] == GATEWAYTYPE_FUTURES:
                self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName'])
        sysMenu.addSeparator()

        for d in gatewayDetails:
            if d['gatewayType'] == GATEWAYTYPE_EQUITY:
                self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName'])
        sysMenu.addSeparator()

        for d in gatewayDetails:
            if d['gatewayType'] == GATEWAYTYPE_INTERNATIONAL:
                self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName'])
        sysMenu.addSeparator()

        for d in gatewayDetails:
            if d['gatewayType'] == GATEWAYTYPE_BTC:
                self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName'])
        sysMenu.addSeparator()

        for d in gatewayDetails:
            if d['gatewayType'] == GATEWAYTYPE_DATA:
                self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName'])

        sysMenu.addSeparator()
        sysMenu.addAction(self.createAction(vtText.CONNECT_DATABASE, self.mainEngine.dbConnect, loadIconPath('database.ico')))
        sysMenu.addSeparator()
        sysMenu.addAction(self.createAction(vtText.EXIT, self.close, loadIconPath('exit.ico')))

        # 功能应用
        appMenu = menubar.addMenu(vtText.APPLICATION)

        for appDetail in self.appDetailList:
            # 如果没有应用界面，则不添加菜单按钮
            if not appDetail['appWidget']:
                continue

            function = self.createOpenAppFunction(appDetail)
            action = self.createAction(appDetail['appDisplayName'], function, loadIconPath(appDetail['appIco']))
            appMenu.addAction(action)

        # 帮助
        helpMenu = menubar.addMenu(vtText.HELP)
        helpMenu.addAction(self.createAction(vtText.CONTRACT_SEARCH, self.openContract, loadIconPath('contract.ico')))
        helpMenu.addAction(self.createAction(vtText.EDIT_SETTING, self.openSettingEditor, loadIconPath('editor.ico')))
        helpMenu.addSeparator()
        helpMenu.addAction(self.createAction(vtText.RESTORE, self.restoreWindow, loadIconPath('restore.ico')))
        helpMenu.addAction(self.createAction(vtText.ABOUT, self.openAbout, loadIconPath('about.ico')))
        helpMenu.addSeparator()
        helpMenu.addAction(self.createAction(vtText.TEST, self.test, loadIconPath('test.ico')))

    #----------------------------------------------------------------------
    def initStatusBar(self):
        """初始化状态栏"""
        self.statusLabel = QtWidgets.QLabel()
        self.statusLabel.setAlignment(QtCore.Qt.AlignLeft)

        self.statusBar().addPermanentWidget(self.statusLabel)
        self.statusLabel.setText(self.getCpuMemory())

        self.sbCount = 0
        self.sbTrigger = 10     # 10秒刷新一次
        self.signalStatusBar.connect(self.updateStatusBar)
        self.eventEngine.register(EVENT_TIMER, self.signalStatusBar.emit)

    #----------------------------------------------------------------------
    def updateStatusBar(self, event):
        """在状态栏更新CPU和内存信息"""
        self.sbCount += 1

        if self.sbCount == self.sbTrigger:
            self.sbCount = 0
            self.statusLabel.setText(self.getCpuMemory())

    #----------------------------------------------------------------------
    def getCpuMemory(self):
        """获取CPU和内存状态信息"""
        cpuPercent = psutil.cpu_percent()
        memoryPercent = psutil.virtual_memory().percent
        return vtText.CPU_MEMORY_INFO.format(cpu=cpuPercent, memory=memoryPercent)

    #----------------------------------------------------------------------
    def addConnectAction(self, menu, gatewayName, displayName=''):
        """增加连接功能"""
        if gatewayName not in self.gatewayNameList:
            return

        def connect():
            self.mainEngine.connect(gatewayName)

        if not displayName:
            displayName = gatewayName

        actionName = vtText.CONNECT + displayName
        connectAction = self.createAction(actionName, connect,
                                          loadIconPath('connect.ico'))
        menu.addAction(connectAction)

    #----------------------------------------------------------------------
    def createAction(self, actionName, function, iconPath=''):
        """创建操作功能"""
        action = QtWidgets.QAction(actionName, self)
        action.triggered.connect(function)

        if iconPath:
            icon = QtGui.QIcon(iconPath)
            action.setIcon(icon)

        return action

    #----------------------------------------------------------------------
    def createOpenAppFunction(self, appDetail):
        """创建打开应用UI的函数"""
        def openAppFunction():
            appName = appDetail['appName']
            try:
                self.widgetDict[appName].show()
            except KeyError:
                appEngine = self.mainEngine.getApp(appName)
                self.widgetDict[appName] = appDetail['appWidget'](appEngine, self.eventEngine)
                self.widgetDict[appName].show()

        return openAppFunction

    #----------------------------------------------------------------------
    def test(self):
        """测试按钮用的函数"""
        # 有需要使用手动触发的测试函数可以写在这里
        pass

    #----------------------------------------------------------------------
    def openAbout(self):
        """打开关于"""
        try:
            self.widgetDict['aboutW'].show()
        except KeyError:
            self.widgetDict['aboutW'] = AboutWidget(self)
            self.widgetDict['aboutW'].show()

    #----------------------------------------------------------------------
    def openContract(self):
        """打开合约查询"""
        try:
            self.widgetDict['contractM'].show()
        except KeyError:
            self.widgetDict['contractM'] = ContractManager(self.mainEngine)
            self.widgetDict['contractM'].show()

    #----------------------------------------------------------------------
    def openSettingEditor(self):
        """打开配置编辑"""
        try:
            self.widgetDict['settingEditor'].show()
        except KeyError:
            self.widgetDict['settingEditor'] = SettingEditor(self.mainEngine)
            self.widgetDict['settingEditor'].show()

    #----------------------------------------------------------------------
    def closeEvent(self, event):
        """关闭事件"""
        reply = QtWidgets.QMessageBox.question(self, vtText.EXIT,
                                           vtText.CONFIRM_EXIT, QtWidgets.QMessageBox.Yes |
                                           QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)

        if reply == QtWidgets.QMessageBox.Yes:
            for widget in self.widgetDict.values():
                widget.close()
            self.saveWindowSettings('custom')

            self.mainEngine.exit()
            event.accept()
        else:
            event.ignore()

    #----------------------------------------------------------------------
    def createDock(self, widgetClass, widgetName, widgetArea):
        """创建停靠组件"""
        widget = widgetClass(self.mainEngine, self.eventEngine)
        dock = QtWidgets.QDockWidget(widgetName)
        dock.setWidget(widget)
        dock.setObjectName(widgetName)
        dock.setFeatures(dock.DockWidgetFloatable|dock.DockWidgetMovable)
        self.addDockWidget(widgetArea, dock)
        return widget, dock

    #----------------------------------------------------------------------
    def saveWindowSettings(self, settingName):
        """保存窗口设置"""
        settings = QtCore.QSettings('vn.trader', settingName)
        settings.setValue('state', self.saveState())
        settings.setValue('geometry', self.saveGeometry())

    #----------------------------------------------------------------------
    def loadWindowSettings(self, settingName):
        """载入窗口设置"""
        settings = QtCore.QSettings('vn.trader', settingName)
        state = settings.value('state')
        geometry = settings.value('geometry')

        # 尚未初始化
        if state is None:
            return
        # 老版PyQt
        elif isinstance(state, QtCore.QVariant):
            self.restoreState(state.toByteArray())
            self.restoreGeometry(geometry.toByteArray())
        # 新版PyQt
        elif isinstance(state, QtCore.QByteArray):
            self.restoreState(state)
            self.restoreGeometry(geometry)
        # 异常
        else:
            content = u'载入窗口配置异常，请检查'
            self.mainEngine.writeLog(content)

    #----------------------------------------------------------------------
    def restoreWindow(self):
        """还原默认窗口设置（还原停靠组件位置）"""
        self.loadWindowSettings('default')
        self.showMaximized()

########################################################################
class AboutWidget(QtWidgets.QDialog):
    """显示关于信息"""

    #----------------------------------------------------------------------
    def __init__(self, parent=None):
        """Constructor"""
        super(AboutWidget, self).__init__(parent)

        self.initUi()

    #----------------------------------------------------------------------
    def initUi(self):
        """"""
        self.setWindowTitle(vtText.ABOUT + 'VnTrader')

        text = u"""
            Developed by Traders, for Traders.

            License：MIT

            Website：www.vnpy.org

            Github：www.github.com/vnpy/vnpy

            """

        label = QtWidgets.QLabel()
        label.setText(text)
        label.setMinimumWidth(500)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(label)

        self.setLayout(vbox)


#  Copyright 2021, Yahoo
#  Licensed under the terms of the Apache 2.0 license. See the LICENSE file in the project root for terms
from abc import ABC
from argparse import ArgumentParser, Namespace
from pathlib import Path
from typing import Any, Optional

from pydantic import ValidationError
from rich.console import Console
from rich.panel import Panel

from ..testplan.schema import TestPlan
from ..utils.argparse import SubCommand
from .exceptions import YChaosCLIError

class YChaosArgumentParser(ArgumentParser):
    """
    YChaosArgumentParser serves as a special parser to parse the
    CLI commands for ychaos. It provides utility methods to parse arguments,
    pass subcommand implementation and run a subcommand. It also handles
    the CLI exception gracefully by running the `handle` method of the exception raised.
    """

    def __init__(self, *args, **kwargs):
        """
        Initialize a YChaos Argument parser.

        Args:
            **kwargs: `__root__` for the root execution when no subcommand is thrown.
        """
        # __root__ SubCommand class determines the root of the YChaos
        # i.e. when YChaos CLI is called without any arguments
        self.__root__ = kwargs.pop("__root__", None)

        super(YChaosArgumentParser, self).__init__(*args, **kwargs)

    def parse_args(self, args=None, namespace=None) -> Namespace:  # type: ignore
        args = super(YChaosArgumentParser, self).parse_args(args, namespace)
        if not hasattr(args, "cls"):
            assert issubclass(self.__root__, SubCommand)
            args.cls = self.__root__

        return args

    def run_command(self, args: Namespace) -> int:
        """
        Run a subcommand from YChaos CLI
        """
        try:
            exitcode = args.cls.main(args)
        except YChaosCLIError as e:
            e.handle()
            exitcode = e.exitcode

        return exitcode

class YChaosSubCommand(SubCommand, ABC):

    _exitcode = 0

    def __init__(self, **kwargs):
        assert kwargs.pop("cls") == self.__class__

        self.app = kwargs.pop("app")
        self.console: Console = self.app.console

    def set_exitcode(self, exitcode=0):
        self._exitcode = exitcode

    @classmethod
    def main(cls, args: Namespace) -> Any:
        args.app.console.log("This command does nothing..")
        return 0

class YChaosTestplanInputSubCommand(YChaosSubCommand, ABC):
    @classmethod
    def build_parser(cls, parser: ArgumentParser) -> ArgumentParser:
        parser.add_argument(
            "-t",
            "--testplan",
            type=Path,
            required=True,
            help="The testplan path. This can be relative path from where the CLI is initiated",
            metavar="path",
        )

        return parser

    def get_validated_test_plan(self, path: Path) -> Optional[TestPlan]:
        self.console.log("Getting Test plan")
        self.console.line()
        try:
            testplan = TestPlan.load_file(path=path)
            return testplan
        except ValidationError as validation_error:
            self.set_exitcode(1)
            self.console.print(
                Panel.fit(str(validation_error), title="Validation Error", style="red")
            )
        except IsADirectoryError as is_directory:
            self.set_exitcode(1)
            self.console.print(
                ":file_folder: The input path ({path}) is not a valid testplan file".format(
                    path=path
                )
            )
        except FileNotFoundError as file_not_found_error:
            self.set_exitcode(1)
            self.console.print(
                ":mag: {file} [italic]not found[/italic]".format(file=str(path)),
                style="indian_red",
            )
        return None

class YChaosCLIHook(ABC):
    """
    The Base CLI Hook. Implement the `__call__` method with appropriate signature
    for each of the hook type. The `__call__` method gets called from the EventHook
    methods whenever an event is occurred.
    """

    def __init__(self, app, *args, **kwargs):
        self.app = app
        self.console = app.console

        # Determines if this hooks is active and callable.
        self.active = True


#calss header
class _ROAST():
	def __init__(self,):
		self.name = "ROAST"
		self.definitions = [u'to cook food in an oven or over a fire: ', u'to heat nuts or coffee beans so that they become drier and browner', u'to criticize severely or speak angrily to someone']

		self.parents = []
		self.childen = []
		self.properties = []
		self.jsondata = {}

		self.specie = 'verbs'

	def run(self, obj1 = [], obj2 = []):
		return self.jsondata


__author__ = 'linweizhong'
# coding:utf-8
"""
Majority Element
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.
"""
class Solution:
    # @param num, a list of integers
    # @return an integer
    def majorityElement(self, num):
        numdict = {}
        for item in num:
            if item in numdict :
                numdict[item] += 1
            else:
                numdict[item] = 1

        halflen = len(num)/2
        for key in numdict :
            if numdict[key] > halflen :
                return  key
        return  None


def solution(answers):
    answer = []
    supo1 = [1, 2, 3, 4, 5]
    supo2 = [2, 1, 2, 3, 2, 4, 2, 5]
    supo3 = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]
    num1 = 5
    num2 = 8
    num3 = 10

    ans_num = len(answers)

    supo1_ans = supo1 * (ans_num // num1) + supo1[:ans_num % num1]
    supo2_ans = supo2 * (ans_num // num2) + supo2[:ans_num % num2]
    supo3_ans = supo3 * (ans_num // num3) + supo3[:ans_num % num3]

    correct_1 = 0
    correct_2 = 0
    correct_3 = 0

    for i in range(ans_num):
        answer_i = answers[i]

        if supo1_ans[i] == answer_i:
            correct_1 += 1
        if supo2_ans[i] == answer_i:
            correct_2 += 1
        if supo3_ans[i] == answer_i:
            correct_3 += 1

    ans = max(correct_1, correct_2, correct_3)

    if ans == correct_1:
        answer.append(1)
    if ans == correct_2:
        answer.append(2)
    if ans == correct_3:
        answer.append(3)

    return answer


import tagging
from django.db import models
from tagging.fields import TagField

class Taggable(models.Model):
    name = models.CharField(max_length=50)
    tags = TagField(null=True, blank=True)
    parent = models.ForeignKey('self', null=True, blank=True)

    def __unicode__(self):
        return self.name

tagging.register(Taggable, tag_descriptor_attr='etags')


from __future__ import print_function
from pyiid.tests import *
import numpy as np
from pyiid.calc.spring_calc import Spring
from ase import Atom
from unittest import SkipTest
from builtins import range
import pytest

__author__ = 'christopher'

def check_meta(value):
    value[0](value[1:])

def check_voxel_nrg(value):
    if value[1]['sp_type'] == 'com':
        raise SkipTest(
            'the center of mass moves on addition/removal of atoms, '
            'making this very complex. COM will be depreciated soon')
    atoms = dc(value[0])
    resolution = 1.
    atoms.center(resolution)
    calc = Spring(**value[1])
    atoms.set_calculator(calc)
    e0 = atoms.get_potential_energy()
    voxel_nrg = atoms.calc.calculate_voxel_energy(atoms, resolution)

    voxel_nrg2 = np.zeros(voxel_nrg.shape)
    im, jm, km = voxel_nrg2.shape
    for i in range(im):
        x = (i + .5) * resolution
        for j in range(jm):
            y = (j + .5) * resolution
            for k in range(km):
                z = (k + .5) * resolution
                atoms2 = dc(atoms)
                atoms2 += Atom('Au', (x, y, z))
                voxel_nrg2[i, j, k] += atoms2.get_potential_energy() - e0
    stats_check(voxel_nrg, voxel_nrg2, rtol=2e-7)
    assert_allclose(voxel_nrg, voxel_nrg2, rtol=2e-7)

def check_atomwise_nrg(value):
    if value[1]['sp_type'] == 'com':
        raise SkipTest(
            'the center of mass moves on addition/removal of atoms, '
            'making this very complex. COM will be depreciated soon')
    atoms = dc(value[0])
    resolution = 1.
    atoms.center(resolution)
    calc = Spring(**value[1])
    atoms.set_calculator(calc)
    e0 = atoms.get_potential_energy()
    print(e0, e0 / 2.)
    voxel_nrg = atoms.calc.calculate_atomwise_energy(atoms)

    nrg2 = np.zeros(len(atoms))
    for atom in atoms:
        atoms2 = dc(atoms)
        del atoms2[atom.index]
        nrg2[atom.index] += atoms2.get_potential_energy() - e0
    stats_check(voxel_nrg, nrg2)
    assert_allclose(voxel_nrg, nrg2)

tests = [
    check_voxel_nrg,
    check_atomwise_nrg
]

test_data = tuple(
    product(tests,
            # test_atoms,
            [test_atom_squares[0][0]],
            test_spring_kwargs))

@pytest.mark.parametrize("a", test_data)
def test_meta(a):
    check_meta(a)


import requests
import re
import xlrd as xl
import pytest
from bs4 import BeautifulSoup
# import socket
# socket.setdefaulttimeout(15)

def check_title(url, title, description1):
    header = {
        "Connection": "close",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"
    }
    r = requests.get(url, headers=header)

    if r.status_code != 200:
        print(f"Error code: {r.status_code}")
    res = r.text
    html = BeautifulSoup(res, 'html.parser')
    title1 = html.title.string   # 获取title里面的内容
    description = html.find(attrs={"name": "description"})['content']
    if description.strip() != description1.strip():
        print(f"Error description:\n{description1}\n{description} ")
    if title1 != title:
        print(f"Error title: {title}")

def get_data_from_excel():
    xls_file = xl.open_workbook("./test.xlsx")#打开文件
    # print(len(xls_file.sheets()))#获得表格工作簿的个数（包括空的工作簿）
    xls_sheet = xls_file.sheets()[0]#打开文件簿，第一个文件簿用[0]表示

    # print(xls_sheet.nrows)#返回工作簿的行数
    # print(xls_sheet.ncols)#返回工作簿的列数

    li = []
    for i in range(132):
        row_value = xls_sheet.row_values(i)#第一行所有的值
        li.append(row_value)

    print(len(li))

    for j in range(80, 133):
        url = li[j][0].replace("www.malts", "malts:Classic@123@secure-malts.diageoplatform")
        title = li[j][2]
        description = li[j][3]
        check_title(url, title, description)
        print(f"{j} success")

get_data_from_excel()


# -- coding: utf-8 --
from selenium.webdriver.common.by import By
from testCase.common.commonPage import Common
from testCase.model.getuserInfo import getYaml
from time import sleep
from ruamel import yaml
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

'''创建首页登录页面的类'''
class userMgtPage(Common):
    #u_para = "/news/" # 当调用open()方法时相当于构造的url="http://localhost/news/"

    # 设置定位器
    repassword_loc= (By.NAME,"repassword")
    submit3_loc = (By.NAME,"Submit3")
    email_loc = (By.NAME,"email")
    company_loc = (By.NAME,"company")
    truename_loc = (By.NAME,"truename")
    oicq_loc = (By.NAME,"oicq")
    msn_loc = (By.NAME,"msn")
    mycall_loc = (By.NAME,"mycall")
    fax_loc = (By.NAME,"fax")
    phone_loc = (By.NAME,"phone")
    homepage_loc = (By.NAME,"homepage")
    userpicfile_loc = (By.NAME,"userpicfile")
    address_loc = (By.NAME,"address")
    zip_loc = (By.NAME,"zip")
    saytext_loc = (By.NAME,"saytext")
    #注册
    register_loc = (By.NAME,"Submit2")
    option_loc = (By.XPATH,"//input[@value='3']")
    nextBtn_loc = (By.NAME,"button")
    #会员中心
    openVipAss_loc = (By.PARTIAL_LINK_TEXT, "站内消息")
    #修改资料
    editProfile_loc = (By.PARTIAL_LINK_TEXT, "修改资料")
    editSuc_loc=(By.PARTIAL_LINK_TEXT,"修改信息成功！")
    #会员中心-修改安全信息
    editPsd_loc = (By.PARTIAL_LINK_TEXT,"修改安全信息")
    oldpsd_loc = (By.ID,"oldpassword")
    #设置登录成功和失败的定位器
    loginPassAss_loc = (By.PARTIAL_LINK_TEXT,"我的空间")   # 登录成功后出现“我的空间”元素
    #收藏夹
    openBm_loc = (By.PARTIAL_LINK_TEXT,"收藏夹")
    addBmType_loc = (By.PARTIAL_LINK_TEXT,"管理分类")
    cname_loc = (By.ID,"cname")
    typeName_loc = (By.XPATH,"//table[@class='tableborder'][2]/tbody/tr[1]/td[2][contains(.,'分类名称')]")
    favaid_loc = (By.NAME,"favaid[]")
    submit4_loc = (By.XPATH,"//input[@name='Submit'][2]")
    eleText1_loc = (By.XPATH, "//table[@class='tableborder'][2]/tbody/tr[2]/td[2]/div/a")
    # cid1_loc = (By.XPATH,"//table[@class='tableborder'][2]/tbody/tr[3]/td/select")
    # cidOp1_loc = (By.XPATH, "//table[@class='tableborder'][2]/tbody/tr[3]/td/select/option")
    cid1_loc = (By.XPATH, "//select[@name='cid' and @style='']")
    cidOp1_loc = (By.XPATH, "//select[@name='cid' and @style='']/option")
    #收藏夹分类记录数
    eleTextMod_loc = (By.XPATH, "//table[@class='tableborder'][2]/tbody/tr/td[2]/div/input[3]")

    #好友列表
    openFriendList_loc = (By.PARTIAL_LINK_TEXT,"好友列表")
    addFriend_loc = (By.PARTIAL_LINK_TEXT,"添加好友")
    eleTextMod1_loc = (By.XPATH, "//table[@class='tableborder'][2]/tbody/tr/td[2]/div/input[4]")
    fname_loc = (By.NAME,"fname")
    fsay_loc = (By.NAME,"fsay")
    eleTextMod2_loc = (By.ID,"fsay[]")
    modLink_loc = (By.XPATH, "//table[@class='tableborder'][2]/tbody/tr[2]/td[4]/div/a[1]")
    delLink_loc = (By.XPATH, "//table[@class='tableborder'][2]/tbody/tr[2]/td[4]/div/a[2]")

    '''注册类'''
    # 普通会员注册
    def type_perRegisterT(self):
        try:
            print("\033[1;35;0m 普通会员注册...\033[0m")
            self.u_para=""
            self.open()
            self.find_element(*self.register_loc).click()
            sleep(1)
            handles = self.driver.window_handles
            self.driver.switch_to.window(handles[-1])
            self.find_element(*self.nextBtn_loc).click()
            #数据填充
            self.type_getAccount()
            self.type_username(self.randoma)
            #每次注册都会覆盖account.yaml中的account对应的文本值，同时确保用于添加好友时，账号是最新的
            data=getYaml('account.yaml')
            with open('F:\\Python\\phomeNetFront\\test_data\\yaml\\account.yaml', 'w', encoding="utf-8") as file:
                data['account']=self.randoma
                yaml.dump(data,file,Dumper=yaml.RoundTripDumper)
            self.type_setPerVip('0')
            self.type_submit()
        except BaseException as msg:
            print(msg)

    # 企业会员注册
    def type_comRegisterT(self):
        try:
            print("\033[1;35;0m 企业会员注册...\033[0m")
            self.u_para = ""
            self.open()
            self.find_element(*self.register_loc).click()
            sleep(1)
            handles = self.driver.window_handles
            self.driver.switch_to.window(handles[-1])
            self.find_element(*self.option_loc).click()
            self.find_element(*self.nextBtn_loc).click()
            #数据填充
            self.type_getAccount()
            self.type_username(self.randoma)
            self.type_setComVip('0')
            self.type_submit()
        except BaseException as msg:
            print(msg)

    '''打开页面'''

    '''修改类'''
    #修改资料
    def type_acc_editProfile(self):
        try:
            print("\033[1;35;0m 会员中心修改资料...\033[0m")
            self.find_element(*self.editProfile_loc).click()
            self.type_setPerVip('nopsd')
            self.find_element(*self.submit_loc).click()
        except BaseException as msg:
            print(msg)

    #新增或修改普通会员信息,动态变化的有两个，email和oicq
    def type_setPerVip(self,type):
        try:
            print("\033[1;35;0m update普通会员信息...\033[0m")
            data = getYaml('userInfo.yaml')
            print(data)
            if type != 'nopsd':
                self.type_password(data['reUserT']['password'])
                self.find_element(*self.repassword_loc).send_keys(data['reUserT']['repassword'])
                self.find_element(*self.email_loc).send_keys(str(self.randoma)+data['reUserT']['email'])
            self.find_element(*self.truename_loc).clear()
            self.find_element(*self.truename_loc).send_keys(data['reUserT']['truename'])
            self.find_element(*self.oicq_loc).clear()
            self.randoma=self.type_getAccount()
            self.find_element(*self.oicq_loc).send_keys(self.randoma)
            self.find_element(*self.msn_loc).clear()
            self.find_element(*self.msn_loc).send_keys(data['reUserT']['msn'])
            self.find_element(*self.mycall_loc).clear()
            self.find_element(*self.mycall_loc).send_keys(data['reUserT']['mycall'])
            self.find_element(*self.phone_loc).clear()
            self.find_element(*self.phone_loc).send_keys(data['reUserT']['phone'])
            self.find_element(*self.homepage_loc).clear()
            self.find_element(*self.homepage_loc).send_keys(data['reUserT']['homepage'])
            self.find_element(*self.userpicfile_loc).clear()
            self.find_element(*self.userpicfile_loc).send_keys(self.userpicfile_path)
            self.find_element(*self.address_loc).clear()
            self.find_element(*self.address_loc).send_keys(data['reUserT']['address'])
            self.find_element(*self.zip_loc).clear()
            self.find_element(*self.zip_loc).send_keys(data['reUserT']['zip'])
            self.find_element(*self.saytext_loc).clear()
            self.find_element(*self.saytext_loc).send_keys(data['reUserT']['saytext'])
            with open('F:\\Python\\phomeNetFront\\test_data\\yaml\\userInfo.yaml', 'w', encoding="utf-8") as file:
                data['reUserT']['oicq'] = self.randoma
                yaml.dump(data, file, Dumper=yaml.RoundTripDumper)
        except BaseException as msg:
            print(msg)

    #新增或修改企业会员信息
    def type_setComVip(self,type):
        try:
            print("\033[1;35;0m update企业会员信息...\033[0m")
            data = getYaml('userInfo.yaml')
            if type != 'nopsd':
                self.type_password(data['reComT']['password'])
                self.find_element(*self.repassword_loc).send_keys(data['reComT']['repassword'])
            self.find_element(*self.email_loc).send_keys(str(self.randoma) + data['reComT']['email'])
            self.find_element(*self.company_loc).send_keys(data['reComT']['company'])
            self.find_element(*self.truename_loc).send_keys(data['reComT']['truename'])
            self.find_element(*self.mycall_loc).send_keys(data['reComT']['mycall'])
            self.find_element(*self.oicq_loc).send_keys(data['reComT']['oicq'])
            self.find_element(*self.msn_loc).send_keys(data['reComT']['msn'])
            self.find_element(*self.fax_loc).send_keys(data['reComT']['fax'])
            self.find_element(*self.phone_loc).send_keys(data['reComT']['phone'])
            self.find_element(*self.homepage_loc).send_keys(data['reComT']['homepage'])
            self.find_element(*self.userpicfile_loc).send_keys(self.userpicfile_path)
            self.find_element(*self.address_loc).send_keys(data['reComT']['address'])
            self.find_element(*self.zip_loc).send_keys(data['reComT']['zip'])
            self.find_element(*self.saytext_loc).send_keys(data['reComT']['saytext'])
        except BaseException as msg:
            print(msg)

    def type_setPsd(self):
        try:
            print("\033[1;35;0m 修改密码...\033[0m")
            self.find_element(*self.editPsd_loc).click()
            print("randNo is :%d" %self.randoma)
            data=getYaml('userInfo.yaml')
            self.find_element(*self.oldpsd_loc).send_keys(data['loUser']['password'])
            sleep(1)
            self.find_element(*self.password_loc).send_keys(self.randoma)
            self.find_element(*self.repassword_loc).send_keys(self.randoma)
            sleep(1)
            self.find_element(*self.submit_loc).click()
            with open('F:\\Python\\phomeNetFront\\test_data\\yaml\\userInfo.yaml', 'w', encoding="utf-8") as file:
                data['loUser']['password'] = self.randoma
                data['loUser']['repassword'] = self.randoma
                yaml.dump(data, file, Dumper=yaml.RoundTripDumper)
        except BaseException as msg:
            print(msg)

    '''收藏夹'''
    def type_openBookmarks(self):
        try:
            print("\033[1;31;40m 打开收藏夹管理页面 \033[0m")
            sleep(1)
            self.find_element(*self.openBm_loc).click()
        except BaseException as msg:
            print(msg)

    def type_openBookmarksType(self):
        try:
            print("\033[1;31;40m 打开收藏夹分类管理页面 \033[0m")
            self.find_element(*self.addBmType_loc).click()
        except BaseException as msg:
            print(msg)

    def type_addBookmarksType(self):
        try:
            print("\033[1;35;0m 添加收藏夹分类...\033[0m")
            count1 = self.get_listCount(self.eleText_loc)
            self.type_getAccount()
            self.find_element(*self.cname_loc).send_keys(self.randoma)
            self.find_element(*self.submit_loc).click()
            self.append_excel("bookmarksType.xlsx", str(self.randoma))
            return count1
        except BaseException as msg:
            print(msg)

    def type_modBookmarksType(self):
        try:
            print("\033[1;35;0m 修改收藏夹分类...\033[0m")
            self.type_getAccount()
            self.find_element(*self.eleTextMod_loc).clear()
            self.find_element(*self.eleTextMod_loc).send_keys(self.randoma)
            self.find_element(*self.submit2_loc).click()
            sleep(1)
            text=self.find_element(*self.eleTextMod_loc).get_attribute('value')
            self.mod_excel("bookmarksType.xlsx", str(self.randoma))
            return text
        except BaseException as msg:
            print(msg)

    def type_delBookmarksType(self):
        try:
            print("\033[1;35;0m 删除收藏夹分类...\033[0m")
            self.find_element(*self.submit3_loc).click()
            self.type_getAlert()
            row = self.get_ExcelRow("bookmarksType.xlsx")
            self.del_excel("bookmarksType.xlsx", row)
        except BaseException as msg:
            print(msg)

    def type_delBookmarksInfo(self):
        try:
            print("\033[1;35;0m 删除收藏夹收藏的信息...\033[0m")
            self.find_element(*self.favaid_loc).click()
            sleep(1)
            element = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located(self.submit4_loc))
            self.driver.execute_script("arguments[0].click();",element)
            # self.find_element(*self.submit4_loc).click()
            sleep(1)
            self.type_getAlert()
        except BaseException as msg:
            print(msg)

    def type_transferBookmarksInfo(self):
        try:
            print("\033[1;35;0m 将信息转移到另一个收藏夹...\033[0m")
            self.find_element(*self.favaid_loc).click()
            tuples = self.get_ranExcelText("bookmarksType.xlsx")
            row = tuples[0]
            text = tuples[1]
            '''这里无法使用id、Xpath[@id='**']对select进行定位,用相对路径'''
            s=self.find_elements(*self.cid_loc)
            tels=s[1].find_elements(*self.cidOp_loc)
            # tels = self.find_elements(*self.cidOp1_loc)
            lists = []
            for i in tels:
                lists.append(i.text)
            print("list is :%r" % lists)
            if text in lists:
                print("text in lists")
                s[1].click()
                select_ele = Select(self.find_element(*self.cid1_loc))
                select_ele.select_by_index(row + 1)  # 选中从excel随机得到的分组
                self.get_sreenshot().insert_img(self.driver,"userMgt_11transferBookmarksInfo00.png")
                self.find_element(*self.submit_loc).click()
                self.type_getAlert()
                return (row + 1)
        except BaseException as msg:
            print(msg)

    def type_checkBmInfoTransfer(self,row):
        try:
            select_ele = Select(self.find_element(*self.cid_loc))
            select_ele.select_by_index(row)  #判断是否转移成功
        except BaseException as msg:
            print(msg)

    '''好友列表'''
    def type_openFriendList(self):
        try:
            print("\033[1;31;40m 打开好友列表管理页面 \033[0m")
            self.find_element(*self.openFriendList_loc).click()
        except BaseException as msg:
            print(msg)

    def type_addFriendType(self):
        try:
            self.find_element(*self.addBmType_loc).click()
            print("\033[1;35;0m 添加好友分类...\033[0m")
            count1 = self.get_listCount(self.eleText_loc)
            self.type_getAccount()
            self.find_element(*self.cname_loc).send_keys(self.randoma)
            self.find_element(*self.submit_loc).click()
            self.append_excel("friendType.xlsx",str(self.randoma))
            self.get_excelList("friendType.xlsx")
            sleep(3)
            return count1
        except BaseException as msg:
            print(msg)

    def type_modFriendType(self):
        try:
            print("\033[1;35;0m 修改好友分类...\033[0m")
            self.type_getAccount()
            self.find_element(*self.eleTextMod1_loc).clear()
            self.find_element(*self.eleTextMod1_loc).send_keys(self.randoma)
            self.find_element(*self.submit2_loc).click()
            sleep(1)
            text=self.find_element(*self.eleTextMod1_loc).get_attribute('value')
            self.mod_excel("friendType.xlsx",str(self.randoma))
            self.get_excelList("friendType.xlsx")
            return text
        except BaseException as msg:
            print(msg)

    def type_delFriendType(self):
        try:
            print("\033[1;35;0m 删除好友分类...\033[0m")
            self.find_element(*self.submit3_loc).click()
            self.type_getAlert()
            row=self.get_ExcelRow("friendType.xlsx")
            self.del_excel("friendType.xlsx",row)
        except BaseException as msg:
            print(msg)

    def type_addFriend(self):
        try:
            self.type_openFriendList()
            count1 = self.get_listCount(self.eleText_loc)
            self.find_element(*self.addFriend_loc).click()
            print("\033[1;35;0m 添加好友...\033[0m")
            data=getYaml("account.yaml")
            self.randoma=data['account']
            print("randma is :%s"%self.randoma)
            self.find_element(*self.fname_loc).send_keys(self.randoma)
            # 为好友选择分组
            tuples=()#用元组接收get_ranExcelText()返回的元组，第一个值是行数，第二个值是行数对应的文本值（分组）
            tuples=self.get_ranExcelText("friendType.xlsx")
            row=tuples[0]
            text=tuples[1]
            tels=self.find_elements(*self.cidOp_loc)
            lists = []
            for i in tels:
                lists.append(i.text)
            print("list is :%r" % lists)
            if text in lists:
                print("text in lists")
                self.find_element(*self.cid_loc).click()
                select_ele=Select(self.find_element(*self.cid_loc))
                select_ele.select_by_index(row+1)#选中从excel随机得到的分组

            self.find_element(*self.fsay_loc).send_keys(self.randoma)
            self.find_element(*self.submit_loc).click()
            self.append_excel("friend.xlsx",str(self.randoma))
            return count1
        except BaseException as msg:
            print(msg)

    def type_modFriend(self):
        try:
            print("\033[1;35;0m 修改好友分类...\033[0m")
            self.type_getAccount()
            self.find_element(*self.modLink_loc).click()
            self.find_element(*self.fsay_loc).clear()
            self.find_element(*self.fsay_loc).send_keys(self.randoma)
            self.find_element(*self.submit_loc).click()
            sleep(1)
            text=self.find_element(*self.eleTextMod2_loc).get_attribute('value')
            return text
        except BaseException as msg:
            print(msg)

    def type_delFriend(self):
        try:
            print("\033[1;35;0m 删除好友...\033[0m")
            self.find_element(*self.delLink_loc).click()
            self.type_getAlert()
            row=self.get_ExcelRow("friend.xlsx")
            self.del_excel("friend.xlsx",row)
        except BaseException as msg:
            print(msg)


'''
스킬트리
문제 설명
선행 스킬이란 어떤 스킬을 배우기 전에 먼저 배워야 하는 스킬을 뜻합니다.

예를 들어 선행 스킬 순서가 스파크 → 라이트닝 볼트 → 썬더일때, 썬더를 배우려면 먼저 라이트닝 볼트를 배워야 하고, 라이트닝 볼트를 배우려면 먼저 스파크를 배워야 합니다.

위 순서에 없는 다른 스킬(힐링 등)은 순서에 상관없이 배울 수 있습니다. 따라서 스파크 → 힐링 → 라이트닝 볼트 → 썬더와 같은 스킬트리는 가능하지만, 썬더 → 스파크나 라이트닝 볼트 → 스파크 → 힐링 → 썬더와 같은 스킬트리는 불가능합니다.

선행 스킬 순서 skill과 유저들이 만든 스킬트리1를 담은 배열 skill_trees가 매개변수로 주어질 때, 가능한 스킬트리 개수를 return 하는 solution 함수를 작성해주세요.

제한 조건
스킬은 알파벳 대문자로 표기하며, 모든 문자열은 알파벳 대문자로만 이루어져 있습니다.
스킬 순서와 스킬트리는 문자열로 표기합니다.
예를 들어, C → B → D 라면 CBD로 표기합니다
선행 스킬 순서 skill의 길이는 1 이상 26 이하이며, 스킬은 중복해 주어지지 않습니다.
skill_trees는 길이 1 이상 20 이하인 배열입니다.
skill_trees의 원소는 스킬을 나타내는 문자열입니다.
skill_trees의 원소는 길이가 2 이상 26 이하인 문자열이며, 스킬이 중복해 주어지지 않습니다.

solution("CBD",["BACDE", "CBADF", "AECB", "BDA"])

'''

def solution(skill, skill_trees):
    answer = 0

    for str in skill_trees:
        temp = ""
        isok = True #동등비교를 위한 변수
        print(str)

        for i in str: # skill과 skill_trees를 비교하여 skill에 포함된 스킬만 저장
            if skill.find(i) != -1:
                temp += i

        for j in range(len(temp)): # skill의 순서와 temp에 저장된 순서가 다르면 false
            if skill[j] != temp[j]:
                isok = False
                break

        if isok == True: #skill과 temp에 저장된 변수가 같다면 answer +=1
           answer+=1

    return answer


from flask import request, Blueprint
from app import db, jsonify
from app.models import DistributionType
from app.utils import decorators
from app.utils.constants import StatusErrors as errors
from sqlalchemy import func

api = Blueprint("admin_dist_type_api", __name__, url_prefix="/api/admin/dist_type")

@api.route("/list", methods=["GET"])
@decorators.login_required
@decorators.only_admins
def list():
    dist_type = DistributionType.query.all()
    dist_type = [d.serialize() for d in dist_type]
    return jsonify(dict(status="success", distribution_types=dist_type))

@api.route("/add", methods=["POST"])
@decorators.login_required
@decorators.only_admins
def add():
    data = request.json or request.data or request.form
    res_code = 200
    res = dict(status="fail")
    name = data.get("name")
    description = data.get("description")
    query = DistributionType.query.filter(
        func.lower(DistributionType.name) == func.lower(name)
    )
    if query.count() > 0:
        res["statusText"] = errors.CUSTOM_ERROR.text
        res["statusData"] = errors.CUSTOM_ERROR.type(
            "Distribution Type of this name already exists"
        )
        return jsonify(res), res_code
    dist_type = DistributionType(name=name, description=description)
    db.session.add(dist_type)
    db.session.commit()
    res["status"] = "success"
    res["dist_type"] = dist_type.serialize()
    return jsonify(res)