import os
import math
import numpy as np
import pandas as pd
from scipy.signal import find_peaks
from imblearn.over_sampling import RandomOverSampler
from sklearn.preprocessing import LabelEncoder
from tensorflow import keras
from tensorflow.keras import layers
import joblib
import stockDataHandler
from sklearn.preprocessing import MinMaxScaler

def min_max_normalization(data, columns):
    normalized_data = data.copy()
    scalers = {}
    for column in columns:
        scaler = MinMaxScaler()
        normalized_data[column] = scaler.fit_transform(data[column].values.reshape(-1, 1)).flatten()
        scalers[column] = scaler
    return normalized_data, scalers

def percent_return(data, columns):
    for column in columns:
        data[column] = data[column].pct_change()
    return data

# Load the data
stock_data = stockDataHandler.LoadData('onehour2018_2023.csv')
stockDataHandler.SetEMA(stock_data, 50, 'EMA50')
stockDataHandler.SetEMA(stock_data, 100, 'EMA100')
stockDataHandler.SetMacd(stock_data, 50)
stockDataHandler.CleanData(stock_data)

numberOfBars = 100

# Label generation
min_prominence = 150
peak_indexes, _ = find_peaks(stock_data['Original_Close'].values, prominence=min_prominence)
valley_indexes, _ = find_peaks(-stock_data['Original_Close'].values, prominence=min_prominence)
sell_indexes = peak_indexes
buy_indexes = valley_indexes

stock_data.loc[stock_data.index[sell_indexes], 'Signal'] = 'Sell'
stock_data.loc[stock_data.index[buy_indexes], 'Signal'] = 'Buy'
stock_data['Signal'].fillna('Hold', inplace=True)

# Split the data
training_data_len = math.ceil(len(stock_data) * 0.7)
train_data = stock_data[:training_data_len]

columns_to_percent_return = ['Open', 'Close', 'High', 'Low']
columns_to_min_max_normalize = ['Volume', 'EMA50', 'EMA100', 'MACD']

# Apply the desired transformations
train_data = percent_return(train_data, columns_to_percent_return)
train_data_min_max, min_max_scalers = min_max_normalization(train_data, columns_to_min_max_normalize)
train_data[columns_to_min_max_normalize] = train_data_min_max[columns_to_min_max_normalize]

# Drop NaN values after transformations
train_data = train_data.dropna()

# Print signal counts
signal_counts = train_data['Signal'].value_counts()
print("Number of 'Buy', 'Sell', and 'Hold' signals in training data:")
print(signal_counts)

# Prepare data for LSTM
x_train = []
y_train = []

for i in range(numberOfBars, len(train_data)):
    x_train.append(train_data[columns_to_percent_return + columns_to_min_max_normalize].iloc[i - numberOfBars:i].values)
    y_train.append(train_data.iloc[i]['Signal'])

x_train = np.array(x_train)
encoder = LabelEncoder()
y_train_encoded = encoder.fit_transform(y_train)

y_train_encoded = keras.utils.to_categorical(y_train_encoded)

# Oversampling
ros = RandomOverSampler(random_state=0)
x_train_resampled, y_train_encoded_resampled = ros.fit_resample(x_train.reshape(x_train.shape[0], -1), y_train_encoded)
x_train_resampled = x_train_resampled.reshape(-1, x_train.shape[1], x_train.shape[2])
y_train_resampled = keras.utils.to_categorical(y_train_encoded_resampled)

cost_matrix = np.array([
    [0, 1, 1],  # Kostnad fra Buy til [Buy, Sell, Hold]
    [1, 0, 1],  # Kostnad fra Sell til [Buy, Sell, Hold]
    [1, 1, 0]   # Kostnad fra Hold til [Buy, Sell, Hold]
])

import tensorflow as tf
def cost_sensitive_loss(y_true, y_pred):
    cost_values = tf.reduce_sum(cost_matrix * y_true, axis=-1)
    cost_values = tf.cast(cost_values, tf.float32)
    loss = tf.reduce_sum(cost_values * tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=y_pred), axis=-1)
    return loss

# LSTM model
model = keras.Sequential()
model.add(layers.LSTM(100, return_sequences=True, input_shape=(x_train_resampled.shape[1], len(columns_to_percent_return + columns_to_min_max_normalize))))
model.add(layers.LSTM(100, return_sequences=True))
model.add(layers.LSTM(100, return_sequences=False))
model.add(layers.Dense(50))
model.add(layers.Dense(y_train_encoded_resampled.shape[1], activation='softmax'))
model.summary()

# Laster inn tidligere modell:
modelname = stockDataHandler.get_full_path('onehour_2018_2023_rmsprop_rolling_epoch1.h5')
model = keras.models.load_model(modelname, custom_objects={'cost_sensitive_loss': cost_sensitive_loss})

model.compile(optimizer='RMSProp', loss=cost_sensitive_loss, metrics=['accuracy'])

model.fit(x_train_resampled, y_train_encoded_resampled, batch_size=3, epochs=5)

newModelname = stockDataHandler.get_full_path('onehour_2018_2023_rmsprop_rolling_epoch3.h5')
model.save(newModelname)

joblib.dump(min_max_scalers, stockDataHandler.get_full_path('min_max_scalers.pkl'))
joblib.dump(encoder, stockDataHandler.get_full_path('encoder.pkl'))

#TODO: Første jeg skal gjøre er å splitte ut alle felles ting, slik at jeg ikke trenger å gjøre endringer i alle tre filene når jeg skal kjøre nye tester...

# Når modellen stort sett predikerer "Kjøp" i en real-time evaluering, er det et tegn på at den kanskje har blitt overjustert til opplæringsdataene, eller at det har vært et skifte i dataene siden modellen ble trent.

# Her er noen trinn du kan ta for å forbedre modellens prestasjon:

# Data Shift: Forsikre deg om at distribusjonen av de sanntidsdataene du evaluerer på er lik distribusjonen av treningsdataene. Hvis de er vesentlig forskjellige, kan det være en forklaring på hvorfor modellen ikke presterer bra.

# Oppdater Datasettet: For aksjehandel kan eldre data være mindre relevant enn nyere data. Vurder å oppdatere treningssettet ditt regelmessig med de nyeste dataene, og kanskje fjerne noen av de eldste dataene.

# Oversampling: Selv om oversampling kan bidra til å bekjempe ubalansen i treningsdataene, kan det også føre til overjustering, spesielt hvis antallet "Kjøp" -eksempler er blitt kunstig oppblåst for mye. Vurder å redusere mengden oversampling eller prøve andre teknikker som SMOTE.

# Parameterjustering: Prøv å justere modellparametrene, som antall epoker, batchstørrelse, etc. Noen ganger kan en enkel endring i disse parametrene forbedre ytelsen betydelig.

# Kompleksitet: Hvis nettverket ditt er for komplekst, kan det føre til overjustering. Vurder å redusere antall lag eller noder for å se om det forbedrer resultatene på sanntidsdataene.

# Valideringssett: I stedet for bare å splitte dataene i trenings- og testsett, vurder å bruke et valideringssett for å finjustere modellen. Dette kan hjelpe deg med å identifisere overjustering tidligere.

# Alternative Modeller: Du kan også vurdere å prøve alternative modeller, som Random Forest, Gradient Boosting eller LSTM-nettverk, som kan være bedre egnet for denne typen tidsserieprediksjon.

# Feilanalyse: Se nærmere på de eksemplene der modellen gjør feil. Er det en trend? Er feilene konsentrert rundt bestemte tidsperioder eller hendelser? En slik analyse kan gi deg innsikt i hvorfor modellen ikke presterer bra og hva som kan gjøres for å forbedre den.

# Regelmessig Retrening: Aksjemarkedsdata endres kontinuerlig basert på globale hendelser, markedssentiment og mange andre faktorer. Det er viktig å trene modellen regelmessig med nye data for å holde den aktuell.


#!/usr/bin/env python

import sys
from wsgiref.simple_server import make_server

from pyweb.core.wsgi.application import Wsgi
import os

def runserver(settings_module):
    args_length = len(sys.argv)

    if args_length <= 1:
        host, port = 'localhost', 8000
    elif args_length == 2:
        host, port = 'localhost', int(sys.argv[1])
    else:
        host, port = sys.argv[1], int(sys.argv[2])

    os.environ.setdefault("SETTINGS_MODULE", settings_module)
    application = Wsgi()

    try:
        print("Starting server ...")
        httpd = make_server(host, port, application)
        print(f"Listening to {host}:{port}")
        print("Quit server with CONTROL-C")
        httpd.serve_forever()
    except OSError:
        print("Looks like the port you provided is already in use.")
    except KeyboardInterrupt:
        print()
        print("Turning Off the server ...")
        print("Server Turned Off")


import os
import torch
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import torch.nn.functional as F
import cv2

def tensor2numpy(tensor, batch_idx=0):
    if tensor is not None and torch.is_tensor(tensor):
        if len(tensor.shape) == 4:
            tensor = tensor.permute(0, 2, 3, 1) # BxHxWxC
        tensor = tensor.clone().detach().cpu().numpy()[batch_idx, ...]
    return tensor

def restore_from_norm(img, normalize_mean = [0.485, 0.456, 0.406], normalize_std = [0.229, 0.224, 0.225]):
    img = img * normalize_std + normalize_mean
    img = np.clip(img, 0, 1)
    return img

def imshow(ax, im, title=''):
    ax.cla()
    ax.axis('off')
    if im is not None:
        ax.imshow(im)
        ax.set_title(title)

def add_rect(ax, bbox, color='r'):
    if bbox is not None:
        rect = patches.Rectangle((bbox[0], bbox[1]), bbox[2], bbox[3],
                                  linewidth=1, edgecolor=color, facecolor='none')
        ax.add_patch(rect)

def visualize_results(fig, axes, frame_id,
                      color, depth, gt_bbox, search_color, search_depth,
                      pred_mask, pred_bbox, pred_prob, pred_bbox_in_search,
                      use_norm=True):

    if fig is None and len(axes) == 0:
        fig, axes = plt.subplots(2, 4, figsize=(6, 6))

    color = tensor2numpy(color)
    depth = tensor2numpy(depth)
    gt_bbox = tensor2numpy(gt_bbox) # (4,)

    search_color = tensor2numpy(search_color)
    search_depth = tensor2numpy(search_depth)
    pred_prob = tensor2numpy(pred_prob) # HxWx1
    pred_mask = tensor2numpy(pred_mask) # HxWx1
    pred_bbox = tensor2numpy(pred_bbox) # (4,)
    pred_bbox_in_search = tensor2numpy(pred_bbox_in_search) # (4,)

    if use_norm:
        # color = restore_from_norm(color)
        # depth = restore_from_norm(depth)
        search_color = restore_from_norm(search_color)
        search_color = np.clip(search_color, 0.0, 1.0)
        search_depth = restore_from_norm(search_depth)
        search_depth = np.clip(search_depth, 0.0, 1.0)

    plt.cla()
    imshow(axes[0, 0], color, title='Frame %d, Color'%frame_id)
    imshow(axes[0, 1], depth, title='Depth')

    imshow(axes[1, 0], search_color, title='search color')
    imshow(axes[1, 1], search_depth, title='search depth')

    imshow(axes[2, 0], pred_mask, title='pred mask')
    imshow(axes[2, 1], pred_prob, title='pred prob : %f'%np.max(pred_prob))

    add_rect(axes[0, 0], gt_bbox, color='g')
    add_rect(axes[0, 0], pred_bbox, color='r')
    add_rect(axes[1, 0], pred_bbox_in_search, color='r')

    plt.pause(0.0001)
    plt.show(block=False)

