from keras.utils.data_utils import get_file
import os
import numpy as np
from os import listdir
from os.path import isfile, join, isdir
import cv2
from random import shuffle
import math
from keras.callbacks import TensorBoard, EarlyStopping, ModelCheckpoint, ReduceLROnPlateau, LearningRateScheduler
from keras.models import Model
from keras import optimizers
import tensorflow as tf
from keras import backend as K
from keras.layers import Input, BatchNormalization, Activation, Dropout, Embedding, LSTM, Dense, Conv2D, MaxPooling2D, TimeDistributed, Flatten, concatenate, Reshape, Lambda
from keras.applications.vgg16 import VGG16
import scipy.ndimage as ndimage

import operator
from keras.applications.vgg16 import preprocess_input

# annot_path='/home/lfan/Dropbox/JointAttention/Data/annotation/'
#
# train_path='/home/lfan/Dropbox/JointAttention/faces/train_union/'
# train_sf=[f for f in listdir(train_path) if isdir(join(train_path,f))]
# validate_path='/home/lfan/Dropbox/JointAttention/faces/validate_union/'
# validate_sf=[f for f in listdir(validate_path) if isdir(join(validate_path,f))]
# test_path='/home/lfan/Dropbox/runCoAtt/rawData/images/separate/test/'
# test_sf=[f for f in listdir(test_path) if isdir(join(test_path,f))]

#
# vid_set=test_sf #train_sf
#
# annot_sf=[join(annot_path,f) for f in listdir(annot_path) if isdir(join(annot_path,f))]
#
# with open('/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_test_new.txt','w') as F:
#     for i in range(len(vid_set)):
#         sf = annot_path+vid_set[i]
#         vid = vid_set[i]
#
#         with open(join(sf, 'coattention.txt'), 'r') as r1:
#             lines = r1.readlines()
#         for j in range(0,len(lines),10):
#             list_now = lines[j].split()
#             frame_now = str(int(list_now[1])+1)
#             img_name = '/home/lfan/Dropbox/runCoAtt/rawData/images/all/' + frame_now.zfill(5) + '_' + vid + '.jpg'
#
#             ca_xmin=float(list_now[2])
#             ca_ymin=float(list_now[3])
#             ca_xmax=float(list_now[4])
#             ca_ymax=float(list_now[5])
#             ca_x=(ca_xmin+ca_xmax)/2
#             ca_y=(ca_ymin+ca_ymax)/2
#
#
#             num_face = (len(list_now) - 2) / 4 - 1
#             for k in range(num_face):
#                 face = list_now[(6 + k * 4):(10 + k * 4)]
#                 xmin=float(face[0])
#                 ymin=float(face[1])
#                 xmax=float(face[2])
#                 ymax=float(face[3])
#                 face_x=(xmin+xmax)/2
#                 face_y=(ymin+ymax)/2
#
#                 dir_x=ca_x-face_x
#                 dir_y=ca_y-face_y
#                 L=math.sqrt(dir_x ** 2 + dir_y ** 2)
#                 dir_x=dir_x/L
#                 dir_y=dir_y/L
#
#                 # if dir_y >= 0:
#                 #     direction = math.acos(dir_x / math.sqrt(dir_x ** 2 + dir_y ** 2))
#                 # elif dir_y < 0:
#                 #     direction = 2*math.pi - math.acos(dir_x / math.sqrt(dir_x ** 2 + dir_y ** 2))
#
#                 F.write(img_name+' '+str(xmin)+' '+str(ymin)+' '+str(xmax)+' '+str(ymax)+' '+str(dir_x)+' '+str(dir_y)+'\n')

# with open('/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_train.txt','r') as f:
#     lines=f.readlines()
#
# for i in range(len(lines)):
#     list=lines[i].split()
#     if not isfile(list[0]):
#
#         print(list[0])

# with open('/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_train.txt','r') as f:
#     lines=f.readlines()
#
# dir_hist=np.zeros(shape=(10,1))
# for i in range(len(lines)):
#     list=lines[i].split()
#
#     dir=int(float(list[5])//(2*math.pi/10))
#     if dir==10:
#         dir=0
#     dir_hist[dir,0]+=1
#
# print(dir_hist)

# with open('/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_test_new.txt','r') as f:
#     lines=f.readlines()
# with open('/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_test_flipped_new.txt','w') as f2:
#     for i in range(len(lines)):
#         list = lines[i].split()
#         xmin=float(list[1])
#         xmax=float(list[3])
#
#         xmax_n=480-xmin
#         xmin_n=480-xmax
#
#         dir_x=float(list[5])
#         dir_y=float(list[6])
#
#         dir_x=-dir_x
#         # if dir<0.5*(2*math.pi):
#         #     dir_n=0.5-dir
#         # else:
#         #     dir_n=1.5*(2*math.pi)-dir
#
#         f2.write(list[0]+' '+str(xmin_n)+' '+list[2]+' '+str(xmax_n)+' '+list[4]+' '+str(dir_x)+' '+str(dir_y)+' '+'f\n')

# gfdatapath='/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/'
#
# with open('/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/annotation_test.txt','r') as f:
#     lines=f.readlines()
# with open('/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/annotation_test_flipped.txt','w') as f2:
#     for i in range(len(lines)):
#         list = lines[i].split()
#         img=cv2.imread(join(gfdatapath,list[0]))
#         h, w, ch = img.shape
#
#         xmin=float(list[1])
#         xmax=float(list[3])+float(list[1])
#
#         xmax_n=w-xmin
#         xmin_n=w-xmax
#         w_n=xmax_n-xmin_n
#
#         dir=float(list[9])
#         if dir<0.5:
#             dir_n=0.5-dir
#         else:
#             dir_n=1.5-dir
#
#         f2.write(list[0]+' '+str(xmin_n)+' '+list[2]+' '+str(w_n)+' '+list[4]+' '+list[5]+' '+list[6]+' '+list[7]+' '+list[8]+' '+str(dir_n)+' '+'f\n')

batch_size=25
epochs=25

nb_train_samples=12000 # 13706
nb_validate_samples=6000 #8533
nb_test_samples=6000

model_weights_path = '/home/lfan/Dropbox/runCoAtt/new_experiment/gazedir/gazedir_finalweights.hdf5'
model_path = '/home/lfan/Dropbox/runCoAtt/new_experiment/gazedir/gazedir_finalmodel.h5'
tensorboard_log_dir = '/home/lfan/Dropbox/runCoAtt/new_experiment/gazedir/tb_log/'

gfdatapath='/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/'

