import numpy as np
import cv2
from PyQt5 import QtCore, QtWidgets
import matplotlib.pyplot as plt
from scipy import signal
from PIL import Image

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(1048, 842)
        self.textEdit = QtWidgets.QTextEdit(Form)
        self.textEdit.setGeometry(QtCore.QRect(60, 50, 951, 741))
        self.textEdit.setObjectName("textEdit")
        self.textEdit_2 = QtWidgets.QTextEdit(Form)
        self.textEdit_2.setGeometry(QtCore.QRect(100, 80, 191, 631))
        self.textEdit_2.setObjectName("textEdit_2")
        self.textEdit_3 = QtWidgets.QTextEdit(Form)
        self.textEdit_3.setGeometry(QtCore.QRect(320, 80, 191, 631))
        self.textEdit_3.setObjectName("textEdit_3")
        self.textEdit_4 = QtWidgets.QTextEdit(Form)
        self.textEdit_4.setGeometry(QtCore.QRect(540, 80, 191, 631))
        self.textEdit_4.setObjectName("textEdit_4")
        self.textEdit_5 = QtWidgets.QTextEdit(Form)
        self.textEdit_5.setGeometry(QtCore.QRect(760, 80, 191, 631))
        self.textEdit_5.setObjectName("textEdit_5")
        self.one_one = QtWidgets.QPushButton(Form)
        self.one_one.setGeometry(QtCore.QRect(120, 150, 161, 81))
        self.one_one.setObjectName("one_one")
        self.one_one.clicked.connect(one_one_clicked) #1-3

        self.one_two = QtWidgets.QPushButton(Form)
        self.one_two.setGeometry(QtCore.QRect(120, 280, 161, 81))
        self.one_two.setObjectName("one_two")
        self.one_two.clicked.connect(one_two_clicked) #1-2

        self.one_three = QtWidgets.QPushButton(Form)
        self.one_three.setGeometry(QtCore.QRect(120, 410, 161, 81))
        self.one_three.setObjectName("one_three")
        self.one_three.clicked.connect(one_three_clicked) #1-3

        self.one_four = QtWidgets.QPushButton(Form)
        self.one_four.setGeometry(QtCore.QRect(110, 570, 161, 81))
        self.one_four.setObjectName("one_four")
        self.one_four.clicked.connect(one_four_clicked) #1-4

        self.two_one = QtWidgets.QPushButton(Form)
        self.two_one.setGeometry(QtCore.QRect(330, 180, 161, 81))
        self.two_one.setObjectName("two_one")
        self.two_one.clicked.connect(two_one_clicked) #2-1

        self.two_two = QtWidgets.QPushButton(Form)
        self.two_two.setGeometry(QtCore.QRect(330, 310, 161, 81))
        self.two_two.setObjectName("two_two")
        self.two_two.clicked.connect(two_two_clicked) #2-2

        self.two_three = QtWidgets.QPushButton(Form)
        self.two_three.setGeometry(QtCore.QRect(330, 440, 161, 81))
        self.two_three.setObjectName("two_three")
        self.two_three.clicked.connect(two_three_clicked) #2-3

        self.three_one = QtWidgets.QPushButton(Form)
        self.three_one.setGeometry(QtCore.QRect(550, 150, 161, 81))
        self.three_one.setObjectName("three_one")
        self.three_one.clicked.connect(three_one_clicked) #3-1

        self.three_two = QtWidgets.QPushButton(Form)
        self.three_two.setGeometry(QtCore.QRect(550, 290, 161, 81))
        self.three_two.setObjectName("three_two")
        self.three_two.clicked.connect(three_two_clicked) #3-2

        self.three_three = QtWidgets.QPushButton(Form)
        self.three_three.setGeometry(QtCore.QRect(550, 400, 161, 81))
        self.three_three.setObjectName("three_three")
        self.three_three.clicked.connect(three_three_clicked) #3-3

        self.three_four = QtWidgets.QPushButton(Form)
        self.three_four.setGeometry(QtCore.QRect(550, 530, 161, 81))
        self.three_four.setObjectName("three_four")
        self.three_four.clicked.connect(three_four_clicked) #3-4

        self.four_one = QtWidgets.QPushButton(Form)
        self.four_one.setGeometry(QtCore.QRect(770, 150, 161, 81))
        self.four_one.setObjectName("four_one")
        self.four_one.clicked.connect(four_one_clicked) #4-1

        self.four_two = QtWidgets.QPushButton(Form)
        self.four_two.setGeometry(QtCore.QRect(770, 270, 161, 81))
        self.four_two.setObjectName("four_two")
        self.four_two.clicked.connect(four_two_clicked) #4-2

        self.four_three = QtWidgets.QPushButton(Form)
        self.four_three.setGeometry(QtCore.QRect(780, 400, 161, 81))
        self.four_three.setObjectName("four_three")
        self.four_three.clicked.connect(four_three_clicked) #4-3

        self.four_four = QtWidgets.QPushButton(Form)
        self.four_four.setGeometry(QtCore.QRect(780, 520, 161, 81))
        self.four_four.setObjectName("four_four")
        self.four_four.clicked.connect(four_four_clicked) #4-4

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.textEdit_2.setHtml(_translate("Form", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<meta name=\"qrichtext\" content=\"1\" />\n"
"
1.Image Processing
"))
        self.textEdit_3.setHtml(_translate("Form", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<meta name=\"qrichtext\" content=\"1\" />\n"
"
2.Image Smoothing
\n"
"

"))
        self.textEdit_4.setHtml(_translate("Form", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<meta name=\"qrichtext\" content=\"1\" />\n"
"
3.Edge Detection
\n"
"

"))
        self.textEdit_5.setHtml(_translate("Form", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<meta name=\"qrichtext\" content=\"1\" />\n"
"
4.Transforms
\n"
"

"))
        self.one_one.setText(_translate("Form", "1.1Load Image File"))
        self.one_two.setText(_translate("Form", "1.2 Color Separation"))
        self.one_three.setText(_translate("Form", "1.3Color Transformation"))
        self.one_four.setText(_translate("Form", "1.4 Blending"))
        self.two_one.setText(_translate("Form", "2.1 Gaussian blur"))
        self.two_two.setText(_translate("Form", "2.2 Bilaterial filter"))
        self.two_three.setText(_translate("Form", "2.3 Median filter"))
        self.three_one.setText(_translate("Form", "3.1 Gaussian blur"))
        self.three_two.setText(_translate("Form", "3.2 Sobel X"))
        self.three_three.setText(_translate("Form", "3.3 Sobel Y"))
        self.three_four.setText(_translate("Form", "3.4 Magnitude"))
        self.four_one.setText(_translate("Form", "4.1 Resize"))
        self.four_two.setText(_translate("Form", "4.2 Translation"))
        self.four_three.setText(_translate("Form", "4.3 Rotation ,Scaling"))
        self.four_four.setText(_translate("Form", "4.4 Sheering"))

def one_one_clicked():
    path = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q1_Image\Sun.jpg"
    img = cv2.imread(path)
    cv2.imshow('good',img)
    if __name__ == '__main__':
        size = img.shape
    print('')
    print('Height : ',size[0])
    print('Width : ',size[1])
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def one_two_clicked():
    path = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q1_Image\Sun.jpg"
    img = cv2.imread(path)
    B,G,R = cv2.split(img);
    zeros = np.zeros(img.shape[:2],dtype="uint8")
    cv2.imshow("BLUE",cv2.merge([B,zeros,zeros]))
    cv2.imshow("GREEN",cv2.merge([zeros,G,zeros]))
    cv2.imshow("RED",cv2.merge([zeros,zeros,R]))
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def one_three_clicked():
    path = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q1_Image\Sun.jpg"
    img = cv2.imread(path)
    image = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY )
    cv2.imshow('OpenCV function', image)
    B,G,R = cv2.split(img)
    ave = (B//3 + G//3 + R//3)
    cv2.imshow('Averaged weighted',ave)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def one_four_clicked():
    left=0.5
    big_dog = r"C:/Users/Windows/Desktop/Hw1/Dataset_OpenCvDl_Hw1/Q1_Image/Dog_Strong.jpg"
    small_dog = r"C:/Users/Windows/Desktop/Hw1/Dataset_OpenCvDl_Hw1/Q1_Image/Dog_Weak.jpg"
    def nothing(x):
        pass
    img1 = cv2.imread(big_dog)
    img2 = cv2.imread(small_dog)
    img = np.zeros((500,500,3), np.uint8)
    cv2.namedWindow('Blend')
    cv2.createTrackbar('blending','Blend',0,255,nothing)
    while(1):
        img=cv2.addWeighted(img1,(1.0-left),img2,left,0)
        cv2.imshow('Blend',img)
        left=cv2.getTrackbarPos('blending','Blend')/255
        if(cv2.waitKey(1) == ord('0')):
            break
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def two_one_clicked():
    hw2=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q2_Image\Lenna_whiteNoise.jpg"
    image = cv2.imread(hw2)
    image1=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image1=np.array(image1)
    after = cv2.GaussianBlur(image1, (5, 5), 0)
    plt.figure()
    plt.suptitle('hw2-1')
    plt.subplot(1,2,1)
    plt.imshow(image1)
    plt.subplot(1,2,2)
    plt.title('Gaussian Blur')
    plt.imshow(after)
    plt.show()
    cv2.waitKey(0)
    cv2.destroyAllWindows

def two_two_clicked():
    hw2=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q2_Image\Lenna_whiteNoise.jpg"
    image = cv2.imread(hw2)
    image1=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image1=np.array(image1)
    after = cv2.bilateralFilter(image1, 9,90,90)
    plt.figure()
    plt.suptitle('hw2-1')
    plt.subplot(1,2,1)
    plt.imshow(image1)
    plt.subplot(1,2,2)
    plt.title('Bilateral Filter')
    plt.imshow(after)
    plt.show()
    cv2.waitKey(0)
    cv2.destroyAllWindows

def two_three_clicked():
    hw2_2=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q2_Image\Lenna_pepperSalt.jpg"
    image = cv2.imread(hw2_2)
    image1=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    image3=cv2.medianBlur(image1,3)
    image5=cv2.medianBlur(image1,5)
    plt.figure()
    plt.suptitle('hw2-3')
    plt.subplot(1,3,1)
    plt.imshow(image1)
    plt.subplot(1,3,2)
    plt.title('Median Filter 3x3')
    plt.imshow(image3)
    plt.subplot(1,3,3)
    plt.title('Median Filter 5x5')
    plt.imshow(image5)
    plt.show()
    cv2.waitKey(0)
    cv2.destroyAllWindows

def three_one_clicked():
    hw3 = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q3_Image\House.jpg"
    image_311 = Image.open(hw3).convert("L")
    image_311 = np.asarray(image_311)
    image_312 = cv2.imread(hw3)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_RGB2BGR)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_BGR2GRAY)
    x, y = np.mgrid[-1:2, -1:2]
    change = np.exp(-(x**2+y**2))
    change = change/change.sum()
    image_32 = signal.convolve2d(image_312, change, boundary='symm', mode='same')
    plt.figure()
    plt.subplot(1,2,1)
    plt.imshow(image_311, cmap='gray', vmin=0, vmax=255)
    plt.subplot(1,2,2)
    plt.imshow(image_32, cmap=plt.get_cmap('gray'))
    plt.show()
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def three_two_clicked():
    hw3 = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q3_Image\House.jpg"
    image_312 = cv2.imread(hw3)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_RGB2BGR)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_BGR2GRAY)
    x, y = np.mgrid[-1:2, -1:2]
    change = np.exp(-(x**2+y**2))
    change = change/change.sum()
    image_312 = signal.convolve2d(image_312, change, boundary='symm', mode='same')
    martix_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
    image_32 = signal.convolve2d(image_312,martix_x, boundary='symm', mode='same')
    plt.figure()
    plt.imshow(np.absolute(image_32),cmap='gray', vmin=0, vmax=255)
    plt.show()

def three_three_clicked():
    hw3 = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q3_Image\House.jpg"
    image_312 = cv2.imread(hw3)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_RGB2BGR)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_BGR2GRAY)
    x, y = np.mgrid[-1:2, -1:2]
    change = np.exp(-(x**2+y**2))
    change = change/change.sum()
    image_312 = signal.convolve2d(image_312, change, boundary='symm', mode='same')
    martix_y = np.array([[1, 2, 1],[0, 0, 0],[-1, -2, -1]])
    image_33 = signal.convolve2d(image_312,martix_y, boundary='symm', mode='same')
    plt.figure()
    plt.imshow(np.absolute(image_33),cmap='gray', vmin=0, vmax=255)
    plt.show()

def three_four_clicked():
    hw3 = r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q3_Image\House.jpg"
    image_312 = cv2.imread(hw3)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_RGB2BGR)
    image_312 = cv2.cvtColor(image_312,cv2.COLOR_BGR2GRAY)
    x, y = np.mgrid[-1:2, -1:2]
    change = np.exp(-(x**2+y**2))
    change = change/change.sum()
    image_312 = signal.convolve2d(image_312, change, boundary='symm', mode='same')
    martix_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
    image_32 = signal.convolve2d(image_312,martix_x, boundary='symm', mode='same')
    martix_y = np.array([[1, 2, 1],[0, 0, 0],[-1, -2, -1]])
    image_33 = signal.convolve2d(image_312,martix_y, boundary='symm', mode='same')
    plt.figure()
    plt.imshow((np.absolute(image_32**2+image_33**2))**0.5,cmap='gray', vmin=0, vmax=255)
    plt.show()

def four_one_clicked():
    hw4=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q4_Image\SQUARE-01.png"
    img_41 = cv2.imread(hw4)
    img_41=cv2.cvtColor(img_41,cv2.COLOR_RGB2BGR)
    img_41 = cv2.resize(img_41,(256,256))
    plt.imshow(img_41)
    plt.show()

def four_two_clicked():
    hw4=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q4_Image\SQUARE-01.png"
    img_41 = cv2.imread(hw4)
    img_41=cv2.cvtColor(img_41,cv2.COLOR_RGB2BGR)
    img_41 = cv2.resize(img_41,(256,256))
    matrix = np.float32([[1,0,0],[0,1,60]])
    img_42 = cv2.warpAffine(img_41, matrix, (400, 300))
    plt.figure()
    plt.suptitle('After translate')
    plt.imshow(img_42)
    plt.show()

def four_three_clicked():
    hw4=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q4_Image\SQUARE-01.png"
    img_41 = cv2.imread(hw4)
    img_41=cv2.cvtColor(img_41,cv2.COLOR_RGB2BGR)
    img_41 = cv2.resize(img_41,(256,256))
    matrix = np.float32([[1,0,0],[0,1,60]])
    img_42 = cv2.warpAffine(img_41, matrix, (400, 300))
    matrix = cv2.getRotationMatrix2D((128,188),10,0.5)
    img_43 = cv2.warpAffine(img_42, matrix, (400,300))
    plt.imshow(img_43)
    plt.show()

def four_four_clicked():
    hw4=r"C:\Users\Windows\Desktop\Hw1\Dataset_OpenCvDl_Hw1\Q4_Image\SQUARE-01.png"
    img_41 = cv2.imread(hw4)
    img_41=cv2.cvtColor(img_41,cv2.COLOR_RGB2BGR)
    img_41 = cv2.resize(img_41,(256,256))
    matrix = np.float32([[1,0,0],[0,1,60]])
    img_42 = cv2.warpAffine(img_41, matrix, (400, 300))
    matrix = cv2.getRotationMatrix2D((128,188),10,0.5)
    img_43 = cv2.warpAffine(img_42, matrix, (400,300))
    pts1 = np.float32([[50,50],[200,50],[50,200]])
    pts2 = np.float32([[10,100],[200,50],[100,250]])
    M = cv2.getAffineTransform(pts1,pts2)
    img_44 = cv2.warpAffine(img_43, M, (400,300))
    plt.imshow(img_44)
    plt.show()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())