def save_debug(temp_path, epoch, batch,
               train_images, train_depths, train_masks, train_boxes,
               test_images, test_depths, test_masks, test_boxes, test_gauss,
               prediction_mask, scores):

    train_rgb = tensor2numpy(train_images)
    train_rgb = restore_from_norm(train_rgb)
    train_d = tensor2numpy(train_depths)
    train_d = restore_from_norm(train_d)

    train_m = tensor2numpy(train_masks)
    train_b = tensor2numpy(train_boxes)

    test_rgb = tensor2numpy(test_images)
    test_rgb = restore_from_norm(test_rgb)

    test_d = tensor2numpy(test_depths)
    test_d = restore_from_norm(test_d)

    test_m = tensor2numpy(test_masks)
    test_b = tensor2numpy(test_boxes)
    test_g = tensor2numpy(test_gauss) # Bx7x7

    scores = tensor2numpy(scores) # Bx7x7

    prediction_mask = tensor2numpy(F.softmax(prediction_mask, dim=1))
    pred_fg = prediction_mask[:, :, 0]
    # pred_bg = prediction_mask[:, :, 1]

    fig, axes = plt.subplots(3, 3, figsize=(8, 8))

    imshow(axes[0, 0], train_rgb, title='train rgb')
    add_rect(axes[0, 0], train_b, color='r')
    imshow(axes[0, 1], train_d, title='depth')
    imshow(axes[0, 2], train_m, title='mask')

    imshow(axes[1, 0], test_rgb, title='test rgb')
    add_rect(axes[1, 0], test_b, color='r')
    imshow(axes[1, 1], test_d, title='depth')
    imshow(axes[1, 2], test_m, title='mask')

    imshow(axes[2, 0], test_g, title='test score')
    imshow(axes[2, 1], scores, title='pred score : %f'%np.max(scores))
    imshow(axes[2, 2], pred_fg, title='pred mask')

    plt.savefig(os.path.join(temp_path,'debug-%d-%d.png'%(epoch, batch)))
    plt.close(fig)


import os
from builtins import bool
os.environ["CUDA_VISIBLE_DEVICES"]="6"

import torch
from torch import multiprocessing, cuda
from torch.utils.data import DataLoader
import torch.nn.functional as F
from torch.backends import cudnn
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import importlib

import imageio
import argparse
from data import data_voc, data_coco
from tool import torchutils, pyutils

cudnn.enabled = True

def overlap(img, seed_map):
    seed_map = seed_map.squeeze()
    seed_map = seed_map.astype(int)

    color = np.array([[0, 0, 0], [255, 0, 0]])
    seed_map = color[seed_map] * 2

    if seed_map.shape == np.array(img).astype(np.float).shape:
        out = (seed_map + np.array(img).astype(np.float)) / 3
        out = (out / np.max(out) * 255).astype(np.uint8)
    else:
        print(seed_map.shape)
        print(np.array(img).shape)
    return out

def draw_seedmap(seed_map, gt_label, orig_img, save_path, img_name):

    seed_map = F.interpolate(seed_map, orig_img.shape[:-1], mode='bilinear', align_corners=False)
    seed_map = seed_map.squeeze()
    seed_map = seed_map.numpy()

    gt_cat = np.where(gt_label==1)[0]

    for _, gt in enumerate(gt_cat):
        heatmap = overlap(orig_img, seed_map[gt])
        cam_viz_path = os.path.join(save_path, img_name + '_{}.png'.format(gt))
        imageio.imsave(cam_viz_path, heatmap)

def denormalization(image) :
    mean=(0.485, 0.456, 0.406)
    std=(0.229, 0.224, 0.225)

    if image.dim() == 3:
        assert image.dim() == 3, "Expected image [CxHxW]"
        assert image.size(0) == 3, "Expected RGB image [3xHxW]"

        for t, m, s in zip(image, mean, std):
            t.mul_(s).add_(m)
    elif image.dim() == 4:
        # batch mode
        assert image.size(1) == 3, "Expected RGB image [3xHxW]"

        for t, m, s in zip((0,1,2), mean, std):
            image[:, t, :, :].mul_(s).add_(m)

    return image