def mygenerator(mode):

    if mode==1:
        file_name='/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_train_new.txt'
        #file_name_flip='/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_train_flipped.txt'
        #file_name_gazefollow='/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/annotation_train.txt'
        #file_name_gazefollow_flipped = '/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/annotation_train_flipped.txt'
        sample_len=nb_train_samples
    elif mode==2:
        file_name = '/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_validate_new.txt'
        #file_name_flip = '/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_validate_flipped.txt'
        #file_name_gazefollow = '/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/annotation_test.txt'
        #file_name_gazefollow_flipped = '/home/lfan/Dropbox/runCoAtt/vgg16/gazefollow_data/annotation_test_flipped.txt'
        sample_len=nb_validate_samples

    with open(file_name,'r') as reader:
        lines=reader.readlines()
    # with open(file_name_flip,'r') as reader:
    #     lines_flipped=reader.readlines()
    # with open(file_name_gazefollow,'r') as reader:
    #     lines_gazefollow=reader.readlines()
    # with open(file_name_gazefollow_flipped,'r') as reader:
    #     lines_gazefollow_flipped=reader.readlines()

    lines=lines[0:sample_len]
    #lines_flipped=lines_flipped[0:sample_len]

    #lines[0:0]=lines_flipped
    # lines[0:0]=lines_gazefollow
    # lines[0:0]=lines_gazefollow_flipped

    #lines=lines[0:sample_len]

    shuffle(lines)
    shuffle(lines)

    cur_batch_index=0
    while True:
        x_batch = np.zeros(shape=(batch_size, 224, 224, 3))
        y_batch = np.zeros(shape=(batch_size, 2))

        start_id = cur_batch_index * batch_size
        end_id = start_id + batch_size
        files_batch_now = lines[start_id:end_id]

        for j in range(batch_size):
            list_now=files_batch_now[j].split()

            if len(list_now)<8:

                img = cv2.imread(list_now[0])
                # if len(list_now) == 7:
                #     img = cv2.flip(img, 1)

                # cv2.imshow('flipped',img)
                # cv2.waitKey(0)
                # cv2.destroyAllWindows()

                xmin = int(float(list_now[1]))# - (float(list_now[3]) - float(list_now[1])) * 0)
                ymin = int(float(list_now[2]))# - (float(list_now[4]) - float(list_now[2])) * 0)
                xmax = int(float(list_now[3]))# + (float(list_now[3]) - float(list_now[1])) * 0)
                ymax = int(float(list_now[4]) )#+ (float(list_now[4]) - float(list_now[2])) * 0)

                # w = float(xmax - xmin)
                # h = float(ymax - ymin)
                # wh_list = [w, h]
                # max_index, max_value = max(enumerate(wh_list), key=operator.itemgetter(1))
                # pad = (wh_list[max_index] - wh_list[1 - max_index]) / 2
                # if max_index == 0:
                #     ymin = ymin - pad
                #     ymax = ymax + pad
                # elif max_index == 1:
                #     xmin -= pad
                #     xmax += pad

                xmin = int(max(0, xmin))
                ymin = int(max(0, ymin))

                xmax = max(xmin + 1, xmax)
                ymax = max(ymin + 1, ymax)

                xmax = int(min(479, xmax))
                ymax = int(min(319, ymax))

                #direction = float(list_now[5]) / (2 * math.pi)
                dir_x=float(list_now[5])
                dir_y=float(list_now[6])
                # print(img.shape)
                face = img[ymin:ymax, xmin:xmax, :]
                face = cv2.resize(face, (224, 224))

                #face=face.astype('float32')
                # face[:, :, 0] -= 123.68
                # face[:, :, 1] -= 116.779
                # face[:, :, 2] -= 103.939
                #face=(face/255)*2-1
                #print(direction)
                #cv2.putText(face, str(direction), (10, 500), cv2.FONT_HERSHEY_SIMPLEX, 4, (255, 255, 255), 2, cv2.LINE_AA)
                # cv2.imshow('face',face)
                # cv2.waitKey(0)
                # cv2.destroyAllWindows()

                x_batch[j, :, :, :] = face
                y_batch[j, 0] = dir_x
                y_batch[j, 1] = dir_y

            elif len(list_now)>9:

                name = list_now[0]
                bbox_x = int(float(list_now[1]))
                bbox_y = int(float(list_now[2]))
                bbox_w = int(float(list_now[3]))
                bbox_h = int(float(list_now[4]))
                eye_x = int(np.float32(list_now[5]))
                eye_y = int(np.float32(list_now[6]))
                direction = np.float32(list_now[9])

                img = cv2.imread(gfdatapath + name)
                if len(list_now)==11:
                    img = cv2.flip(img, 1)

                h, w, ch = img.shape
                totop = np.abs(eye_y - bbox_y)
                if int(totop) == 0:
                    totop = 10
                face_h = int(2* totop)
                face_w = int(2 * totop)
                face_x = int(eye_x - totop)
                face_y = int(eye_y - totop)

                if face_x < bbox_x:
                    face_x = bbox_x
                if face_y < bbox_y:
                    face_y = bbox_y
                if (face_x + face_w) > (bbox_x + bbox_w):
                    face_w = bbox_x + bbox_w - face_x
                if (face_y + face_h) > (bbox_y + bbox_h):
                    face_h = bbox_y + bbox_h - face_y

                if face_x < 0:
                    face_x = 0
                if face_y < 0:
                    face_y = 0

                face_w=max(1,face_w)
                face_h=max(1,face_h)

                if (face_x + face_w) > w:
                    face_w = w - face_x
                if (face_y + face_h) > h:
                    face_h = h - face_y

                face_pro = img[face_y:(face_y + face_h), face_x:(face_x + face_w), :]
                face_pro = cv2.resize(face_pro, (224, 224))

                face_pro=face_pro.astype('float32')
                # face_pro[:, :, 0] -= 103.939
                # face_pro[:, :, 1] -= 116.779
                # face_pro[:, :, 2] -= 123.68

                face_pro = np.float32(face_pro) / 255
                #direction = direction / (math.pi * 2)

                x_batch[j,:,:,:] = face_pro
                y_batch[j,0] = direction

            # cv2.imshow(str(direction),x_batch[j,:,:,:])
            # cv2.waitKey(0)
            # cv2.destroyAllWindows()

        yield  x_batch, y_batch

        cur_batch_index = cur_batch_index + 1
        if cur_batch_index >= (len(lines) // batch_size):
            cur_batch_index = 0
            shuffle(lines)
#
def myloss(y_true,y_pred):

    lamb=0.9
    loss=lamb*tf.reduce_sum(tf.square(y_true-y_pred))
    sess=tf.Session()
    sess.run(loss)
    #+(1-lamb)*tf.abs(1-tf.reduce_sum(tf.square(y_pred)))
    #loss= (1 - tf.matmul(y_true,y_pred,transpose_b=True)/tf.sqrt(tf.reduce_sum(tf.square(y_true))*tf.reduce_sum(tf.square(y_pred)))) #+ tf.abs(1-tf.reduce_sum(tf.square(y_pred)))
    # offset=np.abs(y_true-y_pred)
    # loss=2*((0.5-np.abs(offset-0.5))**2)

    return loss

def lr_decay(epoch):
    initial_lr = 1e-3
    drop = 0.8
    epochs_drop = 2
    lr = initial_lr * math.pow(drop, math.floor(epoch / epochs_drop))

    return lr

def train_model():

    img_input = Input(shape=(224, 224, 3), name='img_input')

    # Block 1
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)

    # Block 2
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)

    # Block 3
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)

    # Block 4
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)

    # Block 5
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
    base_output = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)

    base_model=Model(inputs=img_input,outputs=base_output)
    base_model.trainable=True
    WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'
    weights_path = get_file('vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5',
                            WEIGHTS_PATH_NO_TOP,
                            cache_subdir='models')

    base_model.load_weights(weights_path)

    output = Flatten(name='flatten')(base_output)
    output = Dense(4096, kernel_initializer='normal',activation='relu',name='fc1')(output)
    output = Dropout(0.5)(output)
    output = Dense(4096, kernel_initializer='normal',name='fc2')(output)
    output=BatchNormalization()(output)
    output=Activation('relu')(output)

    output = Dropout(0.5)(output)
    predict= Dense(2, kernel_initializer='normal',activation='tanh', name='predict')(output)

    # Create your own model
    mymodel = Model(inputs=img_input, outputs=predict)
    mymodel.summary()

    mycallback = []
    tbCallback = TensorBoard(log_dir=tensorboard_log_dir,
                             histogram_freq=0, batch_size=batch_size,
                             write_graph=True, write_images=True)
    lrscheduler = LearningRateScheduler(lr_decay)
    model_checkpoint = ModelCheckpoint(
        '/home/lfan/Dropbox/runCoAtt/new_experiment/gazedir/checkpoint.weights.{epoch:02d}-{val_loss:.2f}.hdf5',
        save_best_only=False,
        save_weights_only=True, monitor='val_loss')

    mycallback.append(tbCallback)
    mycallback.append(model_checkpoint)
    mycallback.append(lrscheduler)
    #sgd = optimizers.SGD(lr=1e-4)
    mymodel.compile(optimizer='sgd', loss='mse', metrics=['mae','acc'])

    history = mymodel.fit_generator(mygenerator(1),
                                     steps_per_epoch=(2*nb_train_samples) // batch_size,
                                     epochs=epochs,
                                     validation_data=mygenerator(2),
                                     validation_steps=(2*nb_validate_samples) // batch_size,
                                     callbacks=mycallback)
    mymodel.save_weights(model_weights_path)
    mymodel.save(model_path)
    score = mymodel.evaluate_generator(mygenerator(2), (2*nb_validate_samples) // batch_size)
    print("Validation Accuracy= ", score[1])

def testmodel():

    # img_input = Input(shape=(224, 224, 3), name='img_input')
    #
    # # Block 1
    # x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)
    # x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
    # x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
    #
    # # Block 2
    # x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
    # x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
    # x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
    #
    # # Block 3
    # x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
    # x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
    # x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
    # x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
    #
    # # Block 4
    # x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
    # x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
    # x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
    # x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
    #
    # # Block 5
    # x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
    # x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
    # x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
    # base_output = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
    #
    # output = Flatten(name='flatten')(base_output)
    # output = Dense(1024, activation='tanh', name='fc1')(output)
    # output = Dropout(0.5)(output)
    # output = Dense(512, activation='tanh', name='fc2')(output)
    # output = Dropout(0.5)(output)
    # output = Dense(128, activation='tanh', name='fc3')(output)
    # output = Dropout(0.5)(output)
    # predict = Dense(2, activation='tanh', name='predict')(output)

    img_input = Input(shape=(224, 224, 3), name='img_input')

    # Block 1
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)

    # Block 2
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)

    # Block 3
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)

    # Block 4
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)

    # Block 5
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
    base_output = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)

    output = Flatten(name='flatten')(base_output)
    output = Dense(4096, kernel_initializer='normal', activation='relu', name='fc1')(output)
    output = Dropout(0.5)(output)
    output = Dense(4096, kernel_initializer='normal', name='fc2')(output)
    output = BatchNormalization()(output)
    output = Activation('relu')(output)
    output = Dropout(0.5)(output)
    predict = Dense(2, kernel_initializer='normal', activation='tanh', name='predict')(output)

    # Create your own model
    mymodel = Model(inputs=img_input, outputs=predict)
    mymodel.summary()

    mymodel.load_weights('/home/lfan/Dropbox/runCoAtt/new_experiment/gazedir/checkpoint.weights.19-0.47.hdf5')

    file_name='/home/lfan/Dropbox/runCoAtt/rawData/gaze_summary_test_new.txt'
    sample_len=nb_test_samples

    with open(file_name,'r') as reader:
        lines=reader.readlines()

    lines=lines[0:sample_len]
    shuffle(lines)
    LOSS=0
    cnt=0
    for j in range(sample_len):
        list_now = lines[j].split()

        img = cv2.imread(list_now[0])
        xmin = int(float(list_now[1])) # - (float(list_now[3]) - float(list_now[1])) * 0)
        ymin = int(float(list_now[2])) # - (float(list_now[4]) - float(list_now[2])) * 0)
        xmax = int(float(list_now[3])) # + (float(list_now[3]) - float(list_now[1])) * 0)
        ymax = int(float(list_now[4])) # + (float(list_now[4]) - float(list_now[2])) * 0)

        xmin = max(0, xmin)
        ymin = max(0, ymin)

        xmax = max(xmin + 1, xmax)
        ymax = max(ymin + 1, ymax)

        xmax = min(479, xmax)
        ymax = min(319, ymax)

        dir_x=float(list_now[5])
        dir_y=float(list_now[6])

        #direction = float(list_now[5]) / (2 * math.pi)

        # print(img.shape)
        face = img[ymin:ymax, xmin:xmax, :]
        face = cv2.resize(face, (224, 224))

        #face = face.astype('float32')
        #face=face[:,:,::-1]

        # face[:, :, 0] -= 123.68
        # face[:, :, 1] -= 116.779
        # face[:, :, 2] -= 103.939

        #face=face/255
        # print(direction)
        # cv2.putText(face, str(direction), (10, 500), cv2.FONT_HERSHEY_SIMPLEX, 4, (255, 255, 255), 2, cv2.LINE_AA)

        x_batch=np.zeros(shape=(1,224,224,3))
        x_batch[0,:,:,:]=face
        res=mymodel.predict(x_batch,batch_size=1)
        res=res[0]
        print(res)
        print('GT: '+str(dir_x)+' '+str(dir_y))

        o_x=112
        o_y=112

        cv2.arrowedLine(face,(o_x,o_y),(o_x+int(res[0]*100),o_y+int(res[1]*100)),(0,0,255),5)
        cv2.arrowedLine(face, (o_x, o_y), (o_x + int(dir_x*100), o_y + int(dir_y*100)), (0, 255, 255), 5)
        cv2.imshow('face',face)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

        LOSS+=((dir_x-res[0])**2+(dir_y-res[1])**2)/2
        cnt+=1
        # cv2.imshow(str(res[0])+' '+str(res[1]), face)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
    print('Average loss: {}'.format(LOSS/cnt))