import os
import os.path
import urllib.request
import subprocess
from zipfile import ZipFile
import sys
import shutil
from email.utils import formatdate
import argparse

if sys.platform == "win32":
    program_files = os.environ.get("ProgramW6432")
    if program_files is None:
        program_files = os.environ["ProgramFiles"]
    DIFF_PROGRAM = os.path.join(program_files, "git", "usr", "bin", "diff.exe")
else:
    DIFF_PROGRAM = "diff"

jd_wrapper_jd_cli_zip_url = """https://github.com/jd-wrapper/jd-cli/archive/refs/tags/v1.0.0.zip"""

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

def desuffix(s, suffix):
    assert s.endswith(suffix)
    return s[:-len(suffix)]

def web_download_file(url, output_filename):
    urllib.request.urlretrieve(url, output_filename)

def contents(filename):
    with open(filename, "rb") as handle:
        return handle.read()

def write_contents(filename, data):
    with open(filename, "wb") as handle:
        handle.write(data)

def diff_u(first_file, second_file):
    p = subprocess.Popen([DIFF_PROGRAM, "-uw", first_file, second_file])
    # -u produces a diff in unified format
    # -w ignores all whitespace differences

    p.wait()
    return p.returncode

def file_pattern_replace(filename, old, new, new_filename=None):
    if new_filename is None:
        new_filename = filename
    data = contents(filename)
    if old in data:
        write_contents(new_filename, data.replace(old, new))