def _work(process_id, model, dataset, args):
    databin = dataset[process_id]
    n_gpus = torch.cuda.device_count()
    data_loader = DataLoader(databin, shuffle=False, num_workers=args.num_workers // n_gpus, pin_memory=False)
    os.makedirs(os.path.join(args.session_name, "visual_per_size"), exist_ok=True)

    with torch.no_grad(), cuda.device(process_id):

        model.cuda()
        model.training = False

        for iter, pack in enumerate(data_loader):
            img_name = pack['name'][0]
            label = pack['label'][0]
            size = pack['size']
            label = F.pad(label, (1, 0), 'constant', 1.0)

            # original
            #outputs = [model(img[0].cuda(non_blocking=True), label.cuda(non_blocking=True).unsqueeze(-1).unsqueeze(-1)) for img in pack['img']]

            # print(pack['img'].shape) # torch.Size([1, 2, 3, 281, 500])

            # with PAMR
            label_cuda = label.cuda(non_blocking=True).unsqueeze(-1).unsqueeze(-1)
            img = pack['img'][0]
            outputs = model(img.cuda(non_blocking=True), label_cuda, denormalization(img).cuda(non_blocking=True))

            # multi-scale fusion
            seeds_x1 = outputs[0].cpu()
            seeds_x2 = outputs[1].cpu()
            seeds_x3 = outputs[2].cpu()
            seeds_x4 = outputs[3].cpu()
            seeds_hie = outputs[4].cpu()

            # visualize seed map
            if args.visualize:
                orig_img = np.array(Image.open(pack['img_path'][0]).convert('RGB'))
                draw_seedmap(seeds_x1, label, orig_img, os.path.join(args.session_name, 'visual'), f"{img_name}_x1")
                draw_seedmap(seeds_x2, label, orig_img, os.path.join(args.session_name, 'visual'), f"{img_name}_x2")
                draw_seedmap(seeds_x3, label, orig_img, os.path.join(args.session_name, 'visual'), f"{img_name}_x3")
                draw_seedmap(seeds_x4, label, orig_img, os.path.join(args.session_name, 'visual'), f"{img_name}_x4")
                draw_seedmap(seeds_hie, label, orig_img, os.path.join(args.session_name, 'visual'), f"{img_name}_hie")

            if process_id == n_gpus - 1 and iter % (len(databin) // 100) == 0:
                print("%d " % ((5*iter+1)//(len(databin) // 100)), end='')

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument("--network", default="network.resnet50_AE_SIPE", type=str)
    # parser.add_argument("--num_workers", default=os.cpu_count()//2, type=int)
    parser.add_argument("--num_workers", default=1, type=int)
    parser.add_argument("--session_name", default="exp", type=str)
    parser.add_argument("--ckpt", default="final.pth", type=str)
    parser.add_argument("--visualize", default=True, type=bool)
    parser.add_argument("--dataset", default="voc", type=str)
    parser.add_argument("--make_dataset", default='train', type=str) # trainaug

    args = parser.parse_args()

    os.makedirs(os.path.join(args.session_name, 'npy'), exist_ok=True)
    os.makedirs(os.path.join(args.session_name, 'visual'), exist_ok=True)
    pyutils.Logger(os.path.join(args.session_name, 'infer.log'))
    print(vars(args))

    assert args.dataset in ['voc', 'coco'], 'Dataset must be voc or coco in this project.'

    if args.dataset == 'voc':
        dataset_root = '../PascalVOC2012/VOCdevkit/VOC2012'
        model = getattr(importlib.import_module(args.network), 'CAM')(num_cls=21)
        # dataset = data_voc.VOC12ClsDatasetMSF(f'data/{args.make_dataset}_' + args.dataset + '.txt', voc12_root=dataset_root, scales=(1.0, 0.5, 1.5, 2.0))
        dataset = data_voc.VOC12ClsDatasetMSF(f'data/{args.make_dataset}_' + args.dataset + '.txt', voc12_root=dataset_root, scales=(1.0, ))

    elif args.dataset == 'coco':
        dataset_root = "../ms_coco_14&15/images"
        model = getattr(importlib.import_module(args.network), 'CAM')(num_cls=81)
        dataset = data_coco.COCOClsDatasetMSF('data/train_' + args.dataset + '.txt', coco_root=dataset_root, scales=(1.0, 0.5, 1.5, 2.0))

    checkpoint = torch.load(args.session_name + '/ckpt/' + args.ckpt)
    model.load_state_dict(checkpoint['net'], strict=True)
    model.eval()

    n_gpus = torch.cuda.device_count()

    dataset = torchutils.split_dataset(dataset, n_gpus)

    print('[ ', end='')
    multiprocessing.spawn(_work, nprocs=n_gpus, args=(model, dataset, args), join=True)
    print(']')

    torch.cuda.empty_cache()


import time
from pymem import *
from pymem.process import *
from pymem.ptypes import RemotePointer
import dearpygui.dearpygui as dpg
import threading
import ctypes
import sys

try:
    pm = pymem.Pymem("echovr.exe")
except Exception:
    ctypes.windll.user32.MessageBoxW(0, "Game Not Found, make sure it's running!", "Error!", 1)
    sys.exit(1)

gameModule = module_from_name(pm.process_handle, "echovr.exe").lpBaseOfDll
matchmakingModule = module_from_name(pm.process_handle, "pnsradmatchmaking.dll").lpBaseOfDll
pnsovr = module_from_name(pm.process_handle, "pnsovr.DLL").lpBaseOfDll

def GetPtrAddr(base, offsets):
    remote_pointer = RemotePointer(pm.process_handle, base)
    for offset in offsets:
        if offset != offsets[-1]:
            remote_pointer = RemotePointer(pm.process_handle, remote_pointer.value + offset)
        else:
            return remote_pointer.value + offset

# Addresses
BaseCoords = GetPtrAddr(gameModule + 0x020A3138,[0x60, 0x2A0, 0xF8, 0xEA0, 0xD8, 0x134, 0x118])
BasePlayerList = GetPtrAddr(matchmakingModule + 0x009C49D8,[0x88, 0x0, 0x440, 0x28, 0x40, 0x378, 0x3C])
BaseView = GetPtrAddr(gameModule + 0x020A3138,[0x60, 0x2A0, 0xF8, 0xEA0, 0xD8, 0x134, 0x118]) - 196

def update_value():
    while True:
      dpg.set_value(text_label, "("+str(round(pm.read_float(BaseCoords),2))+" ,"+str(round(pm.read_float(BaseCoords+4),2))+" ,"+str(round(pm.read_float(BaseCoords+8),2))+")")
      time.sleep(0.1)

def update_playerlistvalues():
    while True:
        for i in range(10):
              thehex = "0xD8"
              result = int(thehex, 16) * i
              if pm.read_string(BasePlayerList+result) == "":
                  dpg.set_value(globals()['playerslot' + str(i)], "Player #"+str(i)+": Player Not Detected")
              else:
                dpg.set_value(globals()['playerslot' + str(i)], "Player #"+str(i)+": "+pm.read_string(BasePlayerList+result))
        time.sleep(0.4)

def update_speedvalue():
    while True:
      dpg.set_value(speed_label, "Speed: "+ str(round(pm.read_float(BaseCoords-28),2))+ " M/s")
      time.sleep(0.1)

def update_ViewX():
    while True:
        dpg.set_value(ViewX_label, "ViewX: "+ str(round(pm.read_float(BaseView),2)))
        time.sleep(0.4)
def update_ViewY():
    while True:
        dpg.set_value(ViewY_label, "ViewY: "+ str(round(pm.read_float(BaseView+4),2)))
        time.sleep(0.4)

dpg.create_context()
dpg.create_viewport(title='Echo Overlay', width=200, height=515)
dpg.setup_dearpygui()

with dpg.window(label="Echo Overlay, Welcome"):
    dpg.set_viewport_always_top(True)
    dpg.add_text("---------- Account Info ---------")
    dpg.add_text("Username: "+  pm.read_string(pnsovr + 0xA01B80))
    dpg.add_text("Scoped ID: "+  pm.read_string(pnsovr + 0xA01BF0))
    dpg.add_text("---------------------------------")
    text_label = dpg.add_text("XYZ")
    speed_label = dpg.add_text("Speed: Null M/s")
    ViewX_label = dpg.add_text("ViewX")
    ViewY_label = dpg.add_text("ViewY")
    dpg.add_text("---------- Player List ----------")
    playerslot0 = dpg.add_text("Player #"+":")
    playerslot1 = dpg.add_text("Player #"+":")
    playerslot2 = dpg.add_text("Player #"+":")
    playerslot3 = dpg.add_text("Player #"+":")
    playerslot4 = dpg.add_text("Player #"+":")
    playerslot5 = dpg.add_text("Player #"+":")
    playerslot6 = dpg.add_text("Player #"+":")
    playerslot7 = dpg.add_text("Player #"+":")
    playerslot8 = dpg.add_text("Player #"+":")
    playerslot9 = dpg.add_text("Player #"+":")
    playerlistupdate = threading.Thread(target=update_playerlistvalues)
    speedupdate = threading.Thread(target=update_speedvalue)
    viewXUpdate = threading.Thread(target=update_ViewX)
    viewYUpdate =  threading.Thread(target=update_ViewY)
    thread = threading.Thread(target=update_value)
    viewXUpdate.start()
    viewYUpdate.start()
    thread.start()
    speedupdate.start()
    playerlistupdate.start()

dpg.show_viewport()
dpg.start_dearpygui()

dpg.destroy_context()


import requests
import pytest
import allure

url_list = [
    {'url': "https://www.baidu.com", "method": "get", "status": 200, "title": "百度"},
    {'url': "https://www.cnblogs.com/Neeo/articles/11832655.html", "method": "get", "status": 200, "title":"cnblogs"},
    {'url': "http://www.neeo.cc:6001/post", "method": "post", "status": 200, "title":"post接口"},
    {'url': "http://www.neeo.cc:6001/put", "method": "put", "status": 200, "title":"put接口"},
]

@pytest.mark.parametrize('item', url_list)
def test_case(item):

    allure.dynamic.title(item['title'])
    response = requests.request(method=item['method'], url=item['url'])
    # print(response.status_code,  item['status'])
    assert response.status_code == item['status']

# phone = [10086, 10010, 110]
# code = ['10086', '10010', '110']
#
#
# @pytest.mark.parametrize('item,code', zip(phone, code))
# def test_case(item, code):
#     print(111, item, code)
#     assert 1

# phone = [10086, 10010, 110]
# code = ['10086', '10010', '110']
#
#
# @pytest.mark.parametrize('item', phone)
# @pytest.mark.parametrize('code', code)
# def test_case(item, code):
#     print(111, item, code)
#     assert 1

# def test_case_01():
#     print(phone[0])
#     assert phone[0] == 10086

# def test_case_02():
#     print(phone[1])
#     assert phone[1] == 10010
#
# def test_case_03():
#     print(phone[2])
#     assert phone[2] == 110


from django.shortcuts import render,HttpResponse
#from assents import core,models, asset_handle, utils, admin
from asset import core,utils
from repository import models
from django.shortcuts import render

from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from repository import models as cmdb_models

import json

@csrf_exempt
# @utils.token_required

def asset_report(request):       #1. 这个函数处理的是-有 "资产ID"的情况。
    print(request.GET)
    if request.method == 'POST':
        asset_handle = core.Asset(request)
        if asset_handle.data_is_valid():     #数据合法才会被 注册。
            print("------asset data valid:--------")
            asset_handle.data_inject()  # 注射数据到数据库

        return HttpResponse(json.dumps(asset_handle.response))

    return HttpResponse('----test OK ------')

@csrf_exempt
def asset_with_no_asset_id(request): # 2.1、此函数处理没有 "资产ID" 的情况。
    if request.method == 'POST':
        del_handler = core.Asset(request)
        res = del_handler.get_asset_id_by_sn() #2.2、此函数通过 sn 获取 "资产ID"。

        # return render(request,'assets/acquire_asset_id_test.html',{'response':res})
        return HttpResponse(json.dumps(res))

@csrf_exempt
def new_assets_approval(request):

    if request.method == 'POST':
        request.POST = request.POST.copy()  # request.POST 是不能修改的,所以要拷贝一份。
        approved_asset_list = request.POST.getlist('approved_asset_list')
        approved_asset_list = models.NewAssetApprovalZone.objects.filter(id__in=approved_asset_list)

        response_dic = {}
        for obj in approved_asset_list:
            request.POST['asset_data'] = obj.data
            ass_handler = core.Asset(request)

            if ass_handler.data_is_valid_without_id():

                ass_handler.data_inject()
                obj.approved = True
                obj.save()

            response_dic[obj.id] = ass_handler.response

        return render(request, 'new_assets_approval.html',
                      {'new_assets': approved_asset_list, 'response_dic': response_dic})
    else:
        ids = request.GET.get('ids')
        id_list = ids.split(',')
        new_assets = models.NewAssetApprovalZone.objects.filter(id__in=id_list)

        return render(request, 'new_assets_approval.html', {'new_assets': new_assets})

@login_required
def new_asset_display(request):
    if request.method == "GET":

        new_assets = models.NewAssetApprovalZone.objects.all()
        return render(request, 'asset_display_approval.html', {'new_assets': new_assets})

    if request.method == 'POST':
        ids = json.loads(request.POST.get('selected_ids'))
        # ====== selected_ids ==== ['1', '3']

        selected_ids = ','.join(ids)
        print("==== selected_ids ===",selected_ids)
        selected_objs = cmdb_models.NewAssetApprovalZone.objects.filter(id__in=ids)

        if selected_objs:
              print('=== id IN (+ selected_ids +)===','id IN ('+ selected_ids +')')
              # === id IN (+ selected_ids +)=== id IN (1,3)
              #cmdb_models.NewAssetApprovalZone.objects.extra(where=['id IN (' + selected_ids + ')']).delete()

        return render(request, "asset_display_approval.html", locals())

@login_required
def user(request):

    return render(request,'user.html')

# def test(request):
#     if request.method == "GET":
#         new_assets = models.NewAssetApprovalZone.objects.all()
#         return render(request, 'index1.html',{'new_assets': new_assets})


from django.views.generic.base import TemplateView
from web_admin import api_settings, setup_logger
from authentications.utils import get_correlation_id_from_username, check_permissions_by_user
from braces.views import GroupRequiredMixin
from web_admin.restful_client import RestFulClient
from web_admin.get_header_mixins import GetHeaderMixin
from django.contrib import messages
from web_admin.api_logger import API_Logger
import logging

logger = logging.getLogger(__name__)

class DetailView(GroupRequiredMixin, TemplateView, GetHeaderMixin):
    template_name = "card_design/detail.html"
    logger=logger

    group_required = "SYS_VIEW_DETAIL_CARD_DESIGN"
    login_url = 'web:permission_denied'
    raise_exception = False

    def check_membership(self, permission):
        self.logger.info(
            "Checking permission for [{}] username with [{}] permission".format(self.request.user, permission))

        return check_permissions_by_user(self.request.user, permission[0])

    def dispatch(self, request, *args, **kwargs):
        correlation_id = get_correlation_id_from_username(self.request.user)
        self.logger = setup_logger(self.request, logger, correlation_id)
        return super(DetailView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(DetailView, self).get_context_data(**kwargs)
        card_id = context['card_id']
        provider_id = context['provider_id']
        return self._get_card_design_detail(provider_id, card_id)

    def _get_card_design_detail(self, provider_id, card_id):
        self.logger.info('========== Start getting card design detail ==========')

        is_permission_edit = check_permissions_by_user(self.request.user, 'SYS_EDIT_CARD_DESIGN')
        url = api_settings.CARD_DESIGN_DETAIL.format(provider_id=provider_id, card_id=card_id)
        is_success, status_code, data = RestFulClient.get(url=url, headers=self._get_headers(), loggers=self.logger)

        API_Logger.get_logging(loggers=self.logger, params={}, response=data,
                               status_code=status_code)
        if is_success:
            if data is None or data == "":
                data = {}
        else:
            messages.add_message(
                self.request,
                messages.ERROR,
                "Something went wrong"
            )
            data = {}

        self.logger.info('========== Finish getting card design detail ==========')
        return {"body": data,
                "is_permission_edit": is_permission_edit}


from typing import Iterable, TypeVar, Union

ItemType = TypeVar('ItemType')

class Sentinel:
    """Sentinel object."""

def sequentially_deduplicate(
    iterable: Iterable[ItemType]
) -> Iterable[ItemType]:
    """
    Remove sequential duplicates.

        ..pycon
        >>> list(sequentially_deduplicate([1, 3, 1, 1, 8, 1]))
        [1, 3, 8, 1]
    """
    sentinel = Sentinel()
    previous_item: Union[Sentinel, ItemType] = sentinel

    for item in iterable:   # noqa: WPS110 - this is an item of an iterable
        if item not in {previous_item, sentinel}:
            yield item

        previous_item = item


import json
import sys
import matplotlib.pyplot as plt
import numpy as np
import math
import copy

class WorldModel:
    def __init__(self, _setup_file):
        self.setup = _setup_file
        self.action_index = 0

    def calculate_discontentment(self):
        discontentment = 0.0
        for goal_name, goal_value in self.setup["goals"].items():
            discontentment += pow(goal_value, 2)
        return discontentment

    def next_action(self):
        if self.action_index < len(self.setup["actions"]):
            action = self.setup["actions"][self.action_index]
            self.action_index += 1
            return action
        else:
            return None

    def apply_action(self, action, action_discontentment=None):
        for goal_change in action["goalsChange"]:
            goal_name = goal_change["name"]
            if goal_name in self.setup["goals"]:
                if isinstance(goal_change["value"], str) and '%' in goal_change["value"]:
                    percentage_value = float(goal_change["value"].strip('%')) / 100
                    self.setup["goals"][goal_name] -= math.ceil(self.setup["goals"][goal_name] * percentage_value)
                else:
                    self.setup["goals"][goal_name] -= goal_change["value"]
                if self.setup["goals"][goal_name] > 100:
                    self.setup["goals"][goal_name] = 100
                elif self.setup["goals"][goal_name] < 0:
                    self.setup["goals"][goal_name] = 0

        if "statsChange" in action:
            for stat_change in action["statsChange"]:
                stat_name = stat_change["name"]
                if stat_name in self.setup["stats"]:
                    self.setup["stats"][stat_name] += stat_change["value"]

        if action_discontentment:
            self.setup["stats"]["discontentment"] = action_discontentment

def plan_action(world_model, max_depth):
    models = [None] * (max_depth + 1)
    actions = [None] * max_depth

    models[0] = world_model
    current_depth = 0

    best_action = None
    best_value = float('inf')

    while current_depth >= 0:
        current_value = models[current_depth].calculate_discontentment()

        if current_depth >= max_depth:
            if current_value < best_value:
                best_value = current_value
                best_action = actions[0]

            current_depth -= 1
            continue

        next_action = models[current_depth].next_action()
        if next_action:
            models[current_depth + 1] = copy.deepcopy(models[current_depth])
            actions[current_depth] = next_action
            models[current_depth + 1].apply_action(next_action)
            current_depth += 1
        else:
            current_depth -= 1

    return best_action, best_value

def plot_goals(goals_list):
    plt.figure()
    goal_keys = list(goals_list[0].keys())
    for key in goal_keys:
        goal_values = [d[key] for d in goals_list]
        plt.plot(goal_values, label=key)

    plt.title('Goals over time')
    plt.xlabel('Iteration')
    plt.ylabel('Value')
    plt.legend()
    plt.savefig('GOAP-goals_changes.jpg')

def plot_stats(stats_list):
    plt.figure()
    stat_keys = list(stats_list[0].keys())
    for key in stat_keys:
        stat_values = [d[key] for d in stats_list]
        plt.plot(stat_values, label=key)

    plt.title('Stats over time')
    plt.xlabel('Iteration')
    plt.ylabel('Value')
    plt.legend()
    plt.savefig('GOAP-stats_changes.jpg')

def main(iterations):
    with open("setup_with_percentages.json", "r") as file:
        goals_and_actions_json = json.load(file)

    print("Starting goals are", goals_and_actions_json["goals"])

    all_chosen_actions = []
    stats_list = []
    goals_list = []
    goal_values = []

    for i in range(iterations):
        print("\nRound", i)
        print("Goals:", goals_and_actions_json["goals"])
        goals_list.append(goals_and_actions_json["goals"].copy())
        stats_list.append(goals_and_actions_json["stats"].copy())
        world_model = WorldModel(goals_and_actions_json)
        chosen_action, chosen_action_discontentment = plan_action(world_model, 1)
        if chosen_action:
            print("Chosen action:\t", chosen_action)
            all_chosen_actions.append(chosen_action["name"])
            world_model.apply_action(chosen_action, chosen_action_discontentment)
            goal_values.append(list(goals_and_actions_json["goals"].values()))
            goals_and_actions_json["goals"] = world_model.setup["goals"]
            goals_and_actions_json["stats"] = world_model.setup["stats"]
            print("Goals are now:\t", goals_and_actions_json["goals"])
        else:
            print("No action can be chosen. Closing the game.")
            sys.exit()

    plot_goals(goals_list)
    plot_stats(stats_list)


from __future__ import division

from gi.repository import Gio, GObject, GdkPixbuf
from pyexiv2 import ImageMetadata
from time import mktime
from os import stat

from camera import Camera
from gpsmath import Coordinates, format_list
from gpsmath import dms_to_decimal, decimal_to_dms, float_to_rational
from territories import get_state, get_country

# Prefixes for common EXIF keys.
GPS  = 'Exif.GPSInfo.GPS'
IPTC = 'Iptc.Application2.'

class Photograph(Coordinates):
    """Represents a single photograph and it's location in space and time."""

    def __init__(self, filename, callback, thumb_size=200):
        """Initialize new Photograph object's attributes with default values."""
        self.filename = filename
        self.callback = callback
        self.thm_size = thumb_size
        self.label    = None
        self.iter     = None
        self.exif     = None
        self.thumb    = None
        self.manual   = None

    def read(self):
        """Load exif data from disk."""
        self.exif      = ImageMetadata(self.filename)
        self.timestamp = None
        self.altitude  = None
        self.latitude  = None
        self.longitude = None
        self.timezone  = None
        self.manual    = False
        try:
            self.exif.read()
        except TypeError:
            raise IOError

        Camera(self.exif)

        # Try to get a thumbnail.
        try:
            self.thumb = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    self.filename, self.thm_size, self.thm_size)
        except GObject.GError:
            if len(self.exif.previews) > 0:
                data = self.exif.previews[-1].data
            elif len(self.exif.exif_thumbnail.data) > 0:
                data = self.exif.exif_thumbnail.data
            else:
                raise IOError

            self.thumb = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                Gio.MemoryInputStream.new_from_data(data, None),
                self.thm_size, self.thm_size, True, None)

        self.calculate_timestamp()
        try:
            self.latitude = dms_to_decimal(
                *self.exif[GPS + 'Latitude'].value +
                [self.exif[GPS + 'LatitudeRef'].value]
            )
            self.longitude = dms_to_decimal(
                *self.exif[GPS + 'Longitude'].value +
                [self.exif[GPS + 'LongitudeRef'].value]
            )
        except KeyError:
            pass
        try:
            self.altitude = float(self.exif[GPS + 'Altitude'].value)
            if int(self.exif[GPS + 'AltitudeRef'].value) > 0:
                self.altitude *= -1
        except KeyError:
            pass

    def calculate_timestamp(self):
        """Determine the timestamp based on the currently selected timezone.

        This method relies on the TZ environment variable to be set before
        it is called. If you don't set TZ before calling this method, then it
        implicitely assumes that the camera and the computer are set to the
        same timezone.
        """
        try:
            self.timestamp = int(mktime(
                self.exif['Exif.Photo.DateTimeOriginal'].value.timetuple()))
        except KeyError:
            self.timestamp = int(stat(self.filename).st_mtime)

    def write(self):
        """Save exif data to photo file on disk."""
        if self.altitude is not None:
            self.exif[GPS + 'Altitude']    = float_to_rational(self.altitude)
            self.exif[GPS + 'AltitudeRef'] = '0' if self.altitude >= 0 else '1'
        self.exif[GPS + 'Latitude']     = decimal_to_dms(self.latitude)
        self.exif[GPS + 'LatitudeRef']  = 'N' if self.latitude >= 0 else 'S'
        self.exif[GPS + 'Longitude']    = decimal_to_dms(self.longitude)
        self.exif[GPS + 'LongitudeRef'] = 'E' if self.longitude >= 0 else 'W'
        self.exif[GPS + 'MapDatum']     = 'WGS-84'
        self.exif.write()

    def set_location(self, lat, lon, ele=None):
        """Alter the coordinates of this photo."""
        if ele is not None:
            self.altitude = ele
        self.latitude  = lat
        self.longitude = lon
        self.position_label()
        self.lookup_geoname()
        self.callback(self)

    def position_label(self):
        """Maintain correct position and visibility of ChamplainLabel."""
        if self.valid_coords():
            self.label.set_location(self.latitude, self.longitude)
            self.label.show()
            if self.label.get_selected():
                self.label.raise_top()
        else:
            self.label.hide()

    def set_label_highlight(self, highlight, transparent):
        """Set the highlightedness of the given photo's ChamplainLabel."""
        if self.label.get_property('visible'):
            self.label.set_scale(*[1.1 if highlight else 1] * 2)
            self.label.set_selected(highlight)
            self.label.set_opacity(64 if transparent and not highlight else 255)
            if highlight:
                self.label.raise_top()

    def set_geodata(self, data):
        """Override Coordinates.set_geodata to apply directly into IPTC."""
        city, state, country, tz          = data
        self.exif[IPTC + 'City']          = [city or '']
        self.exif[IPTC + 'ProvinceState'] = [get_state(country, state) or '']
        self.exif[IPTC + 'CountryName']   = [get_country(country) or '']
        self.exif[IPTC + 'CountryCode']   = [country or '']
        self.timezone                     = tz.strip()

    def pretty_geoname(self):
        """Override Coordinates.pretty_geoname to read from IPTC."""
        names = []
        for key in [ 'City', 'ProvinceState', 'CountryName' ]:
            try: names.extend(self.exif[IPTC + key].values)
            except KeyError: pass
        length = sum(map(len, names))
        return format_list(names, ',\n' if length > 35 else ', ')


import torch
from torch import nn
from torch.utils.data import DataLoader
import torchvision
from torchvision import transforms
from torchvision.datasets import CIFAR10
import numpy as np
import matplotlib.pyplot as plt

def imshow(img):
    img = torchvision.utils.make_grid(img)
    img = img / 2 + 0.5
    npimg = img.detach().numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

def train(net, criterion, optimizer, epochs, trainloader):
    losses = []
    output_and_label = []

    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    print('using device:', device)

    net = net.to(device)

    for epoch in range(1, epochs+1):
        print(f'epoch: {epoch}, ', end='')
        running_loss = 0.0
        for counter, (img, _) in enumerate(trainloader, 1):
            img = img.to(device)
            optimizer.zero_grad()
            output = net(img)
            loss = criterion(output, img)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
        avg_loss = running_loss / counter
        losses.append(avg_loss)
        print('loss:', avg_loss)
        output_and_label.append((output, img))
    print('finished')
    return output_and_label, losses

transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = CIFAR10('./data', train=True, transform=transform, download=True)
testset = CIFAR10('./data', train=False, transform=transform, download=True)

batch_size = 50
trainloader = DataLoader(trainset, batch_size=batch_size, shuffle=True)
testloader = DataLoader(testset, batch_size=batch_size // 10, shuffle=False)

class AutoEncoder(torch.nn.Module):
    def __init__(self, enc, dec):
        super().__init__()
        self.enc = enc
        self.dec = dec
    def forward(self, x):
        x = self.enc(x)
        x = self.dec(x)
        return x

enc = torch.nn.Sequential(
    torch.nn.Conv2d(3, 16, kernel_size=4, padding=1, stride=2),
    torch.nn.ReLU(),
    torch.nn.Conv2d(16, 32, kernel_size=4, padding=1, stride=2),
    torch.nn.ReLU()
)

#For ConvTransposed http://makeyourownneuralnetwork.blogspot.com/2020/02/calculating-output-size-of-convolutions.html
dec = torch.nn.Sequential(
    torch.nn.ConvTranspose2d(32, 16, kernel_size=4, stride=2, padding=1),
    torch.nn.ReLU(),
    torch.nn.ConvTranspose2d(16, 3, kernel_size=4, stride=2, padding=1),
    torch.nn.Tanh()
)

net = AutoEncoder(enc, dec)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
EPOCHS = 100

output_and_label, losses = train(net, criterion, optimizer, EPOCHS, trainloader)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.utils.timezone import utc
import datetime

class Migration(migrations.Migration):

    dependencies = [
        ('students', '0002_auto_20150808_2306'),
    ]

    operations = [
        migrations.AddField(
            model_name='mark',
            name='updated_at',
            field=models.DateTimeField(auto_now=True, default=datetime.datetime(2015, 8, 8, 21, 28, 28, 373743, tzinfo=utc)),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='student',
            name='updated_at',
            field=models.DateTimeField(auto_now=True, default=datetime.datetime(2015, 8, 8, 21, 28, 38, 270233, tzinfo=utc)),
            preserve_default=False,
        ),
        migrations.AlterField(
            model_name='mark',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True),
        ),
        migrations.AlterField(
            model_name='student',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True),
        ),
    ]


'--------Author Arun------------'
'-------Created 03.04.2018-----'
from PyPDF2 import PdfFileReader, PdfFileWriter
import re

def pdf_splitter(wordpattern):
    pdfFileObj = PdfFileReader(open('filename.pdf', "rb")) # file path.
    pdf_writer = PdfFileWriter()
    pagenumber = pdfFileObj.getNumPages()
    startpage = [] # number of start pages for the subfile or newfile which is created by splitting the pdf base on some pattern/text/content.
    naming = []

    for i in range(1, pagenumber):
        page = pdfFileObj.getPage(i)
        content = (page.extractText())
        if (re.search((wordpattern), content)):
            startpage.append(i)
            name = re.search(wordpattern, content)
            naming.append(name.group())
    print(startpage)

    for k in range(0, (len(startpage))):
            try:
                x, y = startpage[k], startpage[k + 1]

                for m in range(x, y):
                    page = pdfFileObj.getPage(m)
                    pdf_writer.addPage(page)
            except:
                print("Reached Last page")
                for m in range(y, pagenumber):
                    page = pdfFileObj.getPage(m)
                    pdf_writer.addPage(page)
            newpdf = (open('newfilenames%s.pdf' % naming[k], "wb"))# The nefiles/subfiles are created here.
            pdf_writer.write(newpdf)
            newpdf.close
            pdf_writer = PdfFileWriter()

if __name__ == "__main__":
    pdf_splitter('/d{4}') #give some word pattern or word with which you want to split the file.
                          #--For example I have give /d{4},which means pdf file will split into new files  at places where 4 digit numbers are there.


import math
from typing import List, Union, Dict
import cv2
import numpy as np
from PyQt5 import QtGui
from PyQt5.QtCore import Qt, QRect, QPoint, QPointF
from PyQt5.QtGui import QPixmap, QImage, QCursor
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QWidget
from catboost import CatBoostClassifier
import pickle
from constants import MAX_PIXMAP_SIDE
from ui.qtdesigner import Ui_MaskMenu
from enum import Enum
import pandas as pd
import tensorflow as tf
import os
import json
from tensorflow import keras
from tensorflow.keras import datasets, layers, models
from tensorflow.keras.preprocessing.image import ImageDataGenerator

js = json.load(open('settings.json'))
proba_thresh = js['proba_thresh']
step = js['step']

size = 576
model = tf.keras.applications.resnet50.ResNet50(include_top=True,
                                              input_shape=(size, size, 3),
                                              pooling=None,
                                              weights=None,
                                              classes=102)
model = tf.keras.models.load_model('cnn93.hdf5')
model_ex = keras.Model(inputs=model.inputs, outputs=model.get_layer(name="avg_pool").output)

#cb_model = CatBoostClassifier()
#cb_model.load_model('cb.pkl')
cb_model = pickle.load(open('cb.pkl', 'rb'))

class ImageView(Enum):
    ORIGINAL_IMAGE = 0
    INVERTED_MASKED_IMAGE = 1
    MASKED_IMAGE = 2
    ONLY_MASK = 3

def dist(p1, p2):
    return ((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) ** 0.5

def get_angle(p1, p2, p3):
    """p2 = center"""
    d1 = dist(p1, p2)
    d2 = dist(p2, p3)
    angle = math.acos(min(d1, d2) / max(d1, d2))
    return math.degrees(angle)

class MaskMenuWidget(QWidget, Ui_MaskMenu):
    def get_warp_data(self, group, subgroup):
        img_data = self.data[group]['img_data'][subgroup]
        warp_data = {}
        is_180_rot_global = False
        all_180 = []
        for img_name, mask in img_data.items():
            image_path = os.path.join(group, subgroup, img_name)
            img = cv2.imread(image_path)
            mask = mask.copy()

            h, w = mask.shape
            if h > w:
                img = np.rot90(img)
                mask = np.rot90(mask)

            ret, thresh = cv2.threshold(mask, 127, 255, 0)
            contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

            cnt = contours[0]
            epsilon = 0.001 * cv2.arcLength(cnt, True)
            while True:
                epsilon += epsilon
                approx = cv2.approxPolyDP(cnt, epsilon, True)
                if len(approx) <= 4:
                    break

            left = list(approx[approx[:, :, 0].argmin()][0])
            right = list(approx[approx[:, :, 0].argmax()][0])
            other = np.array([elem[0] for elem in approx.tolist() if elem[0] not in [left, right]]).astype(int)
            if len(approx) == 3:
                if dist(left, other[0]) >= dist(right, other[0]):
                    start = left
                    end = right
                else:
                    start = right
                    end = left
            elif len(approx) == 4:
                subsequence = [(tuple(elem[0], )) for elem in approx.tolist()]
                if abs(subsequence.index(tuple(other[0])) - subsequence.index(tuple(other[1]))) != 1:
                    # если две точки не соединены между собой, то там четырехугольник, то есть только тело
                    if get_angle(other[0], left, other[1]) >= get_angle(other[0], right, other[1]):
                        start = left
                        end = right
                    else:
                        start = right
                        end = left
                else:
                    # если две точки соединены между собой, то там треугольник, то есть хвост
                    if dist(left, other[0]) + dist(left, other[1]) >= dist(right, other[0]) + dist(right, other[1]):
                        start = left
                        end = right
                    else:
                        start = right
                        end = left

            is_180_rot = start < end

            rect = cv2.minAreaRect(contours[0])
            box = cv2.boxPoints(rect)
            box = np.int0(box)
            box = np.where(box > 0, box, 0)

            dtl = math.inf
            for point in box:
                distance = dist([0, 0], point)
                if distance < dtl:
                    tl = point
                    dtl = distance
            elems = [tuple(elem) for elem in box.tolist()]
            ind = elems.index(tuple(tl))
            tl = elems[ind]
            tr = elems[(ind + 1) % len(elems)]
            br = elems[(ind + 2) % len(elems)]
            bl = elems[(ind + 3) % len(elems)]

            box = np.array([tr, tl, bl, br]).astype(np.float32)

            widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
            widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
            heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
            heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
            maxWidth = max(int(widthA), int(widthB))
            maxHeight = max(int(heightA), int(heightB))
            dst = np.array([
                [maxWidth - 1, 0],
                [0, 0],
                [0, maxHeight - 1],
                [maxWidth - 1, maxHeight - 1]], dtype="float32")
            M = cv2.getPerspectiveTransform(box, dst)
            warp_data[img_name] = [M, (maxWidth, maxHeight)]
            all_180.append(is_180_rot)
        s = [int(elem) for elem in all_180]
        s = sum(s) / len(s)
        is_180_rot_global = s > 0.5
        return is_180_rot_global, warp_data

    def save_prediction(self):
        """Сохранение в файл со всеми известными данными"""
        out_path = QFileDialog.getSaveFileName(filter=f'CSV file (*.csv)')[0]
        if not any(out_path):
            return
        data = []
        for group_path, group_data in self.data.items():
            preds = group_data['pred']
            group = os.path.split(group_path)[-1]
            data.append([group] + preds)
        df = pd.DataFrame(data, columns=['name', 'top1', 'top2', 'top3', 'top4', 'top5'])
        df.to_csv(out_path, index=False)

    def predict_all(self):
        if len(self.image_paths) == 0:
            return
        #self.parent.statusBar().showMessage("processing...", 0)
        self.parent.progress_bar.show()
        self.parent.statusBar().show()
        #self.parent.progress_bar.setValue(count)
        for group, group_data in self.data.items():
            img_data = group_data['img_data']

            preds = []
            for subgroup, subgroup_data in img_data.items():
                #self.parent.statusBar().showMessage('warping data...', 0)
                #self.parent.app.processEvents()
                #is_180_rot, warp_data = self.get_warp_data(group, subgroup)
                self.parent.progress_bar.setValue(0)
                self.parent.statusBar().showMessage(f'processing "{os.path.split(group)[-1]}/{subgroup}"...', 0)
                self.parent.app.processEvents()
                l = list(subgroup_data.items())[::step]
                for i, (img_name, mask) in enumerate(l):
                    image_path = os.path.join(group, subgroup, img_name)
                    #img = cv2.imread(image_path)

                    warp_mask = mask.copy()
                    warp_img = cv2.imread(image_path)
                    h, w, *_ = warp_mask.shape
                    #if h > w:
                    #    warp_img = np.rot90(warp_img)
                    #    warp_mask = np.rot90(warp_mask)
                    #warp_mask = cv2.warpPerspective(warp_mask, warp_data[img_name][0], warp_data[img_name][1])
                    #warp_img = cv2.warpPerspective(warp_img, warp_data[img_name][0], warp_data[img_name][1])

                    #h, w, *_ = warp_mask.shape
                    #if h > w:
                    #    continue
                    #if is_180_rot >= 0.5:
                    #    warp_img = warp_img[:, ::-1]
                    #    warp_mask = warp_mask[:, ::-1]

                    img = warp_img
                    img = img / 255
                    img = cv2.resize(img, (576, 576))
                    img = img.reshape(1, 576, 576, 3)
                    x = tf.expand_dims(img, axis=0)
                    y = model_ex(x[0])
                    y = y[0].numpy()
                    proba = max(cb_model.predict_proba(y))
                    #print(cb_model.predict(y))
                    if proba <= proba_thresh:
                        pred = 0
                    else:
                        pred = int(cb_model.predict(y)[0])

                    preds.append(pred)

                    self.parent.progress_bar.setValue(int(i / len(l) * 100))
                    self.parent.app.processEvents()
            print(os.path.split(group)[-1], preds)
            unique, counts = np.unique(preds, return_counts=True)
            x = list(sorted([tuple(elem) for elem in np.asarray((counts, unique)).T.tolist()], reverse=True))
            x = [elem[1] for elem in x]
            if len(x) < 5:
                x = x + [0] * (5 - len(x))
            group_data['pred'] = [x[0], 0, 0, 0, 0]#x[:5]
        self.parent.progress_bar.hide()
        self.parent.statusBar().hide()
        self.classSpinBox.setValue(self.data[self.cur_group]['pred'][0])

    def go_main_menu(self):
        self.parent.go_main_menu()

    def prev_img_id(self):
        self.cur_img_id -= 1

    def next_img_id(self):
        self.cur_img_id += 1

    def notify_none_cur_img(self):
        QMessageBox().warning(self, 'Warning', 'Cannot read image or path')

    def load_data(self):
        folder = QFileDialog.getExistingDirectory()
        if not any(folder):
            return
        self.parent.progress_bar.show()
        self.parent.statusBar().show()
        data = {}
        for group in os.listdir(folder):
            group_path = os.path.join(folder, group)
            if not os.path.isdir(group_path):
                continue
            data[group_path] = {'pred': [0, 0, 0, 0, 0], 'img_data': {}}
            for subgroup in os.listdir(group_path):
                self.parent.statusBar().showMessage(f'loading "{os.path.split(group)[-1]}/{subgroup}"...', 0)
                self.parent.progress_bar.setValue(0)
                self.parent.app.processEvents()
                subgroup_path = os.path.join(group_path, subgroup)
                if not os.path.isdir(subgroup_path):
                    continue
                data[group_path]['img_data'][subgroup] = {}
                filepaths = os.listdir(subgroup_path)
                for i, filepath in enumerate(filepaths):
                    full_filepath = os.path.join(subgroup_path, filepath)
                    if '.jpg' not in filepath or filepath.replace('.jpg', '.png') not in filepaths:
                        continue
                    data[group_path]['img_data'][subgroup][filepath] = cv2.imread(full_filepath.replace('.jpg', '.png'), cv2.IMREAD_GRAYSCALE)
                    self.parent.progress_bar.setValue(int(i / len(filepaths) * 100))
                    self.parent.app.processEvents()
            self.parent.app.processEvents()
        self.data = data
        self.group_id = 0
        #self.groupsList.setCurrentRow(0)
        self.parent.progress_bar.hide()
        self.parent.statusBar().hide()

    def filename_row_changed(self, row):
        self.cur_img_id = row

    def image_view_changed(self, index):
        self.image_view = ImageView(index)

    def group_row_changed(self, row):
        if row == -1:
            return
        self.group_id = row

    def subgroup_row_changed(self, row):
        if row == -1:
            return
        self.subgroup_id = row

    def paintEvent(self, event):
        if (self.cur_img is None and self.image_view != ImageView.ONLY_MASK) or \
                (self.cur_mask is None and self.image_view != ImageView.ORIGINAL_IMAGE):
            pixmap = QPixmap()
        else:
            if self.image_view == ImageView.ORIGINAL_IMAGE:
                img = self.cur_img
            else:
                # отрисовка изображения, связанного с маской
                mask = self.cur_mask
                # преобразование маски в изображение
                if self.image_view == ImageView.ONLY_MASK:
                    img = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)
                else:
                    if self.image_view == ImageView.INVERTED_MASKED_IMAGE:
                        mask = 255 - mask
                    img = cv2.bitwise_and(self.cur_img, self.cur_img, mask=mask)
            img = cv2.resize(img, self.pixmap_size)
            h, w, ch = img.shape
            qt_format = QImage(img.data, w, h, ch * w, QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(qt_format)
        self.imageLabel.setPixmap(pixmap)

    def draw_mask_line(self, from_point: Union[QPoint, QPointF], to_point: Union[QPoint, QPointF],
                       color: int, radius: int):
        if len(self.image_paths) == 0:
            return
        if isinstance(from_point, QPoint):
            from_point = self.get_percentage_point(from_point)
        if isinstance(to_point, QPoint):
            to_point = self.get_percentage_point(to_point)
        mask = self.data[self.cur_group]['img_data'][self.cur_subgroup][self.image_paths[self.cur_img_id]]
        if mask is None:
            return
        h, w = mask.shape
        start_point = (int(from_point.x() * w), int(from_point.y() * h))
        end_point = (int(to_point.x() * w), int(to_point.y() * h))
        cv2.line(mask, start_point, end_point, color, radius)

    def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
        image_point = self.get_image_point()
        self.last_image_point = image_point
        if a0.button() == Qt.LeftButton and 0 <= image_point.x() <= self.pixmap_size[0]:
            self._drawing_mask_color = 255
            self._is_drawing_mask = True
        elif a0.button() == Qt.RightButton and 0 <= image_point.y() <= self.pixmap_size[1]:
            self._drawing_mask_color = 0
            self._is_drawing_mask = True
        else:
            self._is_drawing_mask = False
        if self._is_drawing_mask:
            self.draw_mask_line(image_point, self.last_image_point, self._drawing_mask_color, self.drawingRadiusSpinBox.value())

    def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
        image_point = self.get_image_point()
        if self._is_drawing_mask:
            self.draw_mask_line(image_point, self.last_image_point, self._drawing_mask_color, self.drawingRadiusSpinBox.value())
        self.last_image_point = image_point

    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent) -> None:
        image_point = self.get_image_point()
        self._is_drawing_mask = False
        self._drawing_mask_color = 0
        self.last_image_point = image_point

    def get_image_point(self) -> QPoint:
        if self.cur_img is None:
            return QPoint(0, 0)
        image_point = self.imageLabel.mapFromGlobal(QCursor.pos())
        return image_point

    def get_actual_point(self, point: QPointF) -> QPoint:
        if self.cur_img is None:
            return QRect()
        return QPoint(int(point.x() * self.pixmap_size[0]), int(point.y() * self.pixmap_size[1]))

    def get_percentage_point(self, point: QPoint) -> QPointF:
        if self.cur_img is None:
            return QRect()
        return QPointF(point.x() / self.pixmap_size[0], point.y() / self.pixmap_size[1])

    def delete_cur_img(self):
        if len(self.image_paths) == 0:
            return
        del self.data[self.cur_group]['img_data'][self.cur_subgroup][self.image_paths[self.cur_img_id]]
        self.image_paths = self.image_paths[:self.cur_img_id] + self.image_paths[self.cur_img_id + 1:]

    def class_spin_box_changed(self, a0):
        if len(self.image_paths) == 0:
            return
        self.data[self.cur_group]['pred'][0] = a0
        self.update_top_predictions()

    def update_top_predictions(self):
        self.topPredictionsLabel.setText(f'Топ 5 предсказаний: {",".join([str(pred) for pred in self.data[self.cur_group]["pred"]])}')
        if self.data[self.cur_group]['pred'][0] == 0:
            self.notRecognizedWhaleLabel.show()
        else:
            self.notRecognizedWhaleLabel.hide()

    @property
    def image_paths(self):
        return self._image_paths

    @image_paths.setter
    def image_paths(self, value: List[str]):
        self._image_paths = value

        self.imageFilesList.clear()
        self.imageFilesList.addItems(value)

        # cur_img_id устанавливается после imageFilesList, потому что использует изменение индекса в imageFilesList
        self.cur_img_id = 0

    @property
    def cur_img_id(self):
        return self._cur_img_id

    @cur_img_id.setter
    def cur_img_id(self, value: int):
        if len(self._image_paths) == 0:
            self._cur_img_id = 0
            self._cur_img = None
            self.classSpinBox.setValue(1)
        else:
            self._cur_img_id = value % len(self._image_paths)

            group = self.cur_group
            subgroup = self.cur_subgroup
            img_name = self._image_paths[self._cur_img_id]
            #img_data = self.data[group]['img_data'][img_name]
            self._cur_img = cv2.imread(os.path.join(group, subgroup, img_name))
            if self._cur_img is not None:
                self._cur_img = cv2.cvtColor(self._cur_img, cv2.COLOR_BGR2RGB)
            else:
                self.notify_none_cur_img()
            self.imageFilesList.setCurrentRow(self._cur_img_id)
            self.classSpinBox.setValue(self.data[group]['pred'][0])

    @property
    def cur_img(self):
        return self._cur_img

    @property
    def cur_mask(self):
        if len(self.image_paths) == 0:
            return MAX_PIXMAP_SIDE, MAX_PIXMAP_SIDE
        filename = os.path.split(self.image_paths[self.cur_img_id])[-1]
        mask = self.data[self.cur_group]['img_data'][self.cur_subgroup][self.image_paths[self.cur_img_id]]
        if mask is None and self.cur_img is not None:
            mask = np.zeros(self.cur_img.shape[:2], dtype=np.uint8)
            self.masks[filename] = mask
        if self.cur_img is not None:
            h, w, _ = self.cur_img.shape
            mask = cv2.resize(mask, (w, h))
        return mask

    @property
    def pixmap_size(self):
        """w, h"""
        if self.cur_img is None:
            return MAX_PIXMAP_SIDE, MAX_PIXMAP_SIDE
        h_cur, w_cur, _ = self.cur_img.shape
        if h_cur > w_cur:
            k = MAX_PIXMAP_SIDE / h_cur
        else:
            k = MAX_PIXMAP_SIDE / w_cur
        return int(k * w_cur), int(k * h_cur)

    @property
    def group_id(self) -> int:
        return self._group_id

    @group_id.setter
    def group_id(self, val):
        self.groupsList.clear()

        if len(self.data.keys()) != 0:
            self._group_id = val % len(self.data.keys())
            self.groupsList.addItems(self.data.keys())
            # self.groupsList.setCurrentRow(self._group_id)
        else:
            self._group_id = 0

        self.subgroup_id = 0

    @property
    def cur_group(self):
        return list(self.data.keys())[self._group_id]

    @property
    def subgroup_id(self) -> int:
        return self.subgroup_id

    @subgroup_id.setter
    def subgroup_id(self, val):
        self.subgroupsList.clear()
        if len(self.data[self.cur_group].keys()) != 0:
            self._subgroup_id = val % len(self.data[self.cur_group]['img_data'].keys())
            self.subgroupsList.addItems(self.data[self.cur_group]['img_data'].keys())
            #self.subgroupsList.setCurrentRow(self._subgroup_id)
        else:
            self._subgroup_id = 0

        self.image_paths = list(self.data[self.cur_group]['img_data'][self.cur_subgroup].keys())

    @property
    def cur_subgroup(self):
        return list(self.data[self.cur_group]['img_data'].keys())[self._subgroup_id]

    def __init__(self, parent):
        super().__init__(parent)
        self.setupUi(self)
        self.parent = parent

        self.data = {}

        self.image_view = ImageView(self.imageViewComboBox.currentIndex())
        self.last_image_point = self.imageLabel.mapFromGlobal(QCursor.pos())
        self.masks: Dict[str, np.ndarray] = {}

        self._image_paths = []
        self._group_id = 0
        self._cur_img_id = 0
        self._cur_img = None

        self._is_drawing_mask = False
        self._drawing_mask_color = 0

        # ui
        self.prevButton.clicked.connect(self.prev_img_id)
        self.deleteButton.clicked.connect(self.delete_cur_img)
        self.nextButton.clicked.connect(self.next_img_id)

        self.imageViewComboBox.currentIndexChanged.connect(self.image_view_changed)

        self.imageFilesList.currentRowChanged.connect(self.filename_row_changed)
        self.groupsList.currentRowChanged.connect(self.group_row_changed)
        self.subgroupsList.currentRowChanged.connect(self.subgroup_row_changed)

        self.loadDataButton.clicked.connect(self.load_data)
        self.predictAllButton.clicked.connect(self.predict_all)
        self.savePredictionButton.clicked.connect(self.save_prediction)

        self.classSpinBox.valueChanged.connect(self.class_spin_box_changed)

        self.notRecognizedWhaleLabel.hide()


from selenium.webdriver import Chrome
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
import os

def element(by, value, parent, timeout=10):
    return WebDriverWait(parent, timeout).until(
        expected_conditions.presence_of_element_located((by, value))
    )

def main():
    options = Options()
    options.add_argument(
        "user-data-dir="
        + os.path.join(
            os.getenv("LOCALAPPDATA"), "Google", "Chrome", "User Data"
        )
    )
    service = Service()
    driver = Chrome(options, service)
    driver.get("https://www.payback.de/coupons")
    center = element(By.ID, "coupon-center", driver).shadow_root
    headline = element(
        By.CLASS_NAME, "coupon-center__header-published-headline", center
    )
    container = element(
        By.CLASS_NAME, "coupon-center__container-published-coupons", center
    )
    coupons = container.find_elements(By.TAG_NAME, "pbc-coupon")

    for index, coupon in enumerate(coupons):
        button = element(
            By.CSS_SELECTOR, "pbc-coupon-call-to-action", coupon.shadow_root
        )
        button.click()
        print("Coupon", index + 1, "/", len(coupons), "activated")

    driver.quit()

if __name__ == "__main__":
    main()


import json
import timeit
import itertools
from functools import partial

import pandas as pd
import nlpaug.augmenter.char as nac

import fasttextaug.augmenter.char as fac

data = pd.read_csv("/app/data/Reviews.csv")
REVIEWS = data.iloc[:, -1].to_list()

if __name__ == "__main__":
    bench_result = {}
    REPEATS = 3
    NUMBER_MY_LIB = 7
    NUMBER_THEIR_LIB = 1

    for flags in itertools.product([True, False], repeat=3):
        str_flags = str(flags)
        bench_result[str_flags] = {}
        special_char, numeric, uppercase = flags

        my_lib_aug = fac.KeyboardAug(
            include_special_char=special_char, include_numeric=numeric, include_upper_case=uppercase
        )
        exist_lib_aug = nac.KeyboardAug(
            include_special_char=special_char, include_numeric=numeric, include_upper_case=uppercase
        )

        for num_thread in (1, 2, 4, 8):
            bench_result[str_flags][num_thread] = {}
            my_bench = timeit.repeat(
                partial(my_lib_aug.augment, data=REVIEWS, num_thread=num_thread),
                repeat=REPEATS,
                number=NUMBER_MY_LIB,
            )
            bench_result[str_flags][num_thread]["fasttextaug"] = [
                i / NUMBER_MY_LIB for i in my_bench
            ]
            bench_result[str_flags][num_thread]["fasttextaug_number"] = NUMBER_MY_LIB
            bench_result[str_flags][num_thread]["fasttextaug_repeats"] = REPEATS

            if num_thread == 1:
                lib_bench = timeit.repeat(
                    partial(exist_lib_aug.augment, data=REVIEWS, num_thread=num_thread),
                    repeat=REPEATS,
                    number=NUMBER_THEIR_LIB,
                )
                bench_result[str_flags][num_thread]["nlpaug"] = [
                    i / NUMBER_THEIR_LIB for i in lib_bench
                ]
                bench_result[str_flags][num_thread]["nlpaug_number"] = NUMBER_THEIR_LIB
                bench_result[str_flags][num_thread]["nlpaug_repeats"] = REPEATS

    with open("/reports/keyboard/keyboard_list.json", "w") as file:
        print(json.dumps(bench_result), file=file)


##############################################################################
# Copyright 2016 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##############################################################################

import time
from logging import getLogger

from pyxcli import XCLI_DEFAULT_LOGGER
from pyxcli.mirroring.mirrored_entities import MirroredEntities
from pyxcli.mirroring.mirrored_entities import MirroredCachedEntities
from pyxcli.errors import XCLIError
from pyxcli.errors import CommandExecutionError
from pyxcli.errors import SyncAlreadyActiveError
from pyxcli.errors import SyncAlreadyInactiveError
from pyxcli.mirroring.errors import MirroringException
from pyxcli.mirroring.errors import NoMirrorDefinedError
from pyxcli.mirroring.errors import MirrorInactiveError

CHAR_LIMIT = 60

class RecoveryMethodNotImplementedException(MirroringException):
    pass

class SlaveIsNotConsistentRecoveryException(MirroringException):
    pass

class NoMirrorConnectivityRecoveryException(MirroringException):
    pass

class InsufficientSnapshotSpaceRecoveryException(MirroringException):
    pass

class LunNumberRecoveryException(MirroringException):
    pass

class AlreadyInTestFailoverStartRecoveryException(MirroringException):
    pass

class NoLastReplicatedSnapshotRecoveryException(MirroringException):
    pass

# ========================================================================
#     Base class for volume and consistency-group recovery managers
# ========================================================================

logger = getLogger(XCLI_DEFAULT_LOGGER + '.mirroring')

class RecoveryManager(object):
    xcli_client = None
    action_entities = None

    # ============================================ INIT =================
    def __init__(self, should_use_cache, xcli_client):
        self.xcli_client = xcli_client

        if (should_use_cache):
            self.action_entities = MirroredCachedEntities(
                xcli_client)
        else:
            self.action_entities = MirroredEntities(xcli_client)

    def set_action_entities(self, action_entities):
        self.action_entities = action_entities

    def get_mirror_resources(self):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def get_type_str(self):
        return " - "

    def get_target_by_system_id(self, system_id):
        target_names = [target.name for target in
                        self.xcli_client.cmd.target_list().as_list
                        if target.system_id == system_id]
        return target_names[0] if len(target_names) >= 1 else None

    # ========================================== FAILOVER =============
    def switch_roles(self, resource_id):
        self._switch_roles(resource_id)

    def verify_readiness_for_failover(self, resource_id):
        logger.debug("Verify failover readiness for %s %s" %
                     (self.get_type_str(), resource_id))
        self.verify_mirror_existence(resource_id)
        self.verify_slave_consistency(resource_id)

    def promote(self, resource_id):
        self.verify_mirror_existence(resource_id)
        xcli_mirror = self.get_mirror_resources()[resource_id]
        self._promote_resource(xcli_mirror, resource_id)

    def _promote_resource(self, xcli_mirror, resource_id):
        type_str = self.get_type_str()
        if not MirroredEntities.is_mirror_master(xcli_mirror):
            logger.debug("-> Promoting and setting [r/w] attributes "
                         "for %s [%s]." % (type_str, resource_id,))
            try:
                if self._is_sync_mirror(xcli_mirror):
                    self.snap_target_before_possible_override(resource_id)
                else:
                    self.duplicate_target_snapshot_before_possible_override(
                        resource_id)
            except CommandExecutionError as e:
                logger.warning("Failed to create failsafe snap group "
                               "for %s [%s]." % (type_str,
                                                 resource_id, str(e)))
            except Exception as e:
                logger.error("Unexpected exception %s", e)
                raise e
            self.change_role_to_master(resource_id)
        else:
            logger.warning("-> %s [%s] is already promoted to "
                           "Read-Write" % (type_str, resource_id,))

    # =============================================== TEST FAILOVER ==========
    def _get_snapshot_name(self, test_snapshot_prefix, resource_id,
                           snap_time_format):
        time_tuple = time.localtime()
        str_time = time.strftime(snap_time_format, time_tuple)
        snapshot_name = ("%s_%s_%s" % (test_snapshot_prefix,
                                       resource_id,
                                       str_time))[0:CHAR_LIMIT]
        return snapshot_name

    def test_promote_start(self, resource_id,
                           test_snapshot_prefix, snap_time_format):
        logger.info(
            "Commence: Temporary Snapshot Copy of [%s] on array is "
            "being created for testFailoverStart request" % (resource_id))
        self.verify_mirror_existence(resource_id)
        self._verify_resource_not_in_test_failover(
            resource_id, test_snapshot_prefix)
        self.verify_slave_consistency(resource_id)
        self.verify_snapshot_space_for_resource(resource_id)

        snapshot_name = self._get_snapshot_name(test_snapshot_prefix,
                                                resource_id, snap_time_format)
        self._create_and_unlock_snapshot(resource_id,
                                         snapshot_name,
                                         test_snapshot_prefix)

    def test_promote_stop(self, resource_id, test_snapshot_prefix):
        logger.info("Commence: Deletion of temporary Snapshot "
                    "%s Copy of [%s] for testFailoverStop"
                    "request." % (self.get_type_str(), resource_id,))
        self.verify_mirror_existence(resource_id)
        self._unmap_and_delete_test_snapshots(
            resource_id, test_snapshot_prefix)

    def _verify_resource_not_in_test_failover(self, resource_id,
                                              test_snapshot_prefix):
        if self._does_resource_have_mapped_test_snapshot(resource_id,
                                                         test_snapshot_prefix):
            raise AlreadyInTestFailoverStartRecoveryException()

    def _does_resource_have_mapped_test_snapshot(self, resource_id,
                                                 test_snapshot_prefix):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def _create_and_unlock_snapshot(self, resource_id,
                                    snapshot_name, test_snapshot_prefix):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def _unmap_and_delete_test_snapshots(self, resource_id,
                                         test_snapshot_prefix):
        raise RecoveryMethodNotImplementedException("Unsupported")

    # ============================================ REVERSE REPLICATION =======
    def prepare_reverse_replication(self, resource_id, should_unmap=False):

        # This method should be called on Primary before reverse_replication

        logger.info("Commence: %s [%s] is being set as target for replication "
                    "for prepareReverseReplication"
                    "request." % (self.get_type_str(), resource_id,))
        self.verify_mirror_existence(resource_id)
        self.verify_snapshot_space_for_resource(resource_id)
        self.snap_and_change_role_to_slave(resource_id)
        if should_unmap:
            self.unmap_all_volumes(resource_id)

    def reverse_replication(self, resource_id):

        # This method should be called on Secondary for reverse_replication

        logger.info("Commence: Establish replication for "
                    "%s [%s] with Primary role for reverseReplication "
                    "request." % (self.get_type_str(), resource_id,))
        self.verify_mirror_existence(resource_id)
        self.verify_mirror_connectivity(resource_id)

        self.reactivate_mirror(resource_id)
        logger.debug("-> Setting Primary role for "
                     "%s [%s]." % (self.get_type_str(), resource_id,))
        self._mirror_change_designation(resource_id, 'Primary')

    # ================================================= MIRROR ACTIONS =======

    def delete_mirror(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def activate_mirror(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def deactivate_mirror(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def is_mirror_active(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        return self._is_mirror_active(xcli_mirror)

    def reactivate_mirror(self, resource_id):
        logger.debug("-> Reactivating mirror for %s %s" %
                     (self.get_type_str(), resource_id))
        self.verify_mirror_existence(resource_id)
        xcli_mirror = self.get_mirror_resources()[resource_id]
        if self._is_mirror_active(xcli_mirror):
            self.deactivate_mirror(resource_id)
        self.activate_mirror(resource_id)

    def change_role_to_master(self, resource_id):
        self._change_role(resource_id, 'Master')

    def change_role_to_slave(self, resource_id):
        self._change_role(resource_id, 'Slave')

    def start_async_job(self, xcli_mirror):
        logger.debug("Starting manual sync job for %s => %s" % (
            xcli_mirror.local_peer_name, xcli_mirror.remote_peer_name))
        temp_schedule_name = ('temp_manual_%s' %
                              (xcli_mirror.local_peer_name,))[0:CHAR_LIMIT]
        current_schedule = xcli_mirror.schedule_name
        try:
            self.xcli_client.cmd.schedule_create(
                schedule=temp_schedule_name, type='manual')
            self._set_mirror_schedule(xcli_mirror, temp_schedule_name)
            self.xcli_client.cmd.schedule_create_tick(
                schedule=temp_schedule_name)
        except Exception as e:
            logger.error("Failed to start manual sync job for %s => %s."
                         " Reason: %s" % (xcli_mirror.local_peer_name,
                                          xcli_mirror.remote_peer_name,
                                          str(e)))
            raise (e)
        finally:
            self._set_mirror_schedule(xcli_mirror, current_schedule)
            self.xcli_client.cmd.schedule_delete(schedule=temp_schedule_name)

    def is_async_job_running(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def _create_mirror(self, resource_type, resource_name, target_name,
                       mirror_type, slave_resource_name, create_slave='no',
                       remote_pool=None, rpo=None, remote_rpo=None,
                       schedule=None, remote_schedule=None,
                       activate_mirror='no'):
        '''creates a mirror and returns a mirror object.
            resource_type must be 'vol' or 'cg',
            target name must be a valid target from target_list,
            mirror type must be 'sync' or 'async',
            slave_resource_name would be the slave_vol or slave_cg name'''

        kwargs = {
            resource_type: resource_name,
            'target': target_name,
            'type': mirror_type,
            'slave_' + resource_type: slave_resource_name,
            'create_slave': create_slave,
            'remote_pool': remote_pool,
            'rpo': rpo,
            'remote_rpo': remote_rpo,
            'schedule': schedule,
            'remote_schedule': remote_schedule
        }

        if mirror_type == 'sync':
            kwargs['type'] = 'sync_best_effort'
            kwargs['rpo'] = None
        else:
            kwargs['type'] = 'async_interval'
            if kwargs['remote_schedule'] is None:
                kwargs['remote_schedule'] = kwargs['schedule']

        # avoids a python3 issue of the dict changing
        # during iteration
        keys = set(kwargs.keys()).copy()
        for k in keys:
            if kwargs[k] is None:
                kwargs.pop(k)

        logger.info('creating mirror with arguments: %s' % kwargs)
        self.xcli_client.cmd.mirror_create(**kwargs)

        if activate_mirror == 'yes':
            logger.info('Activating mirror %s' % resource_name)
            self.activate_mirror(resource_name)

        return self.get_mirror_resources()[resource_name]

    def _set_mirror_schedule(self, xcli_mirror, new_schedule):
        is_cg = (xcli_mirror.mirror_object == 'CG')
        if is_cg:
            self.xcli_client.cmd.mirror_change_schedule(
                cg=xcli_mirror.local_peer_name, schedule=new_schedule)
        else:
            self.xcli_client.cmd.mirror_change_schedule(
                vol=xcli_mirror.local_peer_name, schedule=new_schedule)

    def _is_mirror_active(self, xcli_mirror):
        return xcli_mirror.active == "yes"

    def _delete_mirror(self, **kwargs):
        logger.info('Deleting mirror %s' % kwargs)
        self.xcli_client.cmd.mirror_delete(**kwargs)

    def _deactivate_mirror(self, **kwargs):
        # if we get SYNC_ALREADY_INACTIVE (status 3) it is safe to ignore it
        try:
            self.xcli_client.cmd.mirror_deactivate(**kwargs)
        except SyncAlreadyInactiveError:
            logger.warning("_deactivate_mirror got an error, "
                           "Synchronization is already inactive")

    def _activate_mirror(self, **kwargs):
        # if we get SYNC_ALREADY_ACTIVE (status 3) it is safe to ignore it
        try:
            self.xcli_client.cmd.mirror_activate(**kwargs)
        except SyncAlreadyActiveError:
            logger.warning("_activate_mirror got an error, "
                           "Synchronization is already active")

    def _change_role(self, resource_id, role):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def _switch_roles(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def _mirror_change_designation(self, resource_id, new_designation_str):
        raise RecoveryMethodNotImplementedException("Unsupported")

    # =============================================== MAPPING ================

    def unmap_all_volumes(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def unmap_volume(self, volume_name):
        logger.info("-> Remove all mappings of volume %s" % volume_name)
        for mapping in self.xcli_client.cmd.vol_mapping_list(vol=volume_name):
            if mapping.type == 'cluster':
                ports = self.action_entities.get_cluster_port_names(
                    mapping.host)
                logger.debug("-> Volume / Snapshot [%s] is being masked "
                             "from XIV cluster [%s]. Ports "
                             "contained %s." % (volume_name, mapping.host,
                                                ports))
                try:
                    self.xcli_client.cmd.unmap_vol(
                        vol=volume_name, cluster=mapping.host)
                except XCLIError as e:
                    logger.error(e)
                    raise e
            else:
                ports = self.action_entities.get_host_port_names(mapping.host)
                logger.debug("-> Volume / Snapshot [%s] is being masked from"
                             " XIV host [%s]. Ports "
                             "contained %s." % (volume_name, mapping.host,
                                                ports))
                self.xcli_client.cmd.unmap_vol(vol=volume_name,
                                               host=mapping.host)

    def is_volume_mapped(self, volume_name):
        logger.debug("Testing if volume %s is mapped" % volume_name)
        if len(self.xcli_client.cmd.vol_mapping_list(vol=volume_name)) > 0:
            logger.debug("Volume %s is mapped" % volume_name)
            return True
        logger.debug("Volume %s is not mapped" % volume_name)
        return False

    def _is_vol_locked(self, volume_name):
        status = self.action_entities.get_volume_by_name(volume_name).locked
        return status == 'yes'

    # ================================================= SNAPSHOT =============

    def snap_target_before_possible_override(self, resource_id,
                                             snap_name=None):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def duplicate_target_snapshot_before_possible_override(self, resource_id,
                                                           snapshot_name=None):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def snap_and_change_role_to_slave(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        type_str = self.get_type_str()
        if MirroredEntities.is_mirror_master(xcli_mirror):
            self.snap_target_before_possible_override(resource_id)
            logger.debug(
                "-> Setting %s [%s] as replication target." % (type_str,
                                                               resource_id))
            if self._is_mirror_active(xcli_mirror):
                self.deactivate_mirror(resource_id)
            self.change_role_to_slave(resource_id)
        else:
            logger.warning("-> %s [%s] is already a replication target "
                           "target" % (type_str, resource_id))

    def verify_snapshot_space_for_resource(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    # ================================================= QUERIES ==============

    def is_resource_locked(self, resource_id):
        raise RecoveryMethodNotImplementedException("Unsupported")

    def is_mirror_slave_ready_for_failover(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        return self._is_mirror_slave_ready_for_promote(xcli_mirror)

    def _is_mirror_slave_ready_for_promote(self, xcli_mirror):
        return xcli_mirror.sync_state != 'Initializing'

    def _is_sync_mirror(self, xcli_mirror):
        return xcli_mirror.sync_type == 'sync_best_effort'

    def verify_mirror_existence(self, resource_id):
        if resource_id not in self.get_mirror_resources():
            raise NoMirrorDefinedError()

    def verify_slave_consistency(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        if not self._is_slave_consistent(xcli_mirror):
            raise SlaveIsNotConsistentRecoveryException()

    def is_slave_consistent(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        return self._is_slave_consistent(xcli_mirror)

    def _is_slave_consistent(self, xcli_mirror):
        if not MirroredEntities.is_mirror_master(xcli_mirror):
            if not self._is_mirror_slave_ready_for_promote(xcli_mirror):
                return False
        return True

    def verify_mirror_is_active(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        self._verify_mirror_is_active(xcli_mirror)

    def _verify_mirror_is_active(self, xcli_mirror):
        if not self._is_mirror_active(xcli_mirror):
            if xcli_mirror.mirror_error == 'No_Error':
                msg = 'Deactivated by an admin'
            else:
                msg = xcli_mirror.mirror_error
            raise MirrorInactiveError(msg)

    def verify_mirror_connectivity(self, resource_id):
        xcli_mirror = self.get_mirror_resources()[resource_id]
        self._verify_mirror_connectivity(xcli_mirror)

    def _verify_mirror_connectivity(self, xcli_mirror):
        if not MirroredEntities.is_target_connected(xcli_mirror):
            raise NoMirrorConnectivityRecoveryException()

    def _does_pool_have_required_space_for_snapshots(self, pool_name,
                                                     num_of_volumes):
        pool = self.action_entities.get_pool_by_name(pool_name)
        snapshot_size = int(pool.snapshot_size)
        used_by_snapshots = int(pool.used_by_snapshots)
        # A new snapshot requires up to 17 GB per volume in an
        # XIV/Spectrum Accelerate system. The size is smaller for A9000.
        if snapshot_size > used_by_snapshots + num_of_volumes * 17 + 17:
            return True
        return False

    # ================================================= Actions ==============

    def is_cg_replicated(self, local_cg_id):
        return local_cg_id in self.action_entities.get_cg_mirrors()