#train_model()
testmodel()


import scrapy
from module.items import HotlineItem

class HotlineSpider(scrapy.Spider):
    name = "hotline"
    allowed_domains = ["hotline.ua"]
    start_urls = [f"https://hotline.ua/ua/bt/holodilniki/?p={page}" for page in range(1, 4)]

    def parse(self, response):
        catalog = response.xpath('//div[contains(@class, "list-body__content")]').xpath('//div[contains(@class, "list-item ")]')

        for item in catalog:
            url = item.xpath('.//a[contains(@class, "list-item__title")]/@href').get()

            yield scrapy.Request(
                url=f"https://hotline.ua" + url,
                callback=self.parse_hotline
            )

    def parse_hotline(self, response):
        product_name = response.xpath('.//h1[contains(@class, "title__main")]/text()').get()
        store_name = response.xpath('.//div[1][@class="list__item row flex"]//a[@data-eventcategory="Pages Product Prices" and @class="shop__title"]/text()').get()
        price = response.xpath('.//div[1][@class="list__item row flex"]//span[@data-eventcategory="Pages Product Prices"]/span[@class="price__value"]/text()').get()

        yield HotlineItem(
            store_name=store_name,
            product_name=product_name,
            price=price
        )


from __future__ import absolute_import

import hashlib
import json
import os
import re
import socket

from mercurial.i18n import _

from mercurial import (
    error,
    pathutil,
    url as urlmod,
    util,
    vfs as vfsmod,
    worker,
)

from ..largefiles import lfutil

# 64 bytes for SHA256
_lfsre = re.compile(r'\A[a-f0-9]{64}\Z')

class lfsvfs(vfsmod.vfs):
    def join(self, path):
        """split the path at first two characters, like: XX/XXXXX..."""
        if not _lfsre.match(path):
            raise error.ProgrammingError('unexpected lfs path: %s' % path)
        return super(lfsvfs, self).join(path[0:2], path[2:])

    def walk(self, path=None, onerror=None):
        """Yield (dirpath, [], oids) tuple for blobs under path

        Oids only exist in the root of this vfs, so dirpath is always ''.
        """
        root = os.path.normpath(self.base)
        # when dirpath == root, dirpath[prefixlen:] becomes empty
        # because len(dirpath) < prefixlen.
        prefixlen = len(pathutil.normasprefix(root))
        oids = []

        for dirpath, dirs, files in os.walk(self.reljoin(self.base, path or ''),
                                            onerror=onerror):
            dirpath = dirpath[prefixlen:]

            # Silently skip unexpected files and directories
            if len(dirpath) == 2:
                oids.extend([dirpath + f for f in files
                             if _lfsre.match(dirpath + f)])

        yield ('', [], oids)

class filewithprogress(object):
    """a file-like object that supports __len__ and read.

    Useful to provide progress information for how many bytes are read.
    """

    def __init__(self, fp, callback):
        self._fp = fp
        self._callback = callback # func(readsize)
        fp.seek(0, os.SEEK_END)
        self._len = fp.tell()
        fp.seek(0)

    def __len__(self):
        return self._len

    def read(self, size):
        if self._fp is None:
            return b''
        data = self._fp.read(size)
        if data:
            if self._callback:
                self._callback(len(data))
        else:
            self._fp.close()
            self._fp = None
        return data

class local(object):
    """Local blobstore for large file contents.

    This blobstore is used both as a cache and as a staging area for large blobs
    to be uploaded to the remote blobstore.
    """

    def __init__(self, repo):
        fullpath = repo.svfs.join('lfs/objects')
        self.vfs = lfsvfs(fullpath)
        usercache = lfutil._usercachedir(repo.ui, 'lfs')
        self.cachevfs = lfsvfs(usercache)
        self.ui = repo.ui

    def open(self, oid):
        """Open a read-only file descriptor to the named blob, in either the
        usercache or the local store."""
        # The usercache is the most likely place to hold the file.  Commit will
        # write to both it and the local store, as will anything that downloads
        # the blobs.  However, things like clone without an update won't
        # populate the local store.  For an init + push of a local clone,
        # the usercache is the only place it _could_ be.  If not present, the
        # missing file msg here will indicate the local repo, not the usercache.
        if self.cachevfs.exists(oid):
            return self.cachevfs(oid, 'rb')

        return self.vfs(oid, 'rb')

    def download(self, oid, src):
        """Read the blob from the remote source in chunks, verify the content,
        and write to this local blobstore."""
        sha256 = hashlib.sha256()

        with self.vfs(oid, 'wb', atomictemp=True) as fp:
            for chunk in util.filechunkiter(src, size=1048576):
                fp.write(chunk)
                sha256.update(chunk)

            realoid = sha256.hexdigest()
            if realoid != oid:
                raise error.Abort(_('corrupt remote lfs object: %s') % oid)

        # XXX: should we verify the content of the cache, and hardlink back to
        # the local store on success, but truncate, write and link on failure?
        if not self.cachevfs.exists(oid):
            self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
            lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))

    def write(self, oid, data):
        """Write blob to local blobstore.

        This should only be called from the filelog during a commit or similar.
        As such, there is no need to verify the data.  Imports from a remote
        store must use ``download()`` instead."""
        with self.vfs(oid, 'wb', atomictemp=True) as fp:
            fp.write(data)

        # XXX: should we verify the content of the cache, and hardlink back to
        # the local store on success, but truncate, write and link on failure?
        if not self.cachevfs.exists(oid):
            self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
            lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))

    def read(self, oid, verify=True):
        """Read blob from local blobstore."""
        if not self.vfs.exists(oid):
            blob = self._read(self.cachevfs, oid, verify)

            # Even if revlog will verify the content, it needs to be verified
            # now before making the hardlink to avoid propagating corrupt blobs.
            # Don't abort if corruption is detected, because `hg verify` will
            # give more useful info about the corruption- simply don't add the
            # hardlink.
            if verify or hashlib.sha256(blob).hexdigest() == oid:
                self.ui.note(_('lfs: found %s in the usercache\n') % oid)
                lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
        else:
            self.ui.note(_('lfs: found %s in the local lfs store\n') % oid)
            blob = self._read(self.vfs, oid, verify)
        return blob

    def _read(self, vfs, oid, verify):
        """Read blob (after verifying) from the given store"""
        blob = vfs.read(oid)
        if verify:
            _verify(oid, blob)
        return blob

    def has(self, oid):
        """Returns True if the local blobstore contains the requested blob,
        False otherwise."""
        return self.cachevfs.exists(oid) or self.vfs.exists(oid)