def gradle_build_dir(code_dir):
    if sys.platform == "win32":
        command_file = "gradlew.bat"
    else:
        command_file = "gradlew"

    subprocess.check_call([os.path.join(code_dir, command_file), "assemble"], cwd=code_dir)

def get_downloaded_file(url, dir):
    filename_proper = url.rsplit("/", 1)[-1]
    filename = os.path.join(dir, filename_proper)
    if not os.path.exists(filename):
        print("Downloading %s to %s" % (url, dir))
        web_download_file(url, filename)
    else:
        print("Using already downloaded %d" % filename_proper)
    return filename

def unzip_file_to_dir(zip_file, dest_dir):
    with ZipFile(zip_file, "r") as zipObj:
        zipObj.extractall(path=dest_dir)

class JavaDecompiler(object):
    def __init__(self):
        self.cli_jar = None

    def setup(self):
        jd_cli_dir = os.path.join(script_path, "jd-cli")
        if not os.path.isdir(jd_cli_dir):
            jd_cli_zip_filename = get_downloaded_file(jd_wrapper_jd_cli_zip_url, script_path)

            unzip_file_to_dir(jd_cli_zip_filename, jd_cli_dir)

        code_dir = os.path.join(jd_cli_dir, "jd-cli-1.0.0")

        gradle_build_dir(code_dir)

        libs_dir = os.path.join(code_dir, "build", "libs")
        libs_files = os.listdir(libs_dir)

        libs_files = [x for x in libs_files if "-min" not in x]

        assert len(libs_files) == 1

        jd_cli_jar = os.path.join(libs_dir, libs_files[0])
        assert jd_cli_jar.endswith(".jar")

        print("using jd core %s" % jd_cli_jar)
        self.cli_jar = jd_cli_jar

    def ensure_file_dir_exists(self, dest_file):
        dest_inner_dir = os.path.dirname(dest_file)
        os.makedirs(dest_inner_dir, exist_ok=True)

    def decompile_jar_to_dir(self, jar_filename, dest_dir, class_pathspec):
        if self.cli_jar is None:
            raise FileNotFoundError("jd core location unknown; run setup() first")

        assert os.path.isfile(jar_filename)

        dest_file_rel = desuffix(class_pathspec, ".class") + ".java"
        dest_file = os.path.join(dest_dir, dest_file_rel)
        self.ensure_file_dir_exists(dest_file)

        # see docs at https://github.com/jd-wrapper/jd-cli
        cli_command_line_options = ["-b", jar_filename, class_pathspec]

        output = subprocess.check_output(["java", "-jar", self.cli_jar] + cli_command_line_options)

        write_contents(dest_file, output)

        return dest_file

class ModifiedJavaProject(object):

    def __init__(self, decompiler, original_jar, decomp_dir, extracted_classpath_dir, additional_src_dir):
        """
        This represents a Java project originally distributed as a JAR that is being used with modified code

        @param original_jar: The unmodified original JAR
        @param decomp_dir: A working directory we will decompile individual original classes to
        @param extracted_classpath_dir: A classpath directory for runs with the modifications, that contains
                                        all original class files from the original JAR that we are using as-is in
                                        the modified version
        @param additional_src_dir: The source directory with the additional source added in the modification,
                                   that we will also add generated source files to
        """

        assert isinstance(decompiler, JavaDecompiler)
        self.decompiler = decompiler
        self.original_jar_filename = original_jar
        self.decomp_dir = decomp_dir
        self.extracted_classpath_dir = extracted_classpath_dir
        self.src_dir = additional_src_dir

    def additional_src_filename(self, class_pathspec):
        return os.path.join(self.src_dir, desuffix(class_pathspec, ".class") + ".java")

    def class_name_proper(self, class_pathspec):
        return desuffix(os.path.basename(class_pathspec), ".class")

    def common_decompile_and_remove_unpatched(self, class_pathspec):
        """
        Decompile the original class from the JAR
        @param class_pathspec: fully qualified class file specifier using forward slash as the separator and ending with ".class"
        @return: the filename of the extracted source file
        """

        class_name = self.class_name_proper(class_pathspec)

        decompiled_code_filename = self.decompiler.decompile_jar_to_dir(self.original_jar_filename, self.decomp_dir, class_pathspec)

        our_version = self.additional_src_filename(class_pathspec)

        # If the class file is still in the extracted version, remove it, since we want to use the one built from the modified source code instead
        extracted_class_file = os.path.join(self.extracted_classpath_dir, class_pathspec)
        if os.path.isfile(extracted_class_file):
            print("deleting " + extracted_class_file)
            os.remove(extracted_class_file)

        return decompiled_code_filename

    def make_constructor_accessible(self, class_pathspec, show_differences):
        """
        Decompile the source for the given class and make the default (class Foo()) constructor accessible
        @param class_pathspec: fully qualified class file specifier using forward slash as the separator and ending with ".class"
        """

        decompiled_code_filename = self.common_decompile_and_remove_unpatched(class_pathspec)

        # Create a version of the extracted file with added constructor

        new_filename = self.additional_src_filename(class_pathspec)

        class_name = self.class_name_proper(class_pathspec)

        orig_class_start_fragment = "public class %s {" % class_name

        orig_class_start_fragment_bytes = orig_class_start_fragment.encode("utf-8")

        orig_contents = contents(decompiled_code_filename)
        assert orig_class_start_fragment_bytes in orig_contents

        private_constructor_start = "private %s() {" % class_name
        has_private_constructor = private_constructor_start.encode("utf-8") in orig_contents
        protected_constructor_start = "protected %s() {" % class_name
        has_protected_constructor = protected_constructor_start.encode("utf-8") in orig_contents
        has_public_constructor = ("public %s() {" % class_name).encode("utf-8") in orig_contents

        if has_protected_constructor or has_public_constructor:
            print("class %s already has an accessible default constructor")
            shutil.copy(decompiled_code_filename, new_filename)
            return

        note = "// protected constructor version generated by %s %s\n" % (sys.argv[0], formatdate())
        print("replacing " + new_filename)

        if has_private_constructor:
            # we need to change the visibility of the existing constructor
            orig_class_start_fragment_bytes = private_constructor_start.encode("utf-8")
            replacement_fragment = note + protected_constructor_start
            replacement_fragment_bytes = replacement_fragment.encode("utf-8")
            self.decompiler.ensure_file_dir_exists(new_filename)
            file_pattern_replace(decompiled_code_filename, orig_class_start_fragment_bytes, replacement_fragment_bytes, new_filename)
        else:
            # we need to add a constructor
            protected_constructor = "protected %s() { }" % class_name

            replacement_fragment = orig_class_start_fragment + "\n" + note + protected_constructor
            replacement_fragment_bytes = replacement_fragment.encode("utf-8")

            self.decompiler.ensure_file_dir_exists(new_filename)
            file_pattern_replace(decompiled_code_filename, orig_class_start_fragment_bytes, replacement_fragment_bytes, new_filename)

        if show_differences:
            diff_u(decompiled_code_filename, new_filename)

    def get_class_fully_qualified_name(self, class_pathspec):
        return desuffix(class_pathspec, ".class").replace("/", ".")

    def replace_constructed_object(self, class_pathspec, original_constructed_pathspec, new_constructed_pathspec, show_differences):
        """ Decompile the given class and replace calls to construct one class of object
        with calls to construct another class of object
        @param class_pathspec: fully qualified class file specifier using forward slash as the separator and ending with ".class"
        @param original_constructed_pathspec: The class of constructor calls to replace
        @param new_constructed_pathspec: The class to replace it with
        """

        decompiled_code_filename = self.common_decompile_and_remove_unpatched(class_pathspec)

        source_code = contents(decompiled_code_filename).decode("utf-8")

        note = "// alternate constructor call version generated by %s %s\n" % (sys.argv[0], formatdate())

        # note goes at top
        source_code = note + source_code

        full_original_constructed_class_name = self.get_class_fully_qualified_name(original_constructed_pathspec)

        constructor_match_classes = [full_original_constructed_class_name]

        has_original_class_import = ("import %s;" % full_original_constructed_class_name) in source_code

        if has_original_class_import:
            constructor_match_classes.append(self.class_name_proper(original_constructed_pathspec))

        full_replacement_constructed_class_name = self.get_class_fully_qualified_name(new_constructed_pathspec)

        some_match = False
        for cons_match in constructor_match_classes:
            constructor_call_form = "new %s("
            constructor_call_match = constructor_call_form % cons_match
            print(constructor_call_match)
            if constructor_call_match in source_code:
                some_match = True
            source_code = source_code.replace(constructor_call_match, constructor_call_form % full_replacement_constructed_class_name)

        assert some_match, "no matching constructor calls found"

        self.common_finish_contents(class_pathspec, source_code, decompiled_code_filename, show_differences)

    def make_methods_accessible(self, class_pathspec, method_specs_list, show_differences):
        """
        Decompile the source for the given class and make the given methods visible
        @param method_specs_list: a list of specifiers for methods to make visible,
                                    where a specifier is a string with a return type like "void foo"
        @param class_pathspec: fully qualified class file specifier using forward slash as the separator and ending with ".class"
        """

        decompiled_code_filename = self.common_decompile_and_remove_unpatched(class_pathspec)

        source_code = contents(decompiled_code_filename).decode("utf-8")

        note = "// accessible methods version generated by %s %s\n" % (sys.argv[0], formatdate())

        # note goes at top
        source_code = note + source_code

        for method_spec in method_specs_list:
            source_code = source_code.replace("private %s(" % method_spec, "protected %s(" % method_spec)

        self.common_finish_contents(class_pathspec, source_code, decompiled_code_filename, show_differences)

    def common_finish_contents(self, class_pathspec, source_code_str, decompiled_code_filename, show_differences):
        new_filename = self.additional_src_filename(class_pathspec)

        print("replacing " + new_filename)
        self.decompiler.ensure_file_dir_exists(new_filename)
        write_contents(new_filename, source_code_str.encode("utf-8"))

        if show_differences:
            diff_u(decompiled_code_filename, new_filename)

def get_java_bin_path(program):
    assert program == "javac" or program == "jar"
    if program == "javac":
        desc = "A Java compiler"
    elif program == "jar":
        desc = "The jar tool"

    if sys.platform == "win32":
        general_instructions = "\nPlease make sure you have a JDK installed and the JAVA_HOME environment variable is set to its path in Advanced System Settings."
        if "JAVA_HOME" not in os.environ:
            die("The JAVA_HOME environment variable is not set." + general_instructions)
        java_home = os.environ["JAVA_HOME"]
        if not os.path.isdir(java_home):
            die(("The JAVA_HOME environment variable is set to '%s', which does not appear to be a directory." % java_home) + general_instructions)
        result = os.path.join(java_home, "bin", "%s.exe" % program)
        if not os.path.isfile(result):
            die((desc + " was not found in the JAVA_HOME '%s'" % java_home) + general_instructions)
    else:
        result = program
    return result

def compile_java_dir(src_dir, bin_dir, classpath_dirs=None):
    """
    @param src_dir: Java source directory for the top level package
    @param bin_dir: Destination directory for compiler output class files, top level of package hierarchy
    @param classpath_dirs: List of directories or JARs to use as the classpath in addition to normal system library path when building
    """
    javac = get_java_bin_path("javac")

    source_files = []
    for dirpath, dirnames, filenames in os.walk(src_dir):
        for filename in filenames:
            if filename.endswith(".java"):
                full_filename = os.path.join(dirpath, filename)
                source_files.append(full_filename)

    print("passing javac %d source files" % len(source_files))
    args = [javac, "-d", bin_dir]
    if classpath_dirs is not None:
        classpath = ";".join(classpath_dirs)
        args += ["-cp", classpath]
    args += source_files
    subprocess.check_call(args)

def create_mod_jar(output_jar_filename, classpath_dirs, main_class):
    jar = get_java_bin_path("jar")

    print("creating file with initial files from %s" % classpath_dirs[0])
    subprocess.check_call([jar, "cfe", output_jar_filename, main_class, "-C", classpath_dirs[0], "."])
    for classpath_dir in classpath_dirs[1:]:
        print("adding %s" % classpath_dir)
        subprocess.check_call([jar, "uf", output_jar_filename, "-C", classpath_dir, "."])

def parse_args():
    parser = argparse.ArgumentParser("get_sources")
    parser.add_argument("mewnbase_directory", help="The directory containing the original mewnbase game")
    parser.add_argument("--show_differences", default=False, action="store_true", help="Show differences of the patched decompiled class source; requires a diff tool")

    return parser.parse_args()

def die(msg):
    print(msg, file=sys.stderr)
    sys.exit(1)

def step(name):
    print("* " + name)

def main():
    options = parse_args()

    decomp_dir = os.path.join(script_path, "decomp")
    if not os.path.isdir(decomp_dir):
        os.mkdir(decomp_dir)

    extracted_classpath_dir = os.path.join(script_path, "extracted_jar")
    if not os.path.isdir(extracted_classpath_dir):
        os.mkdir(extracted_classpath_dir)

    show_differences = options.show_differences

    # FIXME dynamically determine the existing game location to use
    mewnbase_dir = options.mewnbase_directory
    mewnbase_jar = os.path.join(mewnbase_dir, "game", "desktop-1.0.jar")

    if not os.path.isfile(mewnbase_jar):
        die("Main game JAR file %s not found; double check mewnbase_dir is really %s" % (mewnbase_jar, mewnbase_dir))

    step("Extracting game code class files from JAR")
    unzip_file_to_dir(mewnbase_jar, extracted_classpath_dir)

    jd = JavaDecompiler()
    jd.setup()

    step("Decompiling and modifying game files...")
    print(mewnbase_jar)

    additional_src_dir = os.path.abspath(os.path.join(script_path, "..", "src"))

    modifiedGame = ModifiedJavaProject(jd, mewnbase_jar, decomp_dir, extracted_classpath_dir, additional_src_dir)

    # Make the necessary modifications to classes:

    # constructor visibility
    for class_pathspec in ["com/cairn4/moonbase/tiles/TileFactory.class",
                           "com/cairn4/moonbase/ItemFactory.class"]:

        modifiedGame.make_constructor_accessible(class_pathspec, show_differences)

    # replacement classes
    modifiedGame.replace_constructed_object("com/cairn4/moonbase/ui/GameScreen.class", "com/cairn4/moonbase/GameLoader.class", "net/rakslice/mewnbase_mod/AltGameLoader.class",
                                            show_differences)

    # method visibility
    modifiedGame.make_methods_accessible("com/cairn4/moonbase/GameLoader.class", ["void loadEntities"], show_differences)

    # # For getting a diff for our own hand-modified file we would do something like
    # class_pathspec = "com/cairn4/moonbase/entities/Buggie.class"
    #
    # decompiled_code_filename = jd.decompile_jar_to_dir(mewnbase_jar, decomp_dir, class_pathspec)
    # our_version = os.path.join(script_path, "..", "src", desuffix(class_pathspec, "Buggie.class") + "Train.java")
    #
    # diff_u(decompiled_code_filename, our_version)

    step("Compiling added mod source")
    bin_dir = os.path.abspath(os.path.join(script_path, "..", "bin"))
    compile_java_dir(additional_src_dir, bin_dir, classpath_dirs=[extracted_classpath_dir])

    step("Assemble modded game jar")
    output_jar_filename = os.path.join(script_path, "build", "desktop-1.0.jar")
    jd.ensure_file_dir_exists(output_jar_filename)
    if os.path.exists(output_jar_filename):
        os.remove(output_jar_filename)
    main_class = "com.cairn4.moonbase.desktop.ModDesktopLauncher"
    create_mod_jar(output_jar_filename, [bin_dir, extracted_classpath_dir], main_class)

    step("Done. Output at: %s" % output_jar_filename)

if __name__ == "__main__":
    main()


from typing import List, Optional, Union
from subprocess import CalledProcessError
from . import adbcmds
from . import adbdevice
from .adbprocess import AdbCommandError, AdbProcess

class AdbServer:
    """AdbServer in a class representation for adb server operations.

    :param Optional[int] port: Port, default is 5555.
    :keyword str path: Adb binary path.

    :Example:

    >>> import simpleadb
    >>> device = simpleadb.AdbServer(5555)
    >>> device = simpleadb.AdbDevice(5555, path='/usr/bin/adb')
    """

    def __init__(self, port: Optional[int] = None, **kwargs):
        options_path = kwargs.get("path")
        adb_path = options_path if options_path else adbcmds.ADB
        self.__adb_process = AdbProcess(None, adb_path)
        self.start(port)

    def devices(self) -> List[str]:
        """Get list connected adb devices.

        :raise: AdbCommandError: When failed.
        :return: List of connected devices serial numbers.
        :rtype: List[str]

        :Example:

        >>> import simpleadb
        >>> adb_server = simpleadb.AdbServer(5555)
        >>> adb_server.devices()
        ['emulator-5554']
        """
        cmd = []
        cmd.append(adbcmds.DEVICES)
        try:
            output = self.__adb_process.check_output(cmd)
        except CalledProcessError as err:
            raise AdbCommandError(None, None, err) from err
        devices = []
        devices_list = output.splitlines()
        devices_list.pop(0)
        for line in devices_list:
            device = line.strip().split()
            if device:
                device_id = device[0]
                devices.append(adbdevice.AdbDevice(device_id))
        return devices

    def connect(self, address, port: Optional[Union[int, str]] = 5555) -> None:
        """Connect a device via TCP/IP.

        :param str address: Host address.
        :param port (Optional[Union[int,str]]): Port, default 5555.
        :raise CalledProcessError: When failed.

        :Example:

        >>> import simpleadb
        >>> adb_server = simpleadb.AdbServer(5555)
        >>> adb_server.connect('192.168.42.42', 5555)
        """
        cmd = []
        cmd.append(adbcmds.CONNECT)
        cmd.append(address)
        cmd.append(str(port))
        self.__adb_process.check_output(cmd)

    def disconnect(self, address, port: Optional[Union[int, str]] = None) -> None:
        """Disconnect from given TCP/IP device.

        :param address str: Host address.
        :param (Optional[Union[int, str] port]): Port.
        :raise: AdbCommandError: When failed.

        :Example:

        >>> import simpleadb
        >>> adb_server = simpleadb.AdbServer(5555)
        >>> adb_server.connect('192.168.42.42', 5555)
        >>> adb_server.disconnect('192.168.42.42')
        """
        cmd = []
        cmd.append(adbcmds.DISCONNECT)
        cmd.append(address + f":{port}" if port is not None else "")
        self.__adb_process.check_output(cmd)

    def start(self, port: Optional[Union[int, str]] = None) -> None:
        """Start adb and ensure that there is running.

        :param address str: Host address.
        :param (Optional[Union[int, str] port]): Port, default adb server port.
        :raise: AdbCommandError: When failed.

        :Example:

        >>> import simpleadb
        >>> adb_server = simpleadb.AdbServer(5555)
        >>> adb_server.start()
        >>> adb_server.start(5037)
        """
        cmd = []
        if port is not None:
            cmd.append(" ".join(["-P", str(port)]))
        cmd.append(adbcmds.START_SERVER)
        try:
            self.__adb_process.check_output(cmd)
        except CalledProcessError as err:
            raise AdbCommandError(None, None, err) from err

    def kill(self) -> None:
        """Kill the server if it is running.

        :raise: AdbCommandError: When failed.

        :Example:

        >>> import simpleadb
        >>> adb_server = simpleadb.AdbServer(5555)
        >>> adb_server.kill()
        """
        cmd = []
        cmd.append(adbcmds.KILL_SERVER)
        self.__adb_process.check_output(cmd)


import pandas as pd
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.preprocessing import StandardScaler
from feature_engine.creation import CyclicalFeatures
from typing import Any, Literal, Union, List, Tuple

def train_test_split(
    df: pd.DataFrame, test_start: str, test_end: str, target_var: str
) -> Tuple[pd.DataFrame, pd.Series, pd.DataFrame, pd.Series]:
    """
    Splits the given data into train and test set.
    :param df: The data to split
    :param test_start: The start of the test set - has to be a string parsable by pd.to_datetime
    :param test_end: The end of the test set - has to be a string parsable by pd.to_datetime
    :return: The train and test set
    """
    test_start = pd.to_datetime(test_start)
    test_end = pd.to_datetime(test_end)

    # check if test_start and test_end are in data
    assert test_start in df.index, "test_start not in data."
    assert test_end in df.index, "test_end not in data."
    # check if test_start is before test_end
    assert test_start < test_end, "test_start must be before test_end."

    # check if target_var is in data
    assert target_var in df.columns, "target_var not in data."

    X_train = df.loc[:test_start,][:-1]
    y_train = df.loc[:test_start][target_var][:-1]
    X_test = df.loc[test_start:test_end,]
    y_test = df.loc[test_start:test_end][target_var]

    return X_train, y_train, X_test, y_test

class SupervisedTransformer(BaseEstimator, TransformerMixin):
    """
    Encodes time series data (i.e. index is pd.datetime) into a supervised learning problem.
    """

    def __init__(
        self,
        horizon: Literal["10min", "hourly", "daily"] = "10min",
        window_size: int = 1,
        encode_time: List[Literal["hour", "dayofweek", "month", "year"]] = None,
        include_past: bool = True,
    ):
        """
        Initializes the transformer.
        :param horizon: Specifies the time horizon of the prediction: - 10min: 1 time step ahead
                                                                      - Hourly: 6 time steps ahead
                                                                      - Daily: 144 time steps ahead
        :param window_size: The number of time steps into the past to use for prediction
        :param encode_time: Whether to encode the time features
        :param include_past: Whether to include the past observations of the target in the prediction
        """
        self.horizon = horizon
        self.window_size = window_size
        self.encode_time = encode_time
        self.include_past = include_past

    def _reset(self):
        """
        Resets the transformer.
        """
        if hasattr(self, "X_train"):
            del self.X_train
        if hasattr(self, "target_var"):
            del self.target_var
            del self.target_var_name

    def fit(self, X: pd.DataFrame, y: pd.Series = None):
        """
        Fits the transformer to the given data.
        :param X: The data to fit the transformer to
        :param y: The target variable
        :return: self
        """
        self._reset()
        assert X.isna().sum().sum() == 0, "There are NaNs in the data."
        if y is not None and self.include_past:
            self.target_var = y
            self.target_var_name = y

        self.X_train = X.copy()  # has to be stored for transforming the test set

        return self

    def transform(self, X: pd.DataFrame):
        """
        Transforms the given data into a supervised learning problem.
        :param X: The data to transform
        :return: The transformed data
        """
        # check if self is fitted:
        assert hasattr(self, "X_train"), "Transformer has to be fitted first."
        # check if there are NaNs in the data
        assert X.isna().sum().sum() == 0, "There are NaNs in the data."

        data = X.copy()

        if self.X_train.index.equals(data.index):
            data = self._supervised_transform(data)
        else:
            data = self._supervised_transform_test(data)

        if self.encode_time is not None:
            for time_feature in self.encode_time:
                data = pd.concat(
                    [
                        data,
                        self._get_time_feature(data.index, time_feature),
                    ],
                    axis=1,
                )
        data.index.name = "Date"
        return data

    def _supervised_transform(self, X: pd.DataFrame):
        """
        Transforms the given data into a supervised learning problem.
        :param X: The data to transform
        :param y: The target variable
        :return: The transformed data
        """

        shifts = range(self.horizon, self.window_size + self.horizon)
        predictors = X.columns

        for column in predictors:
            df = pd.DataFrame(columns=[f"{column} (time {-i})" for i in shifts])
            for i in shifts:
                df[f"{column} (time {-i})"] = X[column].shift(i)
            X = pd.concat([X, df], axis=1)

        X.dropna(inplace=True)
        # drop columns of current timestep
        X.drop(columns=predictors, inplace=True)

        return X

    def _supervised_transform_test(self, X: pd.DataFrame):
        """
        Transform the given data into a supervised learning problem for the test set.
        :param X: The data to transform (the test set must be directly after the train set)
        :return: The transformed data
        """
        # check if index of X is directly after index of X_train
        #  assert X.index[0] == self.X_train.index[-1] + pd.Timedelta(self.horizon, unit="min"), "Index of test set must be directly after index of train set."

        # append the last window size observations of the train set to the test set
        X = pd.concat([self.X_train.iloc[-(self.window_size + self.horizon - 1) :], X])

        return self._supervised_transform(X)

    @staticmethod
    def _get_time_feature(
        dates: pd.DatetimeIndex, feature: Literal["hour", "dayofweek", "month", "year"]
    ) -> pd.Series:
        """
        Transforms the given feature of the given dates into a cyclical feature.
        :param dates: The dates to transform
        :param feature: The feature to transform
        """
        cf = CyclicalFeatures(drop_original=True)
        dates.name = feature
        if feature == "hour":
            return cf.fit_transform(pd.DataFrame(dates.hour, index=dates))
        elif feature == "dayofweek":
            return cf.fit_transform(pd.DataFrame(dates.dayofweek, index=dates))
        elif feature == "month":
            return cf.fit_transform(pd.DataFrame(dates.month, index=dates))
        elif feature == "year":
            return cf.fit_transform(pd.DataFrame(dates.year, index=dates))
        else:
            raise ValueError(
                "feature must be one of 'hour', 'dayofweek', 'month' or 'year'."
            )

    def __setattr__(self, __name: str, __value: Any) -> None:
        if __name == "horizon" and isinstance(__value, str):
            if __value == "10min":
                __value = 1
            elif __value == "hourly":
                __value = 6
            elif __value == "daily":
                __value = 144
            else:
                raise ValueError("horizon must be one of '10min', 'hourly' or 'daily'.")
        super().__setattr__(__name, __value)

class DataCleaner(BaseEstimator, TransformerMixin):
    """
    Cleans the given data by interpolating NaNs and removing the remaining NaNs.
    """

    def __init__(
        self,
        features: Union[Literal["auto"], List[str]] = "auto",
        rename_features: Union[Literal[False], List[str]] = False,
    ):
        """
        Initializes the transformer.
        :param features: The features to clean
        :param rename_features: The new names of the features
        :param remove_nans: Whether to remove the remaining NaNs
        """
        self.features = features
        self.rename_features = rename_features

    def fit(self, X: pd.DataFrame, y: pd.Series = None):
        """
        This function is called when the transformer is fitted to the data. In this case, it does nothing
        but it is needed for compatibility with sklearn pipelines.
        :param X: The data to fit the transformer to
        :param y: The target variable
        :return: self
        """
        return self

    def transform(self, X: pd.DataFrame) -> pd.DataFrame:
        """
        Cleans the given data.
        :param X: The data to clean
        :return: The cleaned data
        """
        X = X.copy()
        X = self._select_features(X)
        X = self._clean_data(X)
        return X

    def _clean_data(self, X: pd.DataFrame) -> pd.DataFrame:
        """
        Cleans the given data.
        :param X: The data to clean
        :return: The cleaned data
        """
        X = X.interpolate(method="linear")
        X.dropna(inplace=True)
        if isinstance(self.rename_features, list):
            X = self._rename_columns(X, self.rename_features)
        return X

    def _select_features(self, X: pd.DataFrame, thresh: float = 0.7) -> pd.DataFrame:
        """
        Selects the features to clean.
        :param X: The data to select the features from
        :return: Dataframe with the selected features
        """
        assert self._check_features(
            X
        ), "Features not in data. Please select valid data."
        if self.features == "auto":
            self.features = X.columns[X.isna().sum() < thresh * X.shape[0]]
        return X[self.features]

    def _check_features(self, X: pd.DataFrame) -> bool:
        """
        Checks if the features are in the given data.
        :param X: The data to check
        """
        return all(feature in X.columns for feature in self.features)

    def _rename_columns(
        self, X: pd.DataFrame, renamed_features: List[str]
    ) -> pd.DataFrame:
        """
        Renames the columns of the given data.
        :param X: The data to rename
        :param renamed_features: The new names of the features
        :return: The renamed data
        """
        assert len(self.features) == len(
            renamed_features
        ), "Number of features and number of renamed features must be equal."
        X.columns = renamed_features
        return X

class Normalizer(StandardScaler):
    """
    Overwrites the transform function of the StandardScaler from sklearn to allow for to
    keep the index and column names after scaling. Additionally, it allows for no scaling at all such that
    the effects of the transformation can be studied in a pipeline.
    """

    def __init__(self, scale: bool = True):
        """
        Initializes the transformer.
        :param scale: Whether to scale the data
        """
        self.scale = scale
        super().__init__()

    def transform(self, X: pd.DataFrame):
        """
        Transforms the given data.
        :param X: The data to transform
        :return: The transformed data
        """
        if self.scale:
            X = pd.DataFrame(super().transform(X), index=X.index, columns=X.columns)
            return X
        else:
            return X  # return unchanged data

class FeatureSelector(BaseEstimator, TransformerMixin):
    def __init__(self, features: List[str] = ["power"]) -> None:
        """
        Initializes the transformer.
        :param features: The features to select
        """
        self.features = features

    def fit(self, X: pd.DataFrame, y: pd.Series = None):
        """
        This function is called when the transformer is fitted to the data. In this case, it does nothing
        but it is needed for compatibility with sklearn pipelines.
        :param X: The data to fit the transformer to
        :param y: The target variable
        :return: self
        """
        return self

    def transform(self, X: pd.DataFrame) -> pd.DataFrame:
        """
        Selects the given features from the data.
        :param X: The data to select the features from
        :return: The data with the selected features
        """
        assert self._check_features(
            X
        ), "Features not in data. Please select valid data."
        return X[self.features]

    def _check_features(self, X: pd.DataFrame) -> bool:
        """
        Checks if the features are in the given data.
        :param X: The data to check
        """
        return all(feature in X.columns for feature in self.features)


bl_info = {
    "name": "Cycles Render Engine",
    "author": "",
    "blender": (2, 76, 0),
    "location": "Info header, render engine menu",
    "description": "Cycles Render Engine integration",
    "warning": "",
    "wiki_url": "https://docs.blender.org/manual/en/dev/render/cycles/",
    "tracker_url": "",
    "support": 'OFFICIAL',
    "category": "Render"}

# Support 'reload' case.
if "bpy" in locals():
    import importlib
    if "engine" in locals():
        importlib.reload(engine)
    if "version_update" in locals():
        importlib.reload(version_update)
    if "ui" in locals():
        importlib.reload(ui)
    if "properties" in locals():
        importlib.reload(properties)
    if "presets" in locals():
        importlib.reload(presets)

import bpy

from . import (
        engine,
        version_update,
        )

class CyclesRender(bpy.types.RenderEngine):
    bl_idname = 'CYCLES'
    bl_label = "Cycles Render"
    bl_use_shading_nodes = True
    bl_use_preview = True
    bl_use_exclude_layers = True
    bl_use_save_buffers = True
    bl_use_spherical_stereo = True

    def __init__(self):
        self.session = None

    def __del__(self):
        engine.free(self)

    # final render
    def update(self, data, scene):
        if not self.session:
            if self.is_preview:
                cscene = bpy.context.scene.cycles
                use_osl = cscene.shading_system and cscene.device == 'CPU'

                engine.create(self, data, scene,
                              None, None, None, use_osl)
            else:
                engine.create(self, data, scene)
        else:
            engine.reset(self, data, scene)

    def render(self, scene):
        engine.render(self)

    def bake(self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
        engine.bake(self, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)

    # viewport render
    def view_update(self, context):
        if not self.session:
            engine.create(self, context.blend_data, context.scene,
                          context.region, context.space_data, context.region_data)
        engine.update(self, context.blend_data, context.scene)

    def view_draw(self, context):
        engine.draw(self, context.region, context.space_data, context.region_data)

    def update_script_node(self, node):
        if engine.with_osl():
            from . import osl
            osl.update_script_node(node, self.report)
        else:
            self.report({'ERROR'}, "OSL support disabled in this build.")

    def update_render_passes(self, scene, srl):
        engine.register_passes(self, scene, srl)

def engine_exit():
    engine.exit()

classes = (
    CyclesRender,
)

def register():
    from bpy.utils import register_class
    from . import ui
    from . import properties
    from . import presets
    import atexit

    # Make sure we only registered the callback once.
    atexit.unregister(engine_exit)
    atexit.register(engine_exit)

    engine.init()

    properties.register()
    ui.register()
    presets.register()

    for cls in classes:
        register_class(cls)

    bpy.app.handlers.version_update.append(version_update.do_versions)

def unregister():
    from bpy.utils import unregister_class
    from . import ui
    from . import properties
    from . import presets
    import atexit

    bpy.app.handlers.version_update.remove(version_update.do_versions)

    ui.unregister()
    properties.unregister()
    presets.unregister()

    for cls in classes:
        unregister_class(cls)


# -*- coding:utf-8 -*-
# Author：hankcs
# Date: 2018-03-19 01:05
from __future__ import division
from __future__ import print_function

import os
import sys
import argparse
from jpype import JClass, JException, java
# noinspection PyUnresolvedReferences
from pyhanlp import HanLP, PATH_CONFIG, HANLP_JAR_VERSION, HANLP_JAR_PATH, HANLP_DATA_PATH, \
    hanlp_installed_data_version, STATIC_ROOT
from pyhanlp.util import any2utf8

PY = 3
if sys.version_info[0] < 3:
    PY = 2
    # noinspection PyUnresolvedReferences,PyCompatibility
    reload(sys), sys.setdefaultencoding("utf-8")

def main():
    if len(sys.argv) == 1:
        sys.argv.append('--help')

    arg_parser = argparse.ArgumentParser(description='HanLP: Han Language Processing v{}'.format(HANLP_JAR_VERSION))
    arg_parser.add_argument('-v', '--version', required=False, action='store_true',
                            help='show installed versions of HanLP')
    task_parser = arg_parser.add_subparsers(dest="task", help='which task to perform?')
    segment_parser = task_parser.add_parser(name='segment', help='word segmentation')
    tag_parser = segment_parser.add_mutually_exclusive_group(required=False)
    tag_parser.add_argument('--tag', dest='tag', action='store_true', help='show part-of-speech tags')
    tag_parser.add_argument('--no-tag', dest='tag', action='store_false', help='don\'t show part-of-speech tags')
    segment_parser.set_defaults(tag=True)
    segment_parser.add_argument('-a', '--algorithm', type=str, default='viterbi',
                                help='algorithm of segmentation e.g. perceptron')
    parse_parser = task_parser.add_parser(name='parse', help='dependency parsing')
    server_parser = task_parser.add_parser(name='serve', help='start http server',
                                           description='A http server for HanLP')
    server_parser.add_argument('--port', type=int, default=8765)
    update_parser = task_parser.add_parser(name='update', help='update jar and data of HanLP')

    def add_args(p):
        p.add_argument("--config", default=PATH_CONFIG,
                       help='path to hanlp.properties')
        # p.add_argument("--action", dest="action", default='predict',
        #                help='Which action (train, test, predict)?')

    add_args(segment_parser)
    add_args(parse_parser)

    if '-v' in sys.argv or '--version' in sys.argv:
        print('jar  {}: {}'.format(HANLP_JAR_VERSION, HANLP_JAR_PATH))
        data_version = hanlp_installed_data_version()
        print('data {}: {}'.format(data_version if data_version else '自定义', HANLP_DATA_PATH))
        print('config    : {}'.format(os.path.join(STATIC_ROOT, 'hanlp.properties')))
        exit(0)

    args = arg_parser.parse_args()

    def eprint(*args, **kwargs):
        print(*args, file=sys.stderr, **kwargs)

    def die(msg):
        eprint(msg)
        exit(1)

    if hasattr(args, 'config') and args.config:
        if os.path.isfile(args.config):
            JClass('com.hankcs.hanlp.utility.Predefine').HANLP_PROPERTIES_PATH = args.config
        else:
            die('Can\'t find config file {}'.format(args.config))

    if args.task == 'segment':
        segmenter = None
        try:
            segmenter = HanLP.newSegment(args.algorithm)
        except JException as e:
            if isinstance(e, java.lang.IllegalArgumentException):
                die('invalid algorithm {}'.format(args.algorithm))
            elif isinstance(e, java.lang.RuntimeException):
                die('failed to load required model')
            else:
                die('unknown exception {}'.format(repr(e)))

        is_lexical_analyzer = hasattr(segmenter, 'analyze')
        if not args.tag:
            if is_lexical_analyzer:
                segmenter.enablePartOfSpeechTagging(False)
                JClass('com.hankcs.hanlp.HanLP$Config').ShowTermNature = False
            else:
                JClass('com.hankcs.hanlp.HanLP$Config').ShowTermNature = False
        for line in sys.stdin:
            line = line.strip()
            print(' '.join(term.toString() for term in segmenter.seg(any2utf8(line))))
    elif args.task == 'parse':
        for line in sys.stdin:
            line = line.strip()
            print(HanLP.parseDependency(any2utf8(line)))
    elif args.task == 'serve':
        if PY == 3:
            from pyhanlp import server
            server.run(port=args.port)
        else:
            die('现在server.py暂时不支持Python2，欢迎参与移植')
    elif args.task == 'update':
        if hanlp_installed_data_version() == '手动安装':
            die('手动配置不支持自动升级，若要恢复自动安装，请清除HANLP相关环境变量')
        else:
            from pyhanlp.static import update_hanlp
            update_hanlp()

if __name__ == '__main__':
    main()


# https://leetcode.com/problems/validate-binary-search-tree/
# Given the root of a binary tree, determine if it is a valid binary search tree (BST).
#
# A valid BST is defined as follows:
#
# The left subtree of a node contains only nodes with keys less than the node's key.
# The right subtree of a node contains only nodes with keys greater than the node's key.
# Both the left and right subtrees must also be binary search trees.

from typing import List

# Definition for a binary tree node.

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

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        return self.__is_valid_bst(root, [], [])

    def __is_valid_bst(self, node: TreeNode, to_be_lt: List[int], to_be_gt: List[int]) -> bool:
        for lt in to_be_lt:
            if node.val >= lt:
                return False

        for gt in to_be_gt:
            if node.val <= gt:
                return False

        to_be_lt.append(node.val)
        if node.left and not self.__is_valid_bst(node.left, to_be_lt, to_be_gt):
            return False
        to_be_lt.pop()

        to_be_gt.append(node.val)
        if node.right and not self.__is_valid_bst(node.right, to_be_lt, to_be_gt):
            return False
        to_be_gt.pop()

        return True


import argparse
import numpy as np
import argparse
import numpy as np
import scipy.optimize
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import sys
import os
import math
import wandb
from src.ProteinTransformer import *
from src.ProteinsDataset import *
from src.MatchingLoss import *
from src.utils import *

import json
from scipy.stats import spearmanr

def get_params(params):

    parser = argparse.ArgumentParser()

    # Parameters
    parser.add_argument('--trainset', type=str, help="Path to the dataset for training")
    parser.add_argument('--valset', type=str, help="Path to the dataset for validation")
    parser.add_argument('--save', type=str, default="", help="path to save model, if empty will not save")
    parser.add_argument('--load', type=str, default="", help="path to load model, if empty will not save")
    parser.add_argument('--modelconfig', type=str, default="shallow.config.json", help="hyperparameter")
    parser.add_argument('--outputfile', type=str, default="output.txt", help="file to print scores")

    args = parser.parse_args(params)

    return args

def main(params):

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # Params
    opts = get_params(params)
    f = open(opts.outputfile, "w")
    if opts.save:
        save_model=True
        model_path_save = opts.save
    else:
        save_model = False
    if opts.load:
        load_model=True
        model_path_load = opts.load
    else:
        load_model = False

    with open(opts.modelconfig, "r") as read_file:
        print("loading hyperparameter")
        modelconfig = json.load(read_file)

    Align=modelconfig["Align"]
    pds_train = ProteinDataset(opts.trainset, device=device, Align=Align, returnlabel=False)
    pds_val = ProteinDataset(opts.valset, device=device, Unalign=Unalign, returnlabel=True)
    len_input = pds_train[0].shape[0]

    ntrain = len(pds_train)
    nval = len(pds_val)

    # dval1,dval2 = distanceTrainVal(pds_train, pds_val)
    # print("median", (dval1+dval2).min(dim=0)[0].median())
    # maskValclose = (dval1+dval2).min(dim=0)[0]<(dval1+dval2).min(dim=0)[0].median()
    # maskValclose = maskValclose.cpu().numpy()
    # maskValfar = (dval1+dval2).min(dim=0)[0]>=(dval1+dval2).min(dim=0)[0].median()
    # maskValfar = maskValfar.cpu().numpy()

    train_iterator = DataLoader(pds_train, batch_size=modelconfig["batch_size"],
                    shuffle=False, num_workers=0, collate_fn=default_collate)
    val_iterator = DataLoader(pds_val, batch_size=modelconfig["batch_size"],
                    shuffle=False, num_workers=0, collate_fn=default_collate)

    src_pad_idx =pds_train.padIndex

    trg_position_embedding = PositionalEncoding(modelconfig["embedding_size"], max_len=len_input, device=device)

    model = Transformer(
        modelconfig["embedding_size"],
        modelconfig["trg_vocab_size"],
        pad_idx,
        modelconfig["num_heads"],
        modelconfig["num_decoder_layers"],
        modelconfig["forward_expansion"],
        modelconfig["dropout"],
        trg_position_embedding,
        device,
    ).to(device)

    for p in model.parameters():
        if p.dim() > 1:
            nn.init.xavier_normal_(p)

    optimizer = optim.AdamW(model.parameters(), lr=modelconfig["learning_rate"], weight_decay=modelconfig["wd"])

    if load_model:
        load_checkpoint(torch.load(model_path_load), model, optimizer)

    criterion = nn.CrossEntropyLoss(ignore_index=pds_train.padIndex)
    criterion_raw = nn.CrossEntropyLoss(reduction='none')
    num_epochs = modelconfig["num_epochs"]
    for epoch in range(modelconfig["num_epochs"]+1):
        print(f"[Epoch {epoch} / {num_epochs}]")
        model.train()
        lossesCE = []
        for batch_idx, batch in enumerate(train_iterator):
            optimizer.zero_grad()
            loss = LLLoss(batch, model, criterion)
            lossesCE.append(loss.item())
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1)
            optimizer.step()

        mean_lossCETrain = sum(lossesCE) / len(lossesCE)

        model.eval()
        lossesCE_eval = []
        lossesMatching_eval = []
        accuracyVal = 0
        mes = []

        with  torch.no_grad():
            for batch_idx, batch in enumerate(val_iterator):
                target, me = batch[0], batch[1]
                bs = target.shape[1]
                # target, me= batch[0], batch[1]
                # target = target.to(device)
                # output = model(target[:-1, :])
                # # accuracyVal += accuracy(batch, output, onehot=False).item()
                # output = output.reshape(-1, output.shape[2]) #keep last dimension
                # targets_Original= target
                # targets_Original = targets_Original[1:].reshape(-1)
                # loss_eval = criterion(output, targets_Original)
                loss_full = LLLoss(target, model, criterion_raw).reshape(-1,bs).mean(dim=0)
                for x, xme in zip(loss_full, me):
                    lossesCE_eval.append(x.item())
                    mes.append(xme.item())
            spearmann = spearmanr(lossesCE_eval, mes)

        out = "epoch: "+str(epoch)+", Train loss CE: " + str(mean_lossCETrain) +  ", spearmann: "+ str(spearmann)

        # if epoch%200==0:
        #     model.eval()
        #     criterionE = nn.CrossEntropyLoss(ignore_index=pds_train.padIndex, reduction='none')
        #     scoreHungarianVal = HungarianMatchingBS(pds_val, model, 100)
        #     scoHVal = scipy.optimize.linear_sum_assignment(scoreHungarianVal)
        #     scoreMatchingVal = sum(scoHVal[0]==scoHVal[1])
        #     scoreMatchingValClose = sum((scoHVal[0]==scoHVal[1])[maskValclose])
        #     scoreMatchingValFar = sum((scoHVal[0]==scoHVal[1])[maskValfar])
        #     out+= ", scoreMatching Val :" +str(scoreMatchingVal)+", scoreMatchingValClose: " +str(scoreMatchingValClose)+", scoreMatchingVal Far: "+ str(scoreMatchingValFar)
        #     if save_model:
        #         checkpoint = {
        #             "state_dict": model.state_dict(),
        #             "optimizer": optimizer.state_dict(),
        #         }
        #         save_checkpoint(checkpoint, filename=model_path_save)
        # out+="\n"
        f.write(out)
    print("End Training")
    f.close()

if __name__ == "__main__":
    import sys
    main(sys.argv[1:])