import torch.nn as nn
from classification3d.network.module.weight_init import kaiming_weight_init
from classification3d.network.module.vnet_inblock import InputBlock
from classification3d.network.module.vnet_downblock import DownBlock

def parameters_init(net):
    net.apply(kaiming_weight_init)

class ClassificationNet(nn.Module):

    def __init__(self, in_channels, class_num, input_size):
        super(ClassificationNet, self).__init__()
        self.in_block = InputBlock(in_channels, 16)
        self.down_32 = DownBlock(16, 1, compression=False)
        self.down_64 = DownBlock(32, 2, compression=True)
        self.down_128 = DownBlock(64, 3, compression=True)
        self.down_256 = DownBlock(128, 3, compression=True)
        self.down_512 = DownBlock(256, 3, compression=True)

        self.global_pooling = nn.AvgPool3d((input_size[0] // 32, input_size[1] // 32, input_size[2] // 32), 1, 0)
        self.fc = nn.Linear(512, class_num)
        self.soft_max = nn.Softmax(dim=1)

    def forward(self, input_tensor):
        out16 = self.in_block(input_tensor)
        out32 = self.down_32(out16)
        out64 = self.down_64(out32)
        out128 = self.down_128(out64)
        out256 = self.down_256(out128)
        out512 = self.down_512(out256)
        output = self.global_pooling(out512)
        output = output.view(output.size(0), -1)
        output = self.soft_max(self.fc(output))
        return output

    @staticmethod
    def max_stride():
        return 32


"""Train family of LSTM v3 networks with different prong orders"""

import os
from speval import speval

from vlne.args    import join_dicts
from vlne.consts  import ROOT_OUTDIR
from vlne.presets import PRESETS_TRAIN
from vlne.train   import create_and_train_model
from vlne.utils   import parse_concurrency_cmdargs, setup_logging

config = join_dicts(
    PRESETS_TRAIN['nova_numu_v3'],
    {
    # Config:
        'batch_size'   : 1024,
        #'vars_input_slice',
        #'vars_input_png2d',
        #'vars_input_png3d',
        #'vars_target_total',
        #'vars_target_primary',
        'dataset'      : (
            'numu/prod4/fd_fhc'
            '/dataset_lstm_ee_fd_fhc_nonswap_loose_cut.csv.xz'
        ),
        'early_stop'   : {
            'name'   : 'standard',
            'kwargs' : {
                'monitor'   : 'val_loss',
                'min_delta' : 0,
                'patience'  : 40,
            },
        },
        'epochs'       : 200,
        'loss'         : 'mean_absolute_percentage_error',
        'max_prongs'   : None,
        'model'        : {
            'name'   : 'lstm_v3',
            'kwargs' : {
                'norm'         : 'batch',
                'layers_pre'   : [ 128, 128, 128 ],
                'layers_post'  : [ 128, 128, 128 ],
                'lstm_units2d' : 32,
                'lstm_units3d' : 32,
                'n_resblocks'  : 0,
            },
        },
        'noise'        : {
            'affected_vars_slice' : [ 'calE', 'orphCalE', 'remPngCalE' ],
            'affected_vars_png2d' : [ 'png2d.calE', 'png2d.weightedCalE' ],
            'affected_vars_png3d' : [
                'png.calE',
                'png.weightedCalE',
                'png.bpf[0].overlapE',
                'png.bpf[1].overlapE',
                'png.bpf[2].overlapE',
            ],
            'noise'        : 'discrete',
            'noise_kwargs' : { 'values' : [ -0.2, 0, 0.2 ] },
        },
        'optimizer'    : {
            'name'   : 'RMSprop',
            'kwargs' : { 'lr' : 0.001 },
        },
        'prong_sorters' : None,
        'regularizer'   : {
            'name'   : 'l1',
            'kwargs' : { 'l' : 0.001 },
        },
        'schedule'     : {
            'name'   : 'standard',
            'kwargs' : {
                'monitor'  : 'val_loss',
                'factor'   : 0.5,
                'patience' : 5,
                'cooldown' : 0
            },
        },
        'seed'            : 1337,
        'steps_per_epoch' : 250,
        'test_size'       : 200000,
        'weights' : {
            'name'   : 'flat',
            'kwargs' : { 'bins' : 35, 'range' : (0, 7), 'clip' : 50 },
        },
    # Args:
        'vars_mod_png2d'  : None,
        'vars_mod_png3d'  : None,
        'vars_mod_slice'  : None,
        'outdir'          : 'numu/prod4/06_var_studies/01_fd_vars_order',
    }
)

parse_concurrency_cmdargs(config)

search_space = [
    { 'prong_sorters' : None },
]

for prong_sorter in [ None, 'random', '+png.calE', '-png.calE' ]:
    search_space.append(
        { 'prong_sorters' : { 'input_png3d' : prong_sorter } }
    )

logger = setup_logging(
    log_file = os.path.join(ROOT_OUTDIR, config['outdir'], "train.log")
)

speval(
    lambda x : create_and_train_model(**config, extra_kwargs = x),
    search_space,
    os.path.join(ROOT_OUTDIR, config['outdir'], "trials.db"),
    timeout = 3 * 60 * 60
)


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
import requests
import os
import json
from components.selenium.constants import *

async def getDriverOptions():
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-gpu')
    options.add_argument('--disable-dev-shm-usage')
    return options

async def getRemoteWebDriver(commandExecutor,sessionId=None):
    if sessionId:
        return await attach_to_session(commandExecutor=commandExecutor,sessionId=sessionId)
    else:
        driver = webdriver.Remote(
            command_executor=commandExecutor,
            options=await getDriverOptions()
        )
        return driver

async def attach_to_session(commandExecutor, sessionId):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': sessionId}
        else:
            return original_execute(self, command, params)
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute
    driver = webdriver.Remote(command_executor=commandExecutor, desired_capabilities={})
    driver.session_id = sessionId
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return driver

def enterCaptcha(driver:webdriver.Remote):
    img = driver.find_element(By.XPATH,CAPTCHA_BOX_XPATH).screenshot_as_png
    captcha_image_name = '/tmp/captcha_'+driver.session_id+".png"
    with open(captcha_image_name, 'wb') as f:
        f.write(img)

    url = 'http://35.207.247.66:7000/captcha_ocr'
    with open(captcha_image_name, 'rb') as image:
        name_img = os.path.basename(captcha_image_name)
        files= {'image': (name_img,image,'multipart/form-data',{'Expires': '0'}) }
        with requests.Session() as s:
            response = s.post(url,files=files)
            res= json.loads(response.text)
            captcha = res['output']['captcha']['prediction']
            driver.find_element(By.XPATH,CAPTCHA_INPUT_XPATH).send_keys(captcha)

    os.remove(captcha_image_name)


from flask import Flask, request
from flask_restful import Resource, Api
from gevent.pywsgi import WSGIServer
from ipaddress import IPv4Network
import os
import json
import requests
import sys
import subprocess
import jwt
from gevent import monkey
from dotenv import load_dotenv

monkey.patch_all()
app = Flask(__name__)
api = Api(app)

#Global variables
secret = ""
public_key = ""
private_key = ""
timestamp = ""
DID = ""
endpoint_IdM = ""

# Get own public key curve25519
def get_public_key():
    file = open("public_key", mode="r")
    public_key = file.read()
    public_key = public_key[:-1]
    file.close()
    return public_key

def get_key_pair_from_IdM(secret):
    global public_key
    global private_key

    #This method will be agnostic to the domains after changing the current end-point of the IdM
    header = {"shared-secret": secret}
    req = requests.get("http://172.28.3.153:6800/authentication/operator_key_pair", headers=header)
    req = req.json()
    print("JSON: ", req)
    public_key = req["public_key"]
    private_key = req["private_key"]

def get_own_IP():
    command = "ip addr show ens3 | grep \"inet \" | awk \'{print $2}\' | cut -f1 -d\"/\""
    result = subprocess.run(command, stdout=subprocess.PIPE, shell=True)
    ip = result.stdout.decode('utf-8')
    return ip

# Get own private key curve25519
def get_private_key():
    file = open("private_key", mode="r")
    private_key = file.read()
    private_key = private_key[:-1]
    file.close()

    return private_key

def get_vpn_port():
    file = open("vpn_port", mode="r")
    vpn_port = int(file.read())
    file.close()
    return vpn_port

def set_vpn_port(n_port):
    file = open("vpn_port", mode="w")
    file.write(n_port)
    file.close()

# When acting as server, get next IP available for clients in wg0.conf
"""def get_next_IP_available():
    min1 = 0
    min2 = 0
    min3 = 0
    min4 = 1

    file = open("ip_management", "r")
    for line in file:
        b = line.split(".")
        b1 = int(b[0])
        b2 = int(b[1])
        b3 = int(b[2])
        b4 = int(b[3])
        if b1 > min1:
            min1 = b1
            min2 = 0
            min3 = 0
            min4 = 1
        if b2 > min2:
            min2 = b2
            min3 = 0
            min4 = 1
        if b3 > min3:
            min3 = b3
            min4 = 1
        if b4 > min4:
            min4 = b4
    file.close()

    # Case of last IP in range (.255), new subrange. Else, assigned ip is last IP + 1
    if min4 == 255:
        min3 = min3+1
        min4 = 1
    else:
        min4 = min4+1
    ip = str(min1)+"."+str(min2)+"."+str(min3)+"."+str(min4)

    # Save assigned IP as in usage
    file = open("ip_management", "a")
    file.write(ip+"\n")
    file.close()
    return ip"""

def get_next_IP_available_2():
    ip_range = '0.0.0.0/0'
    with open("/etc/wireguard/wg0.conf", "r") as confi:
        for line in confi:
            if "Address =" in line:
                ip_range = line.split("= ")[1]

    ip_range = ip_range.rstrip()
    if ip_range.split("/")[1] == "24":
        ip = ip_range.split(".")
        ip_range = ip[0]+"."+ip[1]+"."+ip[2]+".0/24"
    elif ip_range.split("/")[1] == "16":
        ip = ip_range.split(".")
        ip_range = ip[0]+"."+ip[1]+".0.0/16"
    elif ip_range.split("/")[1] == "8":
        ip = ip_range.split(".")
        ip_range = ip[0]+"."+"0.0.0/8"

    network = IPv4Network(ip_range)
    IP_reserved = []

    file = open("ip_management", "r")
    for line in file:
        IP_reserved.append(line.rstrip())
    file.close()

    first_IP_available = (host for host in network.hosts() if str(host) not in IP_reserved)

    assigned_ip = next(first_IP_available)

    # Save assigned IP as in usage
    file = open("ip_management", "a")
    file.write(str(assigned_ip)+"\n")
    file.close()
    return str(assigned_ip)

def liberate_free_ip(ip_vpn):
    file = open("ip_management","r")
    line_ip = 0
    for num, line in enumerate(file, 1):
        if ip_vpn in line:
            line_ip = num
    os.system("sudo sed -i '"+str(line_ip+1)+"d' ip_management")

# Returns the number, in order, of the gateway to be connected.
# n in added in one per gateway connected to as a client.
def get_n_gateway():
    file = open("n_gateway", mode="r")
    n_gateway = int(file.read())
    file.close()
    return n_gateway

def set_n_gateway(n):
    file = open("n_gateway", mode="w")
    file.write(str(n))
    file.close()

# Stores n_gate with the server ip and port to be consulted when deleting
# the connection.
def store_interface_server_association(n_gate, server_ip, server_port):
    file = open("interface_server_associations", mode="a")
    file.write(str(n_gate) + ":" + str(server_ip) + ":" + str(server_port) + "\n")
    file.close()

# Stores n_gate with the server_ip and public key to be consulted when deleting
# the connection.
def store_interface_key_association(n_gate, server_ip, public_key):
    file = open("interface_key_associations", mode="a")
    file.write(str(public_key) + ":" + str(n_gate) + ":" + str(server_ip) + "\n")
    file.close()

# Get the n_gate associated with the requested ip and port
def get_interface_server_association(server_ip, server_port):
    with open("interface_server_associations", mode="r") as file:
        for line in file:
            parts = line.split(":")
            server_port = str(server_port).split()
            parts[2] = parts[2].split()
            if server_ip == parts[1] and server_port == parts[2]:
                return int(parts[0])
    return 999999

# Get the public_key associated with the requested server_ip and port
def get_interface_key_association(n_gate, server_ip):
    with open("interface_key_associations", mode="r") as file:
        for line in file:
            parts = line.split(":")
            server_ip = str(server_ip).split()
            parts[2] = parts[2].split()
            if str(n_gate) == parts[1] and server_ip == parts[2]:
                return parts[0]
    return 999999

def get_info_from_NSMM(response):
    global private_key
    global public_key
    global timestamp
    global DID

    # Take environment variable
    load_dotenv()
    key = os.getenv('KEY')

    response = jwt.decode(response, key, algorithms="HS256")
    public_key = response["public_key"]
    private_key = response["private_key"]
    timestamp = response["timestamp"]
    DID = response["DID"]

def check_key_pair(data):
    global secret
    global endpoint_IdM

    header = {"shared-secret": secret, "Content-Type" : "application/json"}
    req = requests.post(endpoint_IdM, data=json.dumps(data).encode("utf-8"), headers=header, timeout=10)

    return req

class installation(Resource):
    def post(self):

        # WireGuard installation
        os.system("sudo add-apt-repository ppa:wireguard/wireguard")
        os.system("sudo apt-get update -y")
        os.system("sudo apt-get install -y wireguard-dkms wireguard-tools linux-headers-$(uname -r) openresolv")

        os.system("sudo apt-get install -y iptables-persistent")
        os.system("sudo systemctl enable netfilter-persistent")

        file = open("/etc/sysctl.conf", "a")
        file.write("net.ipv4.ip_forward=1\n")
        file.close()
        os.system("sudo sysctl -p")

class launch(Resource):
    def post(self):
        global private_key
        global secret
        global endpoint_IdM

        req = request.data.decode("utf-8")
        req = json.loads(req)
        ip_range = req["ip_range"]
        net_interface = req["net_interface"]
        port = req["port"]
        environment = req["environment"]
        endpoint_IdM = req["endpoint_IdM"]

        # Take environment variable
        load_dotenv()
        secret = os.getenv('SHARED_SECRET')
        #endpoint_IdM = "http://172.28.3.153:6800/authentication/operator_key_pair/verify"

        # Generate public/private key pairs and store them
        os.system("umask 077")

        #Two options to enable NXW's team local tests
        if environment == "local":
            os.system("wg genkey | tee private_key | wg pubkey > public_key")
            #os.system("cat private_key | wg pubkey > public_key")
            private_key = get_private_key()
        elif environment == "testbed":
            #get_key_pair_from_IdM(secret)
            get_info_from_NSMM(req["IdM_payload"])

        # Generate server configuration
        config = open("/etc/wireguard/wg0.conf", "w")
        config.write("[Interface]\n")
        config.write("Address = " + ip_range + "\n")
        config.write("SaveConfig = " + str(False) + "\n")
        config.write("ListenPort = " + str(port) + "\n")
        config.write("PrivateKey = " + private_key + "\n")
        config.write(
            "PostUp = " + "iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o " + net_interface + " -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o " + net_interface + " -j MASQUERADE" + "\n")
        config.write(
            "PostDown = " + "iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o " + net_interface + " -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o " + net_interface + " -j MASQUERADE" + "\n")
        config.write("\n\n")
        config.close()

        os.system("sudo wg-quick up wg0")
        os.system("sudo systemctl enable wg-quick@wg0.service")
        # Store VPN port
        set_vpn_port(port)

        # Store interface generated
        set_n_gateway(0)
        file=open("ip_management","w")
        file.write(ip_range.split("/")[0]+"\n")
        file.close()

        # Server rules forwarding
        os.system("sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT")
        os.system("sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT")
        os.system("sudo iptables -A INPUT -p udp -m udp --dport 51820 -m conntrack --ctstate NEW -j ACCEPT")
        os.system("sudo iptables -A INPUT -s %s -p tcp -m tcp -m conntrack --ctstate NEW -j ACCEPT" % ip_range)
        os.system("sudo iptables -A INPUT -s %s -p udp -m udp -m conntrack --ctstate NEW -j ACCEPT" % ip_range)
        os.system("sudo iptables -A FORWARD -i wg0 -o wg0 -m conntrack --ctstate NEW -j ACCEPT")
        os.system("sudo iptables -t nat -A POSTROUTING -o %s -j MASQUERADE" % net_interface)
        os.system("sudo netfilter-persistent save")

class get_configuration(Resource):
    def get(self):
        global public_key

        with open("/etc/wireguard/wg0.conf", "r") as confi:
            for line in confi:
                if "Address =" in line:
                    ip_range = line.split("= ")[1]

        # DID dummy considered, we need to think on the simulated DLT in order to store these information.
        data = {
            "did": "did:5gzorro:dummy12345",
            #"public_key": get_public_key(),
            "public_key": public_key,
            "IP_range": ip_range,
            "vpn_port":get_vpn_port()
        }
        return json.dumps(data)

class add_client(Resource):
    def post(self):
        global public_key
        global endpoint_IdM

        req = request.data.decode("utf-8")
        req = json.loads(req)
        client_public_key = req["client_public_key"]
        destination_IP_range_to_redirect = req["destination_IP_range_to_redirect"]
        environment = req["environment"]

        data = {"did": req["did"], "public_key": req["client_public_key"], "timestamp": req["timestamp"]}

        #Two options to enable NXW's team local tests
        if environment == "testbed":
            verification = check_key_pair(data)

            if verification.status_code == 200:
                assigned_ip = get_next_IP_available_2()
                config = open("/etc/wireguard/wg0.conf", "a")
                config.write("[Peer]\n")
                config.write("PublicKey = " + client_public_key+"\n")
                config.write("AllowedIPs = " + assigned_ip + "/32, "+destination_IP_range_to_redirect+"\n")
                config.write("\n")
                config.close()

                server_public_key = public_key

                vpn_port= get_vpn_port()
                res = {"assigned_ip": assigned_ip, "vpn_port":vpn_port,  "server_public_key": server_public_key}

                # See how to evade interface reboot
                os.system("sudo wg-quick down wg0 && sudo wg-quick up wg0")
                return res
            else:
                print("Incorrect verification",verification, data, endpoint_IdM)
        elif environment == "local":
            assigned_ip = get_next_IP_available_2()
            config = open("/etc/wireguard/wg0.conf", "a")
            config.write("[Peer]\n")
            config.write("PublicKey = " + client_public_key+"\n")
            config.write("AllowedIPs = " + assigned_ip + "/32, "+destination_IP_range_to_redirect+"\n")
            config.write("\n")
            config.close()

            server_public_key = get_public_key()

            vpn_port= get_vpn_port()
            res = {"assigned_ip": assigned_ip, "vpn_port":vpn_port,  "server_public_key": server_public_key}

            # See how to evade interface reboot
            os.system("sudo wg-quick down wg0 && sudo wg-quick up wg0")

            return res

class remove_client(Resource):
    def post(self):
        req = request.data.decode("utf-8")
        req = json.loads(req)
        client_public_key = req["client_public_key"]

        config_line=-100
        ip_vpn = ""
        with open("/etc/wireguard/wg0.conf","r") as file:
            for num, line in enumerate(file, 1):
                if client_public_key in line:
                    config_line = num
                if num == config_line+1:
                    ip_vpn = line.split(" = ")[1]
                    ip_vpn = ip_vpn.split("/")[0]

        if config_line != -100 and ip_vpn != "":
            os.system("sudo sed -i '"+str(config_line+1)+"d' /etc/wireguard/wg0.conf")
            os.system("sudo sed -i '"+str(config_line)+"d' /etc/wireguard/wg0.conf")
            os.system("sudo sed -i '"+str(config_line-1)+"d' /etc/wireguard/wg0.conf")

            liberate_free_ip(ip_vpn)

            # See how to evade interface reboot
            os.system("sudo wg-quick down wg0 && sudo wg-quick up wg0")

            return 200

class connect_to_VPN(Resource):
    def post(self):
        global private_key
        global public_key
        global DID
        global timestamp
        global endpoint_IdM

        req = request.data.decode("utf-8")
        req = json.loads(req)
        ip_address_server = req["ip_address_server"]
        port_server = req["port_server"]
        IP_range_to_redirect = req["IP_range_to_redirect"]
        destination_IP_range_to_redirect = req["destination_IP_range_to_redirect"]
        environment = req["environment"]

        #Two options to enable NXW's team local tests
        if environment == "local":
            client_public_key = get_public_key()
        elif environment == "testbed":
            #Each new connection a new key pair should be employed
            #get_key_pair_from_IdM()
            client_public_key = public_key

        #req = {"client_public_key": client_public_key, "destination_IP_range_to_redirect": destination_IP_range_to_redirect,
               #"environment": environment}
        req = {"client_public_key": client_public_key, "destination_IP_range_to_redirect": destination_IP_range_to_redirect,
               "environment": environment, "did": DID, "timestamp": timestamp}
        headers = {"Content-Type" : "application/json"}
        res = requests.post("http://" + str(ip_address_server) + ":" + str(port_server) + "/add_client",
                            data=json.dumps(req).encode("utf-8"), headers=headers, timeout=10)
        res = json.loads(res.text)
        assigned_ip = res["assigned_ip"]
        server_public_key = res["server_public_key"]
        vpn_port = res["vpn_port"]

        #n_gate = get_n_gateway()
        #n_gate = n_gate + 1
        n_gate = 99999
        interfaces_reserved = []

        try:
            with open("interface_server_associations", "r") as file:
                for line in file:
                    interfaces_reserved.append(str(line.split(":")[0]))
                for x in range(1,10):
                    if str(x) not in interfaces_reserved:
                        n_gate = x
                        break
        except IOError:
            n_gate = 1

        #Two options to enable NXW's team local tests
        if environment == "local":
            client_private_key = get_private_key()
        elif environment == "testbed":
            client_private_key = private_key

        config = open("/etc/wireguard/wg" + str(n_gate) + ".conf", "w")
        config.write("[Interface]\n")
        config.write("Address = " + assigned_ip + "/32\n")
        config.write("PrivateKey = " + client_private_key + "\n")
        config.write("DNS = 8.8.8.8\n\n")
        config.write("[Peer]\n")
        config.write("PublicKey = " + server_public_key + "\n")
        config.write("Endpoint = " + ip_address_server + ":" + str(vpn_port) + "\n")
        config.write("AllowedIPs = "+ IP_range_to_redirect + "\n")
        config.write("\n")
        config.close()

        set_n_gateway(n_gate)

        store_interface_server_association(n_gate, ip_address_server, port_server)
        store_interface_key_association(n_gate,ip_address_server, client_public_key)
        os.system("sudo wg-quick up wg" + str(n_gate))

        return 200

class disconnect_to_VPN(Resource):
    def post(self):
        global public_key

        req = request.data.decode("utf-8")
        req = json.loads(req)
        ip_address_server = req["ip_address_server"]
        port_server = req["port_server"]

        n_gate = get_interface_server_association(ip_address_server, port_server)
        client_public_key = get_interface_key_association(n_gate, ip_address_server)

        req = {"client_public_key": client_public_key}
        res = requests.post("http://" + str(ip_address_server) + ":" + str(port_server) + '/remove_client',
                            data=json.dumps(req).encode("utf-8"))

        if res.status_code == 200:
            os.system("sudo wg-quick down wg" + str(n_gate))
            os.system("rm /etc/wireguard/wg" + str(n_gate) + ".conf")

            config_line = -100
            with open("interface_server_associations","r") as file:
                for num, line in enumerate(file,1):
                    if str(n_gate) in line.split(":")[0]:
                        config_line = num

            if config_line != -100:
                os.system("sudo sed -i '"+str(config_line)+"d' interface_server_associations")

        return 200

def launch_server_REST(port):
    #api.app.run(ssl_context=('cert.pem','key.pem'))
    api.add_resource(installation, '/installation')
    api.add_resource(launch, '/launch')
    api.add_resource(get_configuration, '/get_configuration')
    api.add_resource(add_client, '/add_client')
    api.add_resource(remove_client, '/remove_client')
    api.add_resource(connect_to_VPN, '/connect_to_VPN')
    api.add_resource(disconnect_to_VPN, '/disconnect_to_VPN')
    http_server = WSGIServer(('0.0.0.0', port), app)
    http_server.serve_forever()

if __name__ == "__main__":
    if len(sys.argv)!=2:
        print("Usage: python3 app_api.py [port]")
    else:
        port=int(sys.argv[1])
        launch_server_REST(port)


import csv
import matplotlib.pyplot as plt
import numpy as np

category = []
germany = []
finland = []
italy = []

with open('data/OlympicsWinter.csv') as csvfile:
    reader = csv.reader(csvfile)
    line_count = 0

    for row in reader:
        if line_count is 0:
            category.append(row)
            line_count += 1
        elif row[4] == "GER":
            germany.append([int(row[0]), row[5], row[6], row[7]])
        elif row[4] == "FIN":
            finland.append([int(row[0]), row[5], row[6], row[7]])
            line_count += 1
        elif row[4] == "ITA":
            italy.append([int(row[0]), row[5], row[6], row[7]])
            line_count += 1

silver_1924 = []
silver_1948 = []
silver_1972 = []

# Silver medals in Germany
for medal in germany:
    if medal[0] == 1924 and medal[3] == "Silver":
        silver_1924.append(medal)

    if medal[0] == 1948 and medal[3] == "Silver":
        silver_1948.append(medal)

    if medal[0] == 1972 and medal[3] == "Silver":
        silver_1972.append(medal)

# Silver medals in Finland
for medal in finland:
    if medal[0] == 1924 and medal[3] == "Silver":
        silver_1924.append(medal)

    if medal[0] == 1948 and medal[3] == "Silver":
        silver_1948.append(medal)

    if medal[0] == 1972 and medal[3] == "Silver":
        silver_1972.append(medal)

# Silver medals in Italy
for medal in italy:
    if medal[0] == 1924 and medal[3] == "Silver":
        silver_1924.append(medal)

    if medal[0] == 1948 and medal[3] == "Silver":
        silver_1948.append(medal)

    if medal[0] == 1972 and medal[3] == "Silver":
        silver_1972.append(medal)

print('Silver medals in Germany won from \'1924 to 1972', len(germany))
print('Silver medals in Finland has won since \'1924 to 1972', len(finland))
print('Silver medals in Italy won in \'1924 to 1972', len(italy))

totalSilverMedals = len(germany) + len(finland) + len(italy)

# percentages of three countries for silver medals
germany_pertencage = int(len(germany)) / totalSilverMedals * 100
finland_pertencage = int(len(finland)) / totalSilverMedals * 100
italy_pertencage = int(len(italy)) / totalSilverMedals * 100

print(germany_pertencage, finland_pertencage, italy_pertencage)

print('count', line_count, 'total silver medals:', totalSilverMedals)

# Pie Chart
labels = "Germany", "Finland", "Italy"
sizes = [germany_pertencage, finland_pertencage, italy_pertencage]
colors = ["dimgrey", "darkgrey", "gainsboro"]
explode = (0.1, 0.1, 0.1)

plt.pie(sizes, explode=explode, colors=colors, autopct='%1.1f%%', shadow=True, startangle=140)

plt.axis('equal')
plt.legend(labels, loc=1)
plt.title("SILVER MEDALS WON IN THREE COUNTRIES")
plt.xlabel("Silver Medals from 1924, 1948, and 1972")
plt.show()

# Horizontal bar chart
# Fixing random state for reproducibility
np.random.seed(19680801)

labels = "Germany", "Finland", "Italy"
sizes = [germany_pertencage, finland_pertencage, italy_pertencage]
colors = ["dimgrey", "darkgrey", "gainsboro"]

plt.rcdefaults()
fig, ax = plt.subplots()

y_ind = np.arange(len(labels))
error = np.random.rand(len(labels))
ax.barh(y_ind, sizes, xerr=error, align='center', color=colors)
ax.set_yticks(y_ind)
ax.set_yticklabels(labels)
ax.invert_yaxis()
ax.set_xlabel("Total silver medals in 1924, 1948, and 1972")
ax.set_title("SILVER MEDALS WON IN THREE COUNTRIES")
plt.show()


# %%
from binance import Client
import personal_function as pf
import pandas as pd
import numpy as np
import mplfinance as mpf
from binance.enums import *
import datetime  # For datetime objects
import sys  # To find out the script name (in argv[0])
import backtrader as bt

# %%
client=pf.client()

KlinesType ='SPOT'
symbol ='BTCUSDT'
interval = '4h' # 30m, 4h,8h,12h,3d,1w
start_date ='1 Jan 2011'
end_date = '1 Jan 2021'
#limit = 500
hist_df=pf.historical_data(client,symbol, interval, start_date, end_date, KlinesType)

# %%
training_df=hist_df[0:int((hist_df.shape[0]/2))+1]
training_df.to_csv('{}_training.csv'.format(symbol))
test_df=hist_df[int((hist_df.shape[0]/2))+1:]
test_df.to_csv('{}_test.csv'.format(symbol))

# %%
class MACD(bt.Strategy):
    '''
    This strategy is loosely based on some of the examples from the Van
    K. Tharp book: *Trade Your Way To Financial Freedom*. The logic:

      - Enter the market if:
        - The MACD.macd line crosses the MACD.signal line to the upside
        - The Simple Moving Average has a negative direction in the last x
          periods (actual value below value x periods ago)

     - Set a stop price x times the ATR value away from the close

     - If in the market:

       - Check if the current close has gone below the stop price. If yes,
         exit.
       - If not, update the stop price if the new stop price would be higher
         than the current
    '''

    params = (
        # Standard MACD Parameters
        ('macd1', 12),
        ('macd2', 26),
        ('macdsig', 9),
        ('atrperiod', 14),  # ATR Period (standard)
        ('atrdist', 3.0),   # ATR distance for stop price
        ('smaperiod', 30),  # SMA Period (pretty standard)
        ('dirperiod', 10),  # Lookback period to consider SMA trend direction
    )

    def notify_order(self, order):
        if order.status == order.Completed:
            pass

        if not order.alive():
            self.order = None  # indicate no order is pending

    def __init__(self):
        self.macd = bt.indicators.MACD(self.data,
                                       period_me1=self.p.macd1,
                                       period_me2=self.p.macd2,
                                       period_signal=self.p.macdsig)

        # Cross of macd.macd and macd.signal
        self.mcross = bt.indicators.CrossOver(self.macd.macd, self.macd.signal)

        # To set the stop price
        self.atr = bt.indicators.ATR(self.data, period=self.p.atrperiod)

        # Control market trend
        self.sma = bt.indicators.SMA(self.data, period=self.p.smaperiod)
        self.smadir = self.sma - self.sma(-self.p.dirperiod)

    def start(self):
        self.order = None  # sentinel to avoid operrations on pending order

    def next(self):
        if self.order:
            return  # pending order execution

        if not self.position:  # not in the market
            if self.mcross[0] > 0.0 and self.smadir < 0.0:
                self.order = self.buy()
                pdist = self.atr[0] * self.p.atrdist
                self.pstop = self.data.close[0] - pdist

        else:  # in the market
            pclose = self.data.close[0]
            pstop = self.pstop

            if pclose < pstop:
                self.close()  # stop met - get out
            else:
                pdist = self.atr[0] * self.p.atrdist
                # Update only if greater than
                self.pstop = max(pstop, pclose - pdist)

# %%
if __name__ == '__main__':
    data=bt.feeds.GenericCSVData(
    dataname='{}_training.csv'.format(symbol),
    fromdate=datetime.datetime(2017,8,17,4,0,0),
    todate=datetime.datetime(2019,4,26,8,0,0),
    datetime=1,
    open=2,
    high=3,
    low=4,
    close=5,
    volume=6,
    dtformat=('%Y-%m-%d %H:%M:%S'),
    tmformat=('%H:%M:%S'),
    timeframe=bt.feeds.TimeFrame.Ticks
)
    cerebro = bt.Cerebro()
    cerebro.addstrategy(MACD)
    cerebro.adddata(data)
    cerebro.broker.setcash(100000.0)
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='mysharpe')
    cerebro.addsizer(bt.sizers.SizerFix, stake=30)

    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    thestrats=cerebro.run()
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    thestrat = thestrats[0]
    print('Sharpe Ratio:',  thestrat.analyzers.mysharpe.get_analysis())
    cerebro.plot()


class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        if len(matrix) == 0 or len(matrix[0]) == 0: return 0
        leni,lenj = len(matrix),len(matrix[0])
        maxSide = 0
        temp = [[0]*lenj for _ in range(leni)]
        for i in range(leni):
            for j in range(lenj):
                if matrix[i][j] == '1':
                    if i == 0 or j == 0: temp[i][j] = 1
                    else: temp[i][j] = min(temp[i-1][j],temp[i][j-1],temp[i-1][j-1])+1
                    maxSide = max(maxSide,temp[i][j])
        return maxSide ** 2