class _gitlfsremote(object):

    def __init__(self, repo, url):
        ui = repo.ui
        self.ui = ui
        baseurl, authinfo = url.authinfo()
        self.baseurl = baseurl.rstrip('/')
        useragent = repo.ui.config('experimental', 'lfs.user-agent')
        if not useragent:
            useragent = 'git-lfs/2.3.4 (Mercurial %s)' % util.version()
        self.urlopener = urlmod.opener(ui, authinfo, useragent)
        self.retry = ui.configint('lfs', 'retry')

    def writebatch(self, pointers, fromstore):
        """Batch upload from local to remote blobstore."""
        self._batch(pointers, fromstore, 'upload')

    def readbatch(self, pointers, tostore):
        """Batch download from remote to local blostore."""
        self._batch(pointers, tostore, 'download')

    def _batchrequest(self, pointers, action):
        """Get metadata about objects pointed by pointers for given action

        Return decoded JSON object like {'objects': [{'oid': '', 'size': 1}]}
        See https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
        """
        objects = [{'oid': p.oid(), 'size': p.size()} for p in pointers]
        requestdata = json.dumps({
            'objects': objects,
            'operation': action,
        })
        batchreq = util.urlreq.request('%s/objects/batch' % self.baseurl,
                                       data=requestdata)
        batchreq.add_header('Accept', 'application/vnd.git-lfs+json')
        batchreq.add_header('Content-Type', 'application/vnd.git-lfs+json')
        try:
            rawjson = self.urlopener.open(batchreq).read()
        except util.urlerr.httperror as ex:
            raise LfsRemoteError(_('LFS HTTP error: %s (action=%s)')
                                 % (ex, action))
        try:
            response = json.loads(rawjson)
        except ValueError:
            raise LfsRemoteError(_('LFS server returns invalid JSON: %s')
                                 % rawjson)
        return response

    def _checkforservererror(self, pointers, responses, action):
        """Scans errors from objects

        Raises LfsRemoteError if any objects have an error"""
        for response in responses:
            # The server should return 404 when objects cannot be found. Some
            # server implementation (ex. lfs-test-server)  does not set "error"
            # but just removes "download" from "actions". Treat that case
            # as the same as 404 error.
            notfound = (response.get('error', {}).get('code') == 404
                        or (action == 'download'
                            and action not in response.get('actions', [])))
            if notfound:
                ptrmap = {p.oid(): p for p in pointers}
                p = ptrmap.get(response['oid'], None)
                if p:
                    filename = getattr(p, 'filename', 'unknown')
                    raise LfsRemoteError(
                        _(('LFS server error. Remote object '
                          'for "%s" not found: %r')) % (filename, response))
                else:
                    raise LfsRemoteError(
                        _('LFS server error. Unsolicited response for oid %s')
                        % response['oid'])
            if 'error' in response:
                raise LfsRemoteError(_('LFS server error: %r') % response)

    def _extractobjects(self, response, pointers, action):
        """extract objects from response of the batch API

        response: parsed JSON object returned by batch API
        return response['objects'] filtered by action
        raise if any object has an error
        """
        # Scan errors from objects - fail early
        objects = response.get('objects', [])
        self._checkforservererror(pointers, objects, action)

        # Filter objects with given action. Practically, this skips uploading
        # objects which exist in the server.
        filteredobjects = [o for o in objects if action in o.get('actions', [])]

        return filteredobjects

    def _basictransfer(self, obj, action, localstore):
        """Download or upload a single object using basic transfer protocol

        obj: dict, an object description returned by batch API
        action: string, one of ['upload', 'download']
        localstore: blobstore.local

        See https://github.com/git-lfs/git-lfs/blob/master/docs/api/\
        basic-transfers.md
        """
        oid = str(obj['oid'])

        href = str(obj['actions'][action].get('href'))
        headers = obj['actions'][action].get('header', {}).items()

        request = util.urlreq.request(href)
        if action == 'upload':
            # If uploading blobs, read data from local blobstore.
            with localstore.open(oid) as fp:
                _verifyfile(oid, fp)
            request.data = filewithprogress(localstore.open(oid), None)
            request.get_method = lambda: 'PUT'

        for k, v in headers:
            request.add_header(k, v)

        response = b''
        try:
            req = self.urlopener.open(request)
            if action == 'download':
                # If downloading blobs, store downloaded data to local blobstore
                localstore.download(oid, req)
            else:
                while True:
                    data = req.read(1048576)
                    if not data:
                        break
                    response += data
                if response:
                    self.ui.debug('lfs %s response: %s' % (action, response))
        except util.urlerr.httperror as ex:
            if self.ui.debugflag:
                self.ui.debug('%s: %s\n' % (oid, ex.read()))
            raise LfsRemoteError(_('HTTP error: %s (oid=%s, action=%s)')
                                 % (ex, oid, action))

    def _batch(self, pointers, localstore, action):
        if action not in ['upload', 'download']:
            raise error.ProgrammingError('invalid Git-LFS action: %s' % action)

        response = self._batchrequest(pointers, action)
        objects = self._extractobjects(response, pointers, action)
        total = sum(x.get('size', 0) for x in objects)
        sizes = {}
        for obj in objects:
            sizes[obj.get('oid')] = obj.get('size', 0)
        topic = {'upload': _('lfs uploading'),
                 'download': _('lfs downloading')}[action]
        if len(objects) > 1:
            self.ui.note(_('lfs: need to transfer %d objects (%s)\n')
                         % (len(objects), util.bytecount(total)))
        self.ui.progress(topic, 0, total=total)
        def transfer(chunk):
            for obj in chunk:
                objsize = obj.get('size', 0)
                if self.ui.verbose:
                    if action == 'download':
                        msg = _('lfs: downloading %s (%s)\n')
                    elif action == 'upload':
                        msg = _('lfs: uploading %s (%s)\n')
                    self.ui.note(msg % (obj.get('oid'),
                                 util.bytecount(objsize)))
                retry = self.retry
                while True:
                    try:
                        self._basictransfer(obj, action, localstore)
                        yield 1, obj.get('oid')
                        break
                    except socket.error as ex:
                        if retry > 0:
                            self.ui.note(
                                _('lfs: failed: %r (remaining retry %d)\n')
                                % (ex, retry))
                            retry -= 1
                            continue
                        raise

        # Until https multiplexing gets sorted out
        if self.ui.configbool('experimental', 'lfs.worker-enable'):
            oids = worker.worker(self.ui, 0.1, transfer, (),
                                 sorted(objects, key=lambda o: o.get('oid')))
        else:
            oids = transfer(sorted(objects, key=lambda o: o.get('oid')))

        processed = 0
        for _one, oid in oids:
            processed += sizes[oid]
            self.ui.progress(topic, processed, total=total)
            self.ui.note(_('lfs: processed: %s\n') % oid)
        self.ui.progress(topic, pos=None, total=total)

    def __del__(self):
        # copied from mercurial/httppeer.py
        urlopener = getattr(self, 'urlopener', None)
        if urlopener:
            for h in urlopener.handlers:
                h.close()
                getattr(h, "close_all", lambda : None)()

class _dummyremote(object):
    """Dummy store storing blobs to temp directory."""

    def __init__(self, repo, url):
        fullpath = repo.vfs.join('lfs', url.path)
        self.vfs = lfsvfs(fullpath)

    def writebatch(self, pointers, fromstore):
        for p in pointers:
            content = fromstore.read(p.oid(), verify=True)
            with self.vfs(p.oid(), 'wb', atomictemp=True) as fp:
                fp.write(content)

    def readbatch(self, pointers, tostore):
        for p in pointers:
            with self.vfs(p.oid(), 'rb') as fp:
                tostore.download(p.oid(), fp)

class _nullremote(object):
    """Null store storing blobs to /dev/null."""

    def __init__(self, repo, url):
        pass

    def writebatch(self, pointers, fromstore):
        pass

    def readbatch(self, pointers, tostore):
        pass

class _promptremote(object):
    """Prompt user to set lfs.url when accessed."""

    def __init__(self, repo, url):
        pass

    def writebatch(self, pointers, fromstore, ui=None):
        self._prompt()

    def readbatch(self, pointers, tostore, ui=None):
        self._prompt()

    def _prompt(self):
        raise error.Abort(_('lfs.url needs to be configured'))

_storemap = {
    'https': _gitlfsremote,
    'http': _gitlfsremote,
    'file': _dummyremote,
    'null': _nullremote,
    None: _promptremote,
}

def _verify(oid, content):
    realoid = hashlib.sha256(content).hexdigest()
    if realoid != oid:
        raise error.Abort(_('detected corrupt lfs object: %s') % oid,
                          hint=_('run hg verify'))

def _verifyfile(oid, fp):
    sha256 = hashlib.sha256()
    while True:
        data = fp.read(1024 * 1024)
        if not data:
            break
        sha256.update(data)
    realoid = sha256.hexdigest()
    if realoid != oid:
        raise error.Abort(_('detected corrupt lfs object: %s') % oid,
                          hint=_('run hg verify'))

def remote(repo):
    """remotestore factory. return a store in _storemap depending on config"""
    url = util.url(repo.ui.config('lfs', 'url') or '')
    scheme = url.scheme
    if scheme not in _storemap:
        raise error.Abort(_('lfs: unknown url scheme: %s') % scheme)
    return _storemap[scheme](repo, url)

class LfsRemoteError(error.RevlogError):
    pass


# Creating a regression line - aka line of best fit
# Y = mx + b
from statistics import mean
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style

style.use('fivethirtyeight')

# defined as numpy arrays
xs = np.array([1,2,3,4,5,6], dtype=np.float64)
ys = np.array([5,4,6,5,6,7], dtype=np.float64)

def best_fit_slope_and_intercept(xs,ys):
    m = (((mean(xs) * mean(ys)) - mean(xs*ys)) / ( (mean(xs) * mean(xs)) - mean(xs**2)    ) )
    b = mean(ys) - m*mean(xs)
    return m,b;

m,b = best_fit_slope_and_intercept(xs,ys)

#Creating line via for loop
regression_line = [(m*x)+b for x in xs]

#print(m,b)

predict_x = 8
predict_y = (m*predict_x + b)

#Create plots
plt.scatter(xs,ys)
plt.scatter(predict_x,predict_y)
plt.plot(xs, regression_line)
plt.show()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Resize and add text to videos

Usage example:
  $ python transform.py

"""

import random
import os
import shutil
from moviepy.editor import *
from moviepy.video.tools.subtitles import SubtitlesClip
from sqlite import *

class VideoTransform:
    def __init__(self, videos=[]):
        print(' ----> {} videos to transform'.format(len(videos)))
        for video in videos:
            video['clip'] = VideoFileClip(video['filepath'])
        self.videos = videos
        print(' --> {} videos converted to clips'.format(len(self.videos)))

    def adjustSize(self, clip,width,height):
        # get current dimensions and ratio
        clipWidth,clipHeight = clip.size
        ratio = clipWidth / clipHeight
        # resize the clip
        if ratio > (width/height):
            clip2 = clip.resize(width=width)
        else:
            clip2 = clip.resize(height=height)
        return clip2

    def adjustSizes(self,width=1920,height=1080):
        for video in self.videos:
            video['clip'] = self.adjustSize(video['clip'],width,height)

    def addSubtitle(self, clip, subtitle, howLong, maxLength=15):
        # trim the subtitle if it's too long
        if len(subtitle) > maxLength:
            subtitle = subtitle[:maxLength] + '...'
        # set how long the subtitle will show
        howLong = min(howLong,clip.duration)
        subs = [((0, howLong), subtitle)]
        # create clip with subtitle
        subtitles = SubtitlesClip(subs, lambda txt: TextClip(txt, font='Arial', fontsize=72, color='white', stroke_color='black'))
        # merge clip and subtitles
        result = CompositeVideoClip([clip, subtitles.set_position(('center','bottom'))])
        # return resulting clip
        return result

    def addSubtitles(self, howLong=10):
        print(' ----> Adding subtitles')
        for index, video in enumerate(self.videos):
            video['clip'] = self.addSubtitle(video['clip'],video['title'],howLong)
            print(' --> {}/{} subtitles added'.format(index+1,len(self.videos)))

    def addSource(self,clip,source,howLong):
        howLong = min(howLong,clip.duration)
        subs = [((0, howLong), source)]
        # create clip with source
        subtitles = SubtitlesClip(subs, lambda txt: TextClip(txt, font='Arial', fontsize=24, color='white', bg_color='black'))
        # merge clip and text
        result = CompositeVideoClip([clip, subtitles.set_position((0,0))])
        # return resulting clip
        return result

    def addSources(self, howLong=10):
        print(' ----> Adding sources')
        for index, video in enumerate(self.videos):
            video['clip'] = self.addSource(video['clip'],video['link'],howLong)
            print(' --> {}/{} sources added'.format(index+1,len(self.videos)))

    def save(self, clip, filename, threads=1):
        filepath = os.path.join(os.getcwd(),filename)
        clip.write_videofile(filepath, codec='mpeg4', audio=True, threads=threads)
        return filepath

if __name__ == '__main__':
    # get videos from DB
    sql = Sqlite()
    result = sql.run('SELECT * FROM videos WHERE duration IS NULL')
    videos = [ row for row in result if os.path.isfile(row['filepath']) ]

    # convert them to clips
    limit = 10
    transform = VideoTransform(videos[:limit])

    # resize them
    transform.adjustSizes()

    # add subtitles
    transform.addSubtitles()

    # add link to original
    transform.addSources()

    # backup the original videos
    # and save the updated versions
    for video in transform.videos:
        shutil.move(video['filepath'],video['filepath']+'.original')
        transform.save(video['clip'],video['filepath'])

    # update their durations and sizes on the DB
    for video in transform.videos:
        filepath = video['filepath']
        duration = video['clip'].duration
        width,height = video['clip'].size
        sql.run('''
            UPDATE videos
            SET duration = {duration},
                width    = {width},
                height   = {height}
            WHERE
                filepath = '{filepath}'
        '''.format(
            duration=duration,
            filepath=filepath,
            width=width,
            height=height
        ))


from django.shortcuts import render, get_object_or_404
from .models import Post, Comment
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .forms import CommentForm
from django.views.decorators.http import require_POST
from taggit.models import Tag
"""
This is the Count aggregation function of the Django ORM. This function will
allow you to perform aggregated counts of tags. django.db.models includes the
following aggregation functions:
• Avg: The mean value
• Max: The maximum value
• Min: The minimum value
• Count: The total number of objects
"""
from django.db.models import Count
from itertools import chain

# Define the number of elements in one page
page_elements_count = 6

# Define number of similar posts
similar_posts_count = 3

# Create your views here.
def blog_list(request, tag_slug=None):

    post_list = Post.published.all()

    tag = None
    if tag_slug:
        tag = get_object_or_404(Tag, slug=tag_slug)
        post_list = post_list.filter(tags__in=[tag])

    posts_count = post_list.count()

    # Pagination with page_elements_count per page
    paginator = Paginator(post_list, page_elements_count)

    # f the page parameter is not in the GET parameters of the request, we use
    # the default value 1 to load the first page of results.
    page_number = request.GET.get('page', 1)

    # Try get the requested page
    try:
        posts = paginator.page(page_number)

    # If the requests page is out of range, retrun the last page
    except EmptyPage:
        # If page_number is out of range deliver last page of results
        posts = paginator.page(paginator.num_pages)

    # If the requests page is not an integer, return the first page
    except PageNotAnInteger:
        posts = paginator.page(1)

    return render(
        request,
        'blog/blog_home.html',
        {
            'posts': posts,
            'posts_count': posts_count,
            'tag': tag,
        }
    )

def blog_post(request, post_slug):

    post = get_object_or_404(
        Post,
        slug=post_slug,
        status=Post.Status.PUBLISHED
    )
    # List of active comments for this post
    comments = post.comments.filter(active=True)

    if request.method == 'GET':

        # Form for users to comment
        form = CommentForm()

    else:

        # Define a comment variable with the initial value None. This variable will
        # be used to store the comment object when it gets created.
        comment = None

        form = CommentForm(data=request.POST)

        if form.is_valid():
            comment = form.save(commit=False)

            # Assign the post attribute of the comment to the current post
            comment.post = post

            # Save the comment to the database
            comment.save()

    # List of similar posts

    # retrieve a Python list of IDs for the tags of the current post. The
    # values_list() QuerySet returns tuples with the values for the given
    # fields. We pass flat=True to it to get single values such as
    # [1, 2, 3, ...] instead of one-tuples such as [(1,), (2,), (3,) ...]
    post_tags_ids = post.tags.values_list('id', flat=True)

    # We get all posts that contain any of these tags, excluding the current
    # post itself.
    similar_posts = Post.published.filter(tags__in=post_tags_ids).exclude(id=post.id)

    # use the Count aggregation function to generate a calculated
    # field (same_tags) that contains the number of tags shared with all the
    # tags queried.
    # We order the result by the number of shared tags (descending order) and
    # by publish to display recent posts first for the posts with the same
    # number of shared tags. We slice the result to retrieve only the first
    # three posts.
    similar_posts = similar_posts.annotate(same_tags=Count('tags'))\
                        .order_by('-same_tags', '-created')[:similar_posts_count]

    # Fill similar posts with normal posts; if the similar posts are less than
    # the required similar_posts_count
    if len(similar_posts) < similar_posts_count:
        extra_posts_count = similar_posts_count - len(similar_posts)
        extra_posts = Post.published.order_by('-created').exclude(id=post.id)\
                          .exclude(id__in=similar_posts)[:extra_posts_count]
        similar_posts = list(chain(similar_posts, extra_posts))

    return render(
        request,
        'blog/blog_post.html',
        {
            'post': post,
            'form': form,
            'comments': comments,
            'similar_posts': similar_posts,
        }
    )


# -*- coding: utf-8 -*-
from enum import Enum

class SolarTerms(Enum):
    the_beginning_of_spring = "the Beginning of Spring", "立春"
    rain_water = "Rain Water", "雨水"
    the_waking_of_insects = "the Waking of Insects", "惊蛰"
    the_spring_equinox = "the Spring Equinox", "春分"
    pure_brightness = "Pure Brightness", "清明"
    grain_rain = "Grain Rain", "谷雨"
    the_beginning_of_summer = "the Beginning of Summer", "立夏"
    lesser_fullness_of_grain = "Lesser Fullness of Grain", "小满"
    grain_in_beard = "Grain in Beard", "芒种"
    the_summer_solstice = "the Summer Solstice", "夏至"
    lesser_heat = "Lesser Heat", "小暑"
    greater_heat = "Greater Heat", "大暑"
    the_beginning_of_autumn = "the Beginning of Autumn", "立秋"
    the_end_of_heat = "the End of Heat", "处暑"
    white_dew = "White Dew", "白露"
    the_autumn_equinox = "the Autumn Equinox", "秋分"
    code_dew = "Cold Dew", "寒露"
    frost_descent = "Frost's Descent", "霜降"
    the_beginning_of_winter = "the Beginning of Winter", "立冬"
    lesser_snow = "Lesser Snow", "小雪"
    greater_snow = "Greater Snow", "大雪"
    the_winter_solstice = "the Winter Solstice", "冬至"
    lesser_cold = "Lesser Cold", "小寒"
    greater_cold = "Greater Cold", "大寒"

# 计算节气用的 C 值
# 2000年的小寒、大寒、立春、雨水按照20世纪的C值来算
SOLAR_TERMS_C_NUMS = {
    # 节气: [20世纪值， 21世纪值]
    SolarTerms.the_beginning_of_spring: [4.6295, 3.87],
    SolarTerms.rain_water: [19.4599, 18.73],
    SolarTerms.the_waking_of_insects: [6.3926, 5.63],
    SolarTerms.the_spring_equinox: [21.4155, 20.646],
    SolarTerms.pure_brightness: [5.59, 4.81],
    SolarTerms.grain_rain: [20.888, 20.1],
    SolarTerms.the_beginning_of_summer: [6.318, 5.52],
    SolarTerms.lesser_fullness_of_grain: [21.86, 21.04],
    SolarTerms.grain_in_beard: [6.5, 5.678],
    SolarTerms.the_summer_solstice: [22.2, 21.37],
    SolarTerms.lesser_heat: [7.928, 7.108],
    SolarTerms.greater_heat: [23.65, 22.83],
    SolarTerms.the_beginning_of_autumn: [28.35, 7.5],
    SolarTerms.the_end_of_heat: [23.95, 23.13],
    SolarTerms.white_dew: [8.44, 7.646],
    SolarTerms.the_autumn_equinox: [23.822, 23.042],
    SolarTerms.code_dew: [9.098, 8.318],
    SolarTerms.frost_descent: [24.218, 23.438],
    SolarTerms.the_beginning_of_winter: [8.218, 7.438],
    SolarTerms.lesser_snow: [23.08, 22.36],
    SolarTerms.greater_snow: [7.9, 7.18],
    SolarTerms.the_winter_solstice: [22.6, 21.94],
    SolarTerms.lesser_cold: [6.11, 5.4055],
    SolarTerms.greater_cold: [20.84, 20.12],
}

# 月份和节气对应关系
SOLAR_TERMS_MONTH = {
    1: [SolarTerms.lesser_cold, SolarTerms.greater_cold],
    2: [SolarTerms.the_beginning_of_spring, SolarTerms.rain_water],
    3: [SolarTerms.the_waking_of_insects, SolarTerms.the_spring_equinox],
    4: [SolarTerms.pure_brightness, SolarTerms.grain_rain],
    5: [SolarTerms.the_beginning_of_summer, SolarTerms.lesser_fullness_of_grain],
    6: [SolarTerms.grain_in_beard, SolarTerms.the_summer_solstice],
    7: [SolarTerms.lesser_heat, SolarTerms.greater_heat],
    8: [SolarTerms.the_beginning_of_autumn, SolarTerms.the_end_of_heat],
    9: [SolarTerms.white_dew, SolarTerms.the_autumn_equinox],
    10: [SolarTerms.code_dew, SolarTerms.frost_descent],
    11: [SolarTerms.the_beginning_of_winter, SolarTerms.lesser_snow],
    12: [SolarTerms.greater_snow, SolarTerms.the_winter_solstice],
}

# 有些节气使用公式计算计算的不够准确，需要进行偏移
SOLAR_TERMS_DELTA = {
    (2026, SolarTerms.rain_water): -1,
    (2084, SolarTerms.the_spring_equinox): 1,
    (1911, SolarTerms.the_beginning_of_summer): 1,
    (2008, SolarTerms.lesser_fullness_of_grain): 1,
    (1902, SolarTerms.grain_in_beard): 1,
    (1928, SolarTerms.the_summer_solstice): 1,
    (1925, SolarTerms.lesser_heat): 1,
    (2016, SolarTerms.lesser_heat): 1,
    (1922, SolarTerms.greater_heat): 1,
    (2002, SolarTerms.the_beginning_of_autumn): 1,
    (1927, SolarTerms.white_dew): 1,
    (1942, SolarTerms.the_autumn_equinox): 1,
    (2089, SolarTerms.frost_descent): 1,
    (2089, SolarTerms.the_beginning_of_winter): 1,
    (1978, SolarTerms.lesser_snow): 1,
    (1954, SolarTerms.greater_snow): 1,
    (1918, SolarTerms.the_winter_solstice): -1,
    (2021, SolarTerms.the_winter_solstice): -1,
    (1982, SolarTerms.lesser_cold): 1,
    (2019, SolarTerms.lesser_cold): -1,
    (2000, SolarTerms.greater_cold): 1,
    (2082, SolarTerms.greater_cold): 1,
}


from intrinsic_types import intrinsic_types, is_float
from bitstring import Bits, BitArray
import random
from tempfile import NamedTemporaryFile
import os
import subprocess
from interp import interpret
from compiler import compile
from bit_util import *
import math
import z3
import functools
import operator
from spec_serializer import dump_spec, load_spec

src_path = os.path.dirname(os.path.abspath(__file__))

def get_imm_mask(imm8, outs):
  '''
  Given imm8 and the semantic of the outputs,
  figure out a mask that identifies the bits of imm8
  that are actually useful
  '''
  # TODO: don't assume there is only one output
  y = outs[0]
  mask = (1 << 33)-1
  s = z3.Solver()
  for i in range(33, 0, -1):
    cur_mask = (1<<(i+1))-1
    y_masked = z3.substitute(y, (imm8, imm8 & cur_mask))
    ok = z3.is_true(z3.simplify(y_masked == y))

    if not ok:
      return mask
    mask = cur_mask
  return mask

def extract_float(bv, i, bitwidth):
  '''
  extract i'th float from bv

  bitwidth is the size of a one floating point (either 32 or 64)
  '''
  if bitwidth == 32:
    ty = z3.Float32()
  else:
    assert bitwidth == 64
    ty = z3.Float64()
  sub_bv = z3.Extract(i * bitwidth + bitwidth - 1, i * bitwidth, bv)
  return z3.fpBVToFP(sub_bv, ty)

def equal(a, b, ty):
  if is_float(ty):
    if ty.is_float:
      elem_bw = 32
    else:
      elem_bw = 64
    assert ty.bitwidth % elem_bw == 0
    num_elems = ty.bitwidth // elem_bw
    return z3.Or(a == b, z3.And([
        z3.fpAbs(extract_float(a, i, elem_bw) - extract_float(b, i, elem_bw)) < 1e-5
        for i in range(num_elems)]))
  return a == b

def check_compiled_spec_with_examples(param_vals, outs, out_types, inputs, expected_outs):
  s = z3.Solver()
  s.set(timeout=20000)
  constraints = []
  for input, expected in zip(inputs, expected_outs):
    subs = [(param, z3.BitVecVal(x, param.size())) for param, x in zip(param_vals, input)]
    outs_concrete = [z3.simplify(z3.substitute(out, *subs))
        for out in outs]
    constraints.append(
        z3.And([equal(z3.BitVecVal(y_expected, y.size()), y, out_type)
          for y_expected, y, out_type in zip(expected, outs_concrete, out_types)]))
    #preconditions = [x_sym == x_conc
    #for x_sym, x_conc in zip(param_vals, input)]
    #postconditions = [equal(z3.BitVecVal(y_expected, y.size()), y, out_type)
    #    for y_expected, y, out_type in zip(expected, outs, out_types)]
    #constraints.append(
    #    z3.Implies(z3.And(preconditions), z3.And(postconditions)))
  spec_correct = z3.And(constraints)
  s.add(z3.Not(spec_correct))
  correct = s.check() == z3.unsat
  #if not correct:
  #  print(s.model().evaluate(outs[0]), expected_outs[0][0])
  return correct

def line_to_bitvec(line, ty):
  qwords = list(map(int, line.split()))
  if ty.bitwidth <= 64:
    assert len(qwords) == 1
    [bits] = qwords
    mask = (1 << ty.bitwidth) - 1
    return bits & mask

  assert ty.bitwidth % 64 == 0
  components = [bits << (i * 64) for i, bits in enumerate(qwords)]
  return functools.reduce(operator.or_, components, 0)

load_intrinsics = {
    '_m512i': '_mm512_loadu_si512',
    '__m512i': '_mm512_loadu_si512',
    '__m256i': '_mm256_loadu_si256',
    '__m128i': '_mm_loadu_si128',

    # single precision floats
    '__m512': '_mm512_loadu_ps',
    '__m256': '_mm256_loadu_ps',
    '__m128': '_mm_loadu_ps',
    '_m512': '_mm512_loadu_ps',
    '_m256': '_mm256_loadu_ps',
    '_m128': '_mm_loadu_ps',

    # double precision floats
    '__m512d': '_mm512_loadu_pd',
    '__m256d': '_mm256_loadu_pd',
    '__m128d': '_mm_loadu_pd',
    '_m512d': '_mm512_loadu_pd',
    '_m256d': '_mm256_loadu_pd',
    '_m128d': '_mm_loadu_pd',
    }

# functions that prints these vector registers
printers = {
    '_m512i': 'print__m512i',
    '__m512i': 'print__m512i',
    '__m256i': 'print__m256i',
    '__m128i': 'print__m128i',

    # single precision floats
    '__m512': 'print__m512i',
    '__m256': 'print__m256i',
    '__m128': 'print__m128i',
    '_m512': 'print__m512i',
    '_m256': 'print__m256i',
    '_m128': 'print__m128i',

    # double precision floats
    '__m512d': 'print__m512i',
    '__m256d': 'print__m256i',
    '__m128d': 'print__m128i',
    '_m512d': 'print__m512i',
    '_m256d': 'print__m256i',
    '_m128d': 'print__m128i',
    }

def emit_load(outf, dst, src, typename):
  if typename in load_intrinsics:
    load_intrinsic = load_intrinsics[typename]
    outf.write('%s %s = %s((%s *)%s);\n' % (
      typename, dst, load_intrinsic, typename, src
      ))
  else:
    outf.write('%s %s = *(%s *)(%s);\n' % (
      typename, dst, typename, src
      ))

def gen_rand_data(outf, name, typename):
  '''
  declare a variable of `data_type` called `name`

  print result to `outf` and return the actual bytes in bits

  e.g. for ty=__m512i, name = x1, we declare the following

  unsigned char x1[64] = { ... };
  '''

  if typename.endswith('*'):
    is_pointer = True
    typename = typename[:-1].strip()
  else:
    is_pointer = False

  ty = intrinsic_types[typename]

  # generate floats separates for integer because we don't
  #  want to deal with underflow and other floating point issues
  if not is_float(ty):
    num_bytes = ty.bitwidth // 8
    bytes = [random.randint(0, 255) for _ in range(num_bytes)]
    outf.write('unsigned char %s_aux[%d] = { %s };\n' % (
      name, num_bytes, ','.join(map(str, bytes))
      ))
    bits = BitArray(length=ty.bitwidth)
    for i, byte in enumerate(bytes):
      update_bits(bits, i*8, i*8+8, byte)
  else:
    float_size = 32 if ty.is_float else 64
    c_type = 'float' if ty.is_float else 'double'
    num_floats = ty.bitwidth // float_size
    floats = [random.random() for _ in range(num_floats)]
    outf.write('%s %s_aux[%d] = { %s };\n' % (
      c_type, name, num_floats, ','.join(map(str, floats))
      ))
    bits = float_vec_to_bits(floats, float_size=float_size)

  if not is_pointer:
    # in this case we need to load the bytes
    emit_load(outf, src='%s_aux'%name, dst=name, typename=typename)
  else:
    # in this case we just take the address
    outf.write('%s *%s = (%s *)(&%s_aux);\n' % (
        typename, name, typename, name
      ))

  return bits

def emit_print(outf, var, typename):
  if typename.endswith('*'):
    typename = typename[:-1].strip()
    ty = intrinsic_types[typename]
    is_pointer = True
  else:
    is_pointer = False
    ty = intrinsic_types[typename]

  if is_pointer:
    # need to load the value first first
    tmp = get_temp_name()
    emit_load(outf, dst=tmp, src=var, typename=typename)
    var = tmp

  if typename in printers:
    # use the predefined printers
    printer = printers[typename]
    if ty.is_float:
      param_ty = 'unsigned long'
    elif ty.is_double:
      param_ty = 'unsigned long'
    else:
      param_ty = 'unsigned long'

    outf.write('%s((%s *)&%s);\n' % (printer, param_ty, var))
  else:
    if ty.is_float:
      outf.write('printf("%%u\\n", float2int(%s));\n' % var)
    elif ty.is_double:
      outf.write('printf("%%lu\\n", double2long(%s));\n' % var)
    else:
      outf.write('printf("%%lu\\n", (unsigned long)%s);\n' % var)

counter = 0
def get_temp_name():
  global counter
  counter += 1
  return 'tmp%d' % counter

def fuzz_intrinsic_once(outf, spec, sema):
  '''
  1) generate test (in C) that exercises the intrinsic
  2) run the interpreter per the spec and return the expected output
  '''
  xs, ys = sema

  # generate random arguments
  c_vars = []
  arg_vals = []
  out_params = []
  out_param_types = []
  inst_form = spec.inst_form.split(', ')
  no_imm8 = 'imm8' not in (param.name for param in spec.params)
  # TODO: refactor out this signature parsing logic
  for i, param in enumerate(spec.params):
    if ((no_imm8 and i < len(inst_form) and inst_form[i] == 'imm') or
        param.name == 'imm8'):
      param_id = len(arg_vals)
      mask = get_imm_mask(xs[param_id], ys)
      byte = random.randint(0, 255) & mask
      c_vars.append(str(byte))
      arg_vals.append(Bits(uint=byte, length=8))
      continue
    c_var = get_temp_name()
    arg_val = gen_rand_data(outf, c_var, param.type)
    c_vars.append(c_var)
    arg_vals.append(arg_val)
    if param.type.endswith('*'):
      out_params.append(c_var)
      out_param_types.append(param.type[:-1].strip())

  # call the intrinsic
  has_return_val = spec.rettype != 'void'
  if has_return_val:
    ret_var = get_temp_name()
    outf.write('%s %s = %s(%s);\n' % (
      spec.rettype, ret_var, spec.intrin, ','.join(c_vars)
      ))
    # print the result
    emit_print(outf, ret_var, spec.rettype)
  else:
    outf.write('%s(%s);\n' % (
      spec.intrin, ','.join(c_vars)
      ))

  out_types = []

  for param, param_type in zip(out_params, out_param_types):
    emit_print(outf, param, param_type+'*')

  return arg_vals, out_param_types, has_return_val

def get_err(a, b, is_float):
  err = a - b
  if not is_float:
    return err
  if math.isnan(a) and math.isnan(b):
    return 0
  return err

def identical_vecs(a, b, is_float):
  errs = [get_err(aa, bb, is_float)
      for aa,bb in zip(a, b)]
  if is_float:
    return all(abs(err) <= 1e-6 for err in errs)
  return all(err == 0 for err in errs)

def bits_to_vec(bits, typename):
  if typename.endswith('*'):
    ty = intrinsic_types[typename[:-1]]
  else:
    ty = intrinsic_types[typename]
  if ty.is_float:
    return bits_to_float_vec(bits, float_size=32)
  elif ty.is_double:
    return bits_to_float_vec(bits, float_size=64)

  # integer type
  return bits_to_long_vec(bits)

def fuzz_intrinsic(spec, num_tests=100):
  '''
  spec -> (spec correct, can compile)
  '''
  param_vals, outs = compile(spec)
  sema = param_vals, outs
  interpreted = []
  exe = NamedTemporaryFile(delete=False)
  exe.close()
  with NamedTemporaryFile(suffix='.c', mode='w') as outf:
    outf.write('''
#include <emmintrin.h>
#include <immintrin.h>
#include <nmmintrin.h>
#include <pmmintrin.h>
#include <smmintrin.h>
#include <tmmintrin.h>
#include <wmmintrin.h>
#include <xmmintrin.h>

#include <stdio.h>
#include "printers.h"

#define __int64_t __int64
#define __int64 long long

union float_and_int {
  float f;
  unsigned int i;
};

union double_and_long {
  double d;
  unsigned long l;
};

unsigned int float2int(float f) {
  union float_and_int x;
  x.f = f;
  return x.i;
}

unsigned long double2long(double d) {
  union double_and_long x;
  x.d = d;
  return x.l;
}

int main() {
        ''')

    x = []
    y = []
    for _ in range(num_tests):
      arg_vals, out_param_types, has_return_val = fuzz_intrinsic_once(outf, spec, sema)
      out_types = [intrinsic_types[ty] for ty in out_param_types]
      if spec.rettype != 'void':
        out_types = [intrinsic_types[spec.rettype]] + out_types
      x.append([val.uint for val in arg_vals])

    outf.write('''
  return 0;
}
      ''')
    outf.flush()

    os.system('cp %s %s' % (outf.name, 'debug.c'))

    # TODO: add CPUIDs
    try:
      subprocess.check_output(
          'clang %s -o %s -I%s %s/printers.o >/dev/null 2>/dev/null -mavx -mavx2 -march=native -mfma' % (
            outf.name, exe.name, src_path, src_path),
          shell=True)
    except subprocess.CalledProcessError:
      return False, False

    num_outputs_per_intrinsic = len(out_types)

    stdout = subprocess.check_output([exe.name])
    lines = stdout.decode('utf-8').strip().split('\n')
    assert(len(lines) == num_tests * num_outputs_per_intrinsic)

  os.system('rm '+exe.name)

  for i in range(0, len(lines), num_outputs_per_intrinsic):
    outputs = []
    for ty, line in zip(out_types, lines[i:i+num_outputs_per_intrinsic]):
      outputs.append(line_to_bitvec(line, ty))
    y.append(outputs)

  correct = check_compiled_spec_with_examples(param_vals, outs, out_types, x, y)
  return correct, True

if __name__ == '__main__':
  import sys
  import xml.etree.ElementTree as ET
  from manual_parser import get_spec_from_xml
  from intrinsic_types import IntegerType

  sema = '''
<intrinsic tech="Other" rettype='unsigned int' name='_bextr_u32'>
	<type>Integer</type>
	<CPUID>BMI1</CPUID>
	<category>Bit Manipulation</category>
	<parameter type='unsigned int' varname='a' />
	<parameter type='unsigned int' varname='start' />
	<parameter type='unsigned int' varname='len' />
	<description>Extract contiguous bits from unsigned 32-bit integer "a", and store the result in "dst". Extract the number of bits specified by "len", starting at the bit specified by "start".</description>
	<operation>
tmp := ZeroExtend_To_512(a)
dst := ZeroExtend(tmp[start[7:0]+len[7:0]-1:start[7:0]])
	</operation>
	<instruction name='bextr' form='r32, r32, r32'/>
	<header>immintrin.h</header>
</intrinsic>
  '''
  intrin_node = ET.fromstring(sema)
  spec = get_spec_from_xml(intrin_node)
  ok = fuzz_intrinsic(spec, num_tests=32)
  print(ok)


#!/usr/bin/python3

import sys
import pyvips

im = pyvips.Image.new_from_file(sys.argv[1], access="sequential")

text = pyvips.Image.text(f"{sys.argv[3]}",
                         width=500,
                         dpi=100,
                         align="centre",
                         rgba=True)

# scale the alpha down to make the text semi-transparent
text = (text * [1, 1, 1, 0.3]).cast("uchar")

text = text.rotate(45)

# tile to the size of the image page, then tile again to the full image size
text = text.embed(10, 10, text.width + 20, text.width + 20)
page_height = im.get_page_height()
text = text.replicate(1 + im.width / text.width, 1 + page_height / text.height)
text = text.crop(0, 0, im.width, page_height)
text = text.replicate(1, 1 + im.height / text.height)
text = text.crop(0, 0, im.width, im.height)

# composite the two layers
im = im.composite(text, "over")

im.write_to_file(sys.argv[2])


from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(899, 563)
        MainWindow.setMinimumSize(QtCore.QSize(700, 480))
        MainWindow.setStyleSheet("*{\n"
"background:#18162A;\n"
"border:none;\n"
"color:white;\n"
"}")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
        self.centralwidget.setSizePolicy(sizePolicy)
        self.centralwidget.setObjectName("centralwidget")
        self.hboxlayout = QtWidgets.QHBoxLayout(self.centralwidget)
        self.hboxlayout.setContentsMargins(0, 0, 0, 0)
        self.hboxlayout.setSpacing(0)
        self.hboxlayout.setObjectName("hboxlayout")
        self.leftMenu = QtWidgets.QFrame(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.leftMenu.sizePolicy().hasHeightForWidth())
        self.leftMenu.setSizePolicy(sizePolicy)
        self.leftMenu.setMinimumSize(QtCore.QSize(200, 0))
        self.leftMenu.setMaximumSize(QtCore.QSize(0, 16777215))
        self.leftMenu.setStyleSheet("background:#060117; border:none;")
        self.leftMenu.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.leftMenu.setFrameShadow(QtWidgets.QFrame.Raised)
        self.leftMenu.setLineWidth(0)
        self.leftMenu.setObjectName("leftMenu")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.leftMenu)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setSpacing(0)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.frame_4 = QtWidgets.QFrame(self.leftMenu)
        self.frame_4.setMinimumSize(QtCore.QSize(0, 50))
        self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_4.setObjectName("frame_4")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_4)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.dvsoft = QtWidgets.QPushButton(self.frame_4)
        self.dvsoft.setText("DVsoft")
        self.dvsoft.setObjectName("pushButton_9")
        self.dvsoft.setStyleSheet("font-size:32px;")
        self.verticalLayout_3.addWidget(self.dvsoft, 0, QtCore.Qt.AlignLeft)
        self.verticalLayout_2.addWidget(self.frame_4, 0, QtCore.Qt.AlignTop)
        self.frame_5 = QtWidgets.QFrame(self.leftMenu)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.frame_5.sizePolicy().hasHeightForWidth())
        self.frame_5.setSizePolicy(sizePolicy)
        self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_5.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_5.setObjectName("frame_5")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_5)
        self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_4.setSpacing(0)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.Menu2 = QtWidgets.QToolBox(self.frame_5)
        self.Menu2.setStyleSheet("QToolBox{\n"
"    background-color:rgb(24,24,36);\n"
"    text-align:left;\n"
"    font-size:20px;\n"
"    color:white;\n"
"}\n"
"QToolBox::tab{\n"
"    border-radius:5px;\n"
"    background-color:rgb(17,16,26);\n"
"    text-align:left;\n"
"    font-size:20px;\n"
"    color:white;\n"
"}")
        self.Menu2.setObjectName("Menu2")
        self.Menu1 = QtWidgets.QWidget()
        self.Menu1.setGeometry(QtCore.QRect(0, 0, 200, 357))
        self.Menu1.setStyleSheet("")
        self.Menu1.setObjectName("Menu1")
        self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.Menu1)
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.frame_7 = QtWidgets.QFrame(self.Menu1)
        self.frame_7.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_7.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_7.setObjectName("frame_7")
        self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.frame_7)
        self.verticalLayout_6.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_6.setSpacing(10)
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.pushButton = QtWidgets.QPushButton(self.frame_7)
        self.pushButton.setStyleSheet("font-size:20px")
        self.pushButton.setObjectName("pushButton")
        self.verticalLayout_6.addWidget(self.pushButton)
        self.pushButton_2 = QtWidgets.QPushButton(self.frame_7)
        self.pushButton_2.setStyleSheet("font-size:20px")
        self.pushButton_2.setObjectName("pushButton_2")
        self.verticalLayout_6.addWidget(self.pushButton_2)
        self.pushButton_3 = QtWidgets.QPushButton(self.frame_7)
        self.pushButton_3.setStyleSheet("font-size:20px")
        self.pushButton_3.setObjectName("pushButton_3")
        self.verticalLayout_6.addWidget(self.pushButton_3)
        self.verticalLayout_5.addWidget(self.frame_7, 0, QtCore.Qt.AlignTop)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("icons/strelka3.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.Menu2.addItem(self.Menu1, icon, "")
        self.menu2 = QtWidgets.QWidget()
        self.menu2.setGeometry(QtCore.QRect(0, 0, 200, 357))
        self.menu2.setObjectName("menu2")
        self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.menu2)
        self.verticalLayout_7.setObjectName("verticalLayout_7")
        self.frame_8 = QtWidgets.QFrame(self.menu2)
        self.frame_8.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_8.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_8.setObjectName("frame_8")
        self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.frame_8)
        self.verticalLayout_8.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_8.setSpacing(15)
        self.verticalLayout_8.setObjectName("verticalLayout_8")
        self.pushButton_4 = QtWidgets.QPushButton(self.frame_8)
        self.pushButton_4.setStyleSheet("font-size:20px;")
        self.pushButton_4.setObjectName("pushButton_4")
        self.verticalLayout_8.addWidget(self.pushButton_4)
        self.pushButton_5 = QtWidgets.QPushButton(self.frame_8)
        self.pushButton_5.setStyleSheet("font-size:20px")
        self.pushButton_5.setObjectName("pushButton_5")
        self.verticalLayout_8.addWidget(self.pushButton_5)
        self.label_2 = QtWidgets.QLabel(self.frame_8)
        self.label_2.setStyleSheet("font-size:20px;")
        self.label_2.setWordWrap(True)
        self.label_2.setObjectName("label_2")
        self.verticalLayout_8.addWidget(self.label_2)
        self.verticalLayout_7.addWidget(self.frame_8)
        self.Menu2.addItem(self.menu2, icon, "")
        self.verticalLayout_4.addWidget(self.Menu2)
        self.verticalLayout_2.addWidget(self.frame_5)
        self.frame_6 = QtWidgets.QFrame(self.leftMenu)
        self.frame_6.setMinimumSize(QtCore.QSize(0, 50))
        self.frame_6.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_6.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_6.setObjectName("frame_6")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.frame_6)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.exit = QtWidgets.QPushButton(self.frame_6)
        self.exit.setStyleSheet("font-size:20px;")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("icons/выход.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.exit.setIcon(icon1)
        self.exit.setObjectName("pushButton_12")
        self.horizontalLayout_8.addWidget(self.exit, 0, QtCore.Qt.AlignLeft)
        self.verticalLayout_2.addWidget(self.frame_6)
        self.hboxlayout.addWidget(self.leftMenu)
        self.MainFrame = QtWidgets.QFrame(self.centralwidget)
        self.MainFrame.setStyleSheet("border:none;")
        self.MainFrame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.MainFrame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.MainFrame.setObjectName("MainFrame")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.MainFrame)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.header = QtWidgets.QFrame(self.MainFrame)
        self.header.setMinimumSize(QtCore.QSize(0, 50))
        self.header.setStyleSheet("background:#060117; border:none;")
        self.header.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.header.setFrameShadow(QtWidgets.QFrame.Raised)
        self.header.setLineWidth(0)
        self.header.setObjectName("header")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.header)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.frame = QtWidgets.QFrame(self.header)
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setSpacing(0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.menuTurn = QtWidgets.QPushButton(self.frame)
        self.menuTurn.setText("")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("icons/свернуть бар.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.menuTurn.setIcon(icon2)
        self.menuTurn.setIconSize(QtCore.QSize(32, 32))
        self.menuTurn.setObjectName("pushButton_11")
        self.horizontalLayout.addWidget(self.menuTurn)
        self.lineEdit = QtWidgets.QLineEdit(self.frame)
        self.lineEdit.setStyleSheet("border-bottom:2px solid #19E67E;\n"
"font-size:24px;")
        self.lineEdit.setObjectName("lineEdit")
        self.horizontalLayout.addWidget(self.lineEdit)
        self.pushButton_10 = QtWidgets.QPushButton(self.frame)
        self.pushButton_10.setText("")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap("icons/search.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_10.setIcon(icon3)
        self.pushButton_10.setIconSize(QtCore.QSize(32, 32))
        self.pushButton_10.setObjectName("pushButton_10")
        self.horizontalLayout.addWidget(self.pushButton_10)
        self.horizontalLayout_2.addWidget(self.frame, 0, QtCore.Qt.AlignLeft)
        self.frame_2 = QtWidgets.QFrame(self.header)
        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_2.setObjectName("frame_2")
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame_2)
        self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_4.setSpacing(0)
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.username = QtWidgets.QPushButton(self.frame_2)
        self.username.setText("USERNAME")
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("icons/пользователь.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.username.setIcon(icon4)
        self.username.setIconSize(QtCore.QSize(32, 32))
        self.username.setObjectName("pushButton_9")
        self.username.setStyleSheet("font-size:24px;")
        self.horizontalLayout_4.addWidget(self.username, 0, QtCore.Qt.AlignLeft)
        self.horizontalLayout_2.addWidget(self.frame_2, 0, QtCore.Qt.AlignHCenter)
        self.frame_3 = QtWidgets.QFrame(self.header)
        self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_3.setObjectName("frame_3")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frame_3)
        self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_3.setSpacing(0)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.turn = QtWidgets.QPushButton(self.frame_3)
        self.turn.setText("")
        icon5 = QtGui.QIcon()
        icon5.addPixmap(QtGui.QPixmap("icons/свернуть.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.turn.setIcon(icon5)
        self.turn.setIconSize(QtCore.QSize(45, 45))
        self.turn.setObjectName("pushButton_6")
        self.horizontalLayout_3.addWidget(self.turn)
        self.expand = QtWidgets.QPushButton(self.frame_3)
        self.expand.setText("")
        icon6 = QtGui.QIcon()
        icon6.addPixmap(QtGui.QPixmap("icons/двойная диагональная стрелка.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.expand.setIcon(icon6)
        self.expand.setIconSize(QtCore.QSize(30, 40))
        self.expand.setObjectName("pushButton_7")
        self.horizontalLayout_3.addWidget(self.expand)
        self.close = QtWidgets.QPushButton(self.frame_3)
        self.close.setText("")
        icon7 = QtGui.QIcon()
        icon7.addPixmap(QtGui.QPixmap("icons/x.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.close.setIcon(icon7)
        self.close.setIconSize(QtCore.QSize(40, 40))
        self.close.setObjectName("pushButton_8")
        self.horizontalLayout_3.addWidget(self.close)
        self.horizontalLayout_2.addWidget(self.frame_3, 0, QtCore.Qt.AlignRight)
        self.verticalLayout.addWidget(self.header)
        self.main = QtWidgets.QFrame(self.MainFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.main.sizePolicy().hasHeightForWidth())
        self.main.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setStyleStrategy(QtGui.QFont.PreferDefault)
        self.main.setFont(font)
        self.main.setAutoFillBackground(False)
        self.main.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.main.setFrameShadow(QtWidgets.QFrame.Raised)
        self.main.setObjectName("main")
        self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.main)
        self.verticalLayout_9.setObjectName("verticalLayout_9")
        self.label_5 = QtWidgets.QLabel(self.main)
        self.label_5.setStyleSheet("border:10px solid #19E67E;\n"
"border-radius:90px;\n"
"padding: 15px")
        self.label_5.setText("")
        self.label_5.setPixmap(QtGui.QPixmap("icons/логотип.svg"))
        self.label_5.setObjectName("label_5")
        self.verticalLayout_9.addWidget(self.label_5, 0, QtCore.Qt.AlignHCenter|QtCore.Qt.AlignBottom)
        self.label_6 = QtWidgets.QLabel(self.main)
        self.label_6.setStyleSheet("font-size:50px;")
        self.label_6.setObjectName("label_6")
        self.verticalLayout_9.addWidget(self.label_6, 0, QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
        self.verticalLayout.addWidget(self.main)
        self.footer = QtWidgets.QFrame(self.MainFrame)
        self.footer.setMinimumSize(QtCore.QSize(50, 50))
        self.footer.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.footer.setFrameShadow(QtWidgets.QFrame.Raised)
        self.footer.setObjectName("footer")
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.footer)
        self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_5.setSpacing(0)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.frame_10 = QtWidgets.QFrame(self.footer)
        self.frame_10.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_10.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_10.setObjectName("frame_10")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.frame_10)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.label_4 = QtWidgets.QLabel(self.frame_10)
        self.label_4.setStyleSheet("font-size:14px;\n"
"")
        self.label_4.setObjectName("label_4")
        self.horizontalLayout_6.addWidget(self.label_4, 0, QtCore.Qt.AlignLeft|QtCore.Qt.AlignBottom)
        self.horizontalLayout_5.addWidget(self.frame_10, 0, QtCore.Qt.AlignLeft)
        self.frame_9 = QtWidgets.QFrame(self.footer)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.frame_9.sizePolicy().hasHeightForWidth())
        self.frame_9.setSizePolicy(sizePolicy)
        self.frame_9.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_9.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_9.setObjectName("frame_9")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.frame_9)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.horizontalLayout_5.addWidget(self.frame_9)
        self.verticalLayout.addWidget(self.footer)
        self.hboxlayout.addWidget(self.MainFrame)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        self.Menu2.setCurrentIndex(1)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.dvsoft.setText(_translate("MainWindow", "DVsoft"))
        self.pushButton.setText(_translate("MainWindow", "Item1"))
        self.pushButton_2.setText(_translate("MainWindow", "Item2"))
        self.pushButton_3.setText(_translate("MainWindow", "Item3"))
        self.Menu2.setItemText(self.Menu2.indexOf(self.Menu1), _translate("MainWindow", "Menu1"))
        self.pushButton_4.setText(_translate("MainWindow", "Weather"))
        self.pushButton_5.setText(_translate("MainWindow", "Course Dollar/Euro"))
        self.label_2.setText(_translate("MainWindow", "Больше информации вы можете прочеcть на нашем сайте, который ещё не готов :)"))
        self.Menu2.setItemText(self.Menu2.indexOf(self.menu2), _translate("MainWindow", "Menu2"))
        self.exit.setText(_translate("MainWindow", "Exit"))
        self.lineEdit.setText(_translate("MainWindow", "Search"))
        self.label_6.setText(_translate("MainWindow", "DVsoft"))
        self.label_4.setText(_translate("MainWindow", "DVsoft.project.1"))
import icons_rc