#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, Optional

from pilot.model.conversation import conv_templates
from pilot.utils.parameter_utils import BaseParameters

suported_prompt_templates = ",".join(conv_templates.keys())

class WorkerType(str, Enum):
    LLM = "llm"
    TEXT2VEC = "text2vec"

    @staticmethod
    def values():
        return [item.value for item in WorkerType]

@dataclass
class ModelControllerParameters(BaseParameters):
    host: Optional[str] = field(
        default="0.0.0.0", metadata={"help": "Model Controller deploy host"}
    )
    port: Optional[int] = field(
        default=8000, metadata={"help": "Model Controller deploy port"}
    )
    daemon: Optional[bool] = field(
        default=False, metadata={"help": "Run Model Controller in background"}
    )
    log_level: Optional[str] = field(
        default=None,
        metadata={
            "help": "Logging level",
            "valid_values": [
                "FATAL",
                "ERROR",
                "WARNING",
                "WARNING",
                "INFO",
                "DEBUG",
                "NOTSET",
            ],
        },
    )
    log_file: Optional[str] = field(
        default="dbgpt_model_controller.log",
        metadata={
            "help": "The filename to store log",
        },
    )
    tracer_file: Optional[str] = field(
        default="dbgpt_model_controller_tracer.jsonl",
        metadata={
            "help": "The filename to store tracer span records",
        },
    )

@dataclass
class BaseModelParameters(BaseParameters):
    model_name: str = field(metadata={"help": "Model name", "tags": "fixed"})
    model_path: str = field(metadata={"help": "Model path", "tags": "fixed"})

@dataclass
class ModelWorkerParameters(BaseModelParameters):
    worker_type: Optional[str] = field(
        default=None,
        metadata={"valid_values": WorkerType.values(), "help": "Worker type"},
    )
    worker_class: Optional[str] = field(
        default=None,
        metadata={"help": "Model worker class, pilot.model.cluster.DefaultModelWorker"},
    )
    model_type: Optional[str] = field(
        default="huggingface",
        metadata={
            "help": "Model type: huggingface, llama.cpp, proxy and vllm",
            "tags": "fixed",
        },
    )
    host: Optional[str] = field(
        default="0.0.0.0", metadata={"help": "Model worker deploy host"}
    )

    port: Optional[int] = field(
        default=8001, metadata={"help": "Model worker deploy port"}
    )
    daemon: Optional[bool] = field(
        default=False, metadata={"help": "Run Model Worker in background"}
    )
    limit_model_concurrency: Optional[int] = field(
        default=5, metadata={"help": "Model concurrency limit"}
    )
    standalone: Optional[bool] = field(
        default=False,
        metadata={"help": "Standalone mode. If True, embedded Run ModelController"},
    )
    register: Optional[bool] = field(
        default=True, metadata={"help": "Register current worker to model controller"}
    )
    worker_register_host: Optional[str] = field(
        default=None,
        metadata={
            "help": "The ip address of current worker to register to ModelController. If None, the address is automatically determined"
        },
    )
    controller_addr: Optional[str] = field(
        default=None, metadata={"help": "The Model controller address to register"}
    )
    send_heartbeat: Optional[bool] = field(
        default=True, metadata={"help": "Send heartbeat to model controller"}
    )
    heartbeat_interval: Optional[int] = field(
        default=20, metadata={"help": "The interval for sending heartbeats (seconds)"}
    )

    log_level: Optional[str] = field(
        default=None,
        metadata={
            "help": "Logging level",
            "valid_values": [
                "FATAL",
                "ERROR",
                "WARNING",
                "WARNING",
                "INFO",
                "DEBUG",
                "NOTSET",
            ],
        },
    )
    log_file: Optional[str] = field(
        default="dbgpt_model_worker_manager.log",
        metadata={
            "help": "The filename to store log",
        },
    )
    tracer_file: Optional[str] = field(
        default="dbgpt_model_worker_manager_tracer.jsonl",
        metadata={
            "help": "The filename to store tracer span records",
        },
    )

@dataclass
class BaseEmbeddingModelParameters(BaseModelParameters):
    def build_kwargs(self, **kwargs) -> Dict:
        pass

@dataclass
class EmbeddingModelParameters(BaseEmbeddingModelParameters):
    device: Optional[str] = field(
        default=None,
        metadata={
            "help": "Device to run model. If None, the device is automatically determined"
        },
    )

    normalize_embeddings: Optional[bool] = field(
        default=None,
        metadata={
            "help": "Determines whether the model's embeddings should be normalized."
        },
    )

    def build_kwargs(self, **kwargs) -> Dict:
        model_kwargs, encode_kwargs = None, None
        if self.device:
            model_kwargs = {"device": self.device}
        if self.normalize_embeddings:
            encode_kwargs = {"normalize_embeddings": self.normalize_embeddings}
        if model_kwargs:
            kwargs["model_kwargs"] = model_kwargs
        if encode_kwargs:
            kwargs["encode_kwargs"] = encode_kwargs
        return kwargs

@dataclass
class ModelParameters(BaseModelParameters):
    device: Optional[str] = field(
        default=None,
        metadata={
            "help": "Device to run model. If None, the device is automatically determined"
        },
    )
    model_type: Optional[str] = field(
        default="huggingface",
        metadata={
            "help": "Model type: huggingface, llama.cpp, proxy and vllm",
            "tags": "fixed",
        },
    )
    prompt_template: Optional[str] = field(
        default=None,
        metadata={
            "help": f"Prompt template. If None, the prompt template is automatically determined from model path, supported template: {suported_prompt_templates}"
        },
    )
    max_context_size: Optional[int] = field(
        default=4096, metadata={"help": "Maximum context size"}
    )

    num_gpus: Optional[int] = field(
        default=None,
        metadata={
            "help": "The number of gpus you expect to use, if it is empty, use all of them as much as possible"
        },
    )
    max_gpu_memory: Optional[str] = field(
        default=None,
        metadata={
            "help": "The maximum memory limit of each GPU, only valid in multi-GPU configuration"
        },
    )
    cpu_offloading: Optional[bool] = field(
        default=False, metadata={"help": "CPU offloading"}
    )
    load_8bit: Optional[bool] = field(
        default=False, metadata={"help": "8-bit quantization"}
    )
    load_4bit: Optional[bool] = field(
        default=False, metadata={"help": "4-bit quantization"}
    )
    quant_type: Optional[str] = field(
        default="nf4",
        metadata={
            "valid_values": ["nf4", "fp4"],
            "help": "Quantization datatypes, `fp4` (four bit float) and `nf4` (normal four bit float), only valid when load_4bit=True",
        },
    )
    use_double_quant: Optional[bool] = field(
        default=True,
        metadata={"help": "Nested quantization, only valid when load_4bit=True"},
    )
    compute_dtype: Optional[str] = field(
        default=None,
        metadata={
            "valid_values": ["bfloat16", "float16", "float32"],
            "help": "Model compute type",
        },
    )
    trust_remote_code: Optional[bool] = field(
        default=True, metadata={"help": "Trust remote code"}
    )
    verbose: Optional[bool] = field(
        default=False, metadata={"help": "Show verbose output."}
    )

@dataclass
class LlamaCppModelParameters(ModelParameters):
    seed: Optional[int] = field(
        default=-1, metadata={"help": "Random seed for llama-cpp models. -1 for random"}
    )
    n_threads: Optional[int] = field(
        default=None,
        metadata={
            "help": "Number of threads to use. If None, the number of threads is automatically determined"
        },
    )
    n_batch: Optional[int] = field(
        default=512,
        metadata={
            "help": "Maximum number of prompt tokens to batch together when calling llama_eval"
        },
    )
    n_gpu_layers: Optional[int] = field(
        default=1000000000,
        metadata={
            "help": "Number of layers to offload to the GPU, Set this to 1000000000 to offload all layers to the GPU."
        },
    )
    n_gqa: Optional[int] = field(
        default=None,
        metadata={"help": "Grouped-query attention. Must be 8 for llama-2 70b."},
    )
    rms_norm_eps: Optional[float] = field(
        default=5e-06, metadata={"help": "5e-6 is a good value for llama-2 models."}
    )
    cache_capacity: Optional[str] = field(
        default=None,
        metadata={
            "help": "Maximum cache capacity. Examples: 2000MiB, 2GiB. When provided without units, bytes will be assumed. "
        },
    )
    prefer_cpu: Optional[bool] = field(
        default=False,
        metadata={
            "help": "If a GPU is available, it will be preferred by default, unless prefer_cpu=False is configured."
        },
    )

@dataclass
class ProxyModelParameters(BaseModelParameters):
    proxy_server_url: str = field(
        metadata={
            "help": "Proxy server url, such as: https://api.openai.com/v1/chat/completions"
        },
    )

    proxy_api_key: str = field(
        metadata={"tags": "privacy", "help": "The api key of current proxy LLM"},
    )

    proxy_api_base: str = field(
        default=None,
        metadata={
            "help": "The base api address, such as: https://api.openai.com/v1. If None, we will use proxy_api_base first"
        },
    )

    proxy_api_type: Optional[str] = field(
        default=None,
        metadata={
            "help": "The api type of current proxy the current proxy model, if you use Azure, it can be: azure"
        },
    )

    proxy_api_version: Optional[str] = field(
        default=None,
        metadata={"help": "The api version of current proxy the current model"},
    )

    http_proxy: Optional[str] = field(
        default=os.environ.get("http_proxy") or os.environ.get("https_proxy"),
        metadata={"help": "The http or https proxy to use openai"},
    )

    proxyllm_backend: Optional[str] = field(
        default=None,
        metadata={
            "help": "The model name actually pass to current proxy server url, such as gpt-3.5-turbo, gpt-4, chatglm_pro, chatglm_std and so on"
        },
    )
    model_type: Optional[str] = field(
        default="proxy",
        metadata={
            "help": "Model type: huggingface, llama.cpp, proxy and vllm",
            "tags": "fixed",
        },
    )
    device: Optional[str] = field(
        default=None,
        metadata={
            "help": "Device to run model. If None, the device is automatically determined"
        },
    )
    prompt_template: Optional[str] = field(
        default=None,
        metadata={
            "help": f"Prompt template. If None, the prompt template is automatically determined from model path, supported template: {suported_prompt_templates}"
        },
    )
    max_context_size: Optional[int] = field(
        default=4096, metadata={"help": "Maximum context size"}
    )

@dataclass
class ProxyEmbeddingParameters(BaseEmbeddingModelParameters):
    proxy_server_url: str = field(
        metadata={
            "help": "Proxy base url(OPENAI_API_BASE), such as https://api.openai.com/v1"
        },
    )
    proxy_api_key: str = field(
        metadata={
            "tags": "privacy",
            "help": "The api key of the current embedding model(OPENAI_API_KEY)",
        },
    )
    device: Optional[str] = field(
        default=None,
        metadata={"help": "Device to run model. Not working for proxy embedding model"},
    )
    proxy_api_type: Optional[str] = field(
        default=None,
        metadata={
            "help": "The api type of current proxy the current embedding model(OPENAI_API_TYPE), if you use Azure, it can be: azure"
        },
    )
    proxy_api_version: Optional[str] = field(
        default=None,
        metadata={
            "help": "The api version of current proxy the current embedding model(OPENAI_API_VERSION)"
        },
    )
    proxy_backend: Optional[str] = field(
        default="text-embedding-ada-002",
        metadata={
            "help": "The model name actually pass to current proxy server url, such as text-embedding-ada-002"
        },
    )

    proxy_deployment: Optional[str] = field(
        default="text-embedding-ada-002",
        metadata={"help": "Tto support Azure OpenAI Service custom deployment names"},
    )

    def build_kwargs(self, **kwargs) -> Dict:
        params = {
            "openai_api_base": self.proxy_server_url,
            "openai_api_key": self.proxy_api_key,
            "openai_api_type": self.proxy_api_type if self.proxy_api_type else None,
            "openai_api_version": self.proxy_api_version
            if self.proxy_api_version
            else None,
            "model": self.proxy_backend,
            "deployment": self.proxy_deployment
            if self.proxy_deployment
            else self.proxy_backend,
        }
        for k, v in kwargs:
            params[k] = v
        return params

_EMBEDDING_PARAMETER_CLASS_TO_NAME_CONFIG = {
    ProxyEmbeddingParameters: "proxy_openai,proxy_azure"
}

EMBEDDING_NAME_TO_PARAMETER_CLASS_CONFIG = {}

def _update_embedding_config():
    global EMBEDDING_NAME_TO_PARAMETER_CLASS_CONFIG
    for param_cls, models in _EMBEDDING_PARAMETER_CLASS_TO_NAME_CONFIG.items():
        models = [m.strip() for m in models.split(",")]
        for model in models:
            if model not in EMBEDDING_NAME_TO_PARAMETER_CLASS_CONFIG:
                EMBEDDING_NAME_TO_PARAMETER_CLASS_CONFIG[model] = param_cls

_update_embedding_config()


import os
import glob
import time
import subprocess

from rich.live import Live
from rich.table import Table

table = Table()
table.add_column("File Name")
table.add_column("Level")
table.add_column("Difference")

directory = f"{os.getcwd()}\\tests"
python_file = f"{os.getcwd()}\\src\\main.py"

# the default cmd.exe has different env vars than a normal bat file so we need to account to that.
env_vars = {
    "PATHEXT": ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC",
    "PUBLIC": r"C:\Users\Public",
    "COMMONPROGRAMFILES(X86)": r"C:\Program Files (x86)\Common Files",
    "PROGRAMFILES": r"C:\Program Files",
    "PROGRAMFILES(X86)": r"C:\Program Files (x86)",
    "DRIVERDATA": r"C:\Windows\System32\Drivers\DriverData",
    "COMMONPROGRAMFILES": r"C:\Program Files\Common Files",
    "COMMONPROGRAMW6432": r"C:\Program Files\Common Files",
    "COMMONPROGRAMFILES(X86)": r"C:\Program Files (x86)\Common Files",
}

# using this we take the current env vars and update them with the ones we need. (so we also get the good ones that normally work for the user too)
custom_env = os.environ.copy()
custom_env.update(env_vars)

menu = """
1.) Delete all obfuscated files
2.) Obfuscate all files
3.) Run all tests
4.) Delete all obfuscated files in ALL test directories
"""

class RunAll:
    """
    A class that provides methods to delete all files, test all files, check output and run full test sequence.
    This is important because it allows us more control over using somalifuscator over multiple files and cleanup.
    If obfuscated bat files that aren't test files aren't working for you please check to see if these are also all obfuscated correctly.
    If they are please contact K.Dot or Godfather and let them know. Otherwise try changing your code around to make it more simple.
    """

    def __init__(self, *args, **kwargs) -> None:
        choice = input("What would you like to do?\n" + menu + "\n> ")
        choice_list = {
            "1": self.delete_all,
            "2": self.test_all,
            "3": self.full_test_sequence,
            "4": self.delete_all,
        }

        args1 = True if choice == "4" else False

        choice_list[choice](args1)

        return

    def delete_all(self, rec: bool = False, *args, **kwargs) -> None:
        """
        A method that deletes all files with .bat extension in the directory.

        Args:
        - rec (bool): A boolean value that indicates whether to delete files recursively or not. Default is False.

        Returns:
        - None
        """
        remove_endings = ["_obf.bat", ".rar"]
        for root, dirs, files in os.walk(directory, topdown=rec):
            for file in files:
                if any([file.endswith(x) for x in remove_endings]):
                    os.remove(os.path.join(root, file))
        return

    def test_all(self, *args, **kwargs) -> None:
        """
        A method that tests all files with .bat extension in the directory.

        Args:
        - None

        Returns:
        - None
        """
        for file in glob.glob(f"{directory}\\*.bat"):
            os.system(f"python {python_file} -f {file}")
        return

    def check_output(self, file_path, new_file_path, *args, **kwargs):
        """
        A method that checks the output of the file.

        Args:
        - file_path (str): A string that represents the path of the file.
        - new_file_path (str): A string that represents the path of the new file.

        Returns:
        - None
        """
        command1 = f"{file_path} > output1.txt"
        command2 = f"{new_file_path} > output2.txt"

        t1 = subprocess.Popen(command1, shell=True, env=custom_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        t2 = subprocess.Popen(command2, shell=True, env=custom_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        # wait for process to finish
        out1, err1 = t1.communicate()
        out2, err2 = t2.communicate()

        with open("output1.txt", "r", encoding="utf8") as f:
            inside1 = f.read().strip()
        with open("output2.txt", "r", encoding="utf8") as f:
            inside2 = f.read().strip()

        if inside1 == inside2:
            table.add_row(file_path, "[green]Obfuscated Correctly[/green]", "NONE")
        else:
            a = set(inside1.split())
            b = set(inside2.split())

            diff = a.symmetric_difference(b)
            # these next 3 if statements are very important.
            # they check to see if the difference is set() or set([]) or set() (python set is very weird and sometimes works strangly (I also have no idea how it works ngl))
            # If you want to take a deeper look into the output of these commands you can always comment out the os.remove("output1.txt") and check the type files.
            # Also sometimes my obfuscator might put extra spaces in between variables. This is normal and im not too sure why but it's only with echo and doesn't affect
            # the code runtime.
            if diff == "set()" or diff == set():
                table.add_row(file_path, "[green]Obfuscated Correctly[/green]", "NONE")
                return
            # check if diff is type set
            if type(diff) == set:
                if len(diff) == 1:
                    if diff.pop() == "0":
                        table.add_row(file_path, "[green]Obfuscated Correctly[/green]", "NONE")
                        return
                # check if first item is a string
                try:
                    if type(diff.pop()) == str:
                        # check if first 2 letters of first item are numbers
                        if diff.pop()[0:2].isdigit():
                            table.add_row(file_path, "[green]Obfuscated Correctly[/green]", "NONE")
                            return
                except KeyError:
                    pass

            table.add_row(file_path, "[red]Error[/red]", str(diff))

        os.remove("output1.txt")
        os.remove("output2.txt")

        return

    def full_test_sequence(self, *args, **kwargs) -> None:
        """
        A method that runs the full test sequence.

        Args:
        - None

        Returns:
        - None
        """
        os.system("cls")
        with Live(table, refresh_per_second=4) as live:
            location = f"{os.getcwd()}\\tests\\tests_full\\*.bat"
            files = glob.glob(location, recursive=True)
            for file in files:
                file_path = os.path.join(os.getcwd(), file)
                if file.endswith("_obf.bat"):
                    try:
                        os.remove(file_path)
                    except FileNotFoundError:
                        pass
                    continue
                # we need to put .communicate() at the end or it will continue with the code instead of waiting until it finishes.
                subprocess.Popen(f"python {python_file} -f {file_path}", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

                new_file_path = file_path.replace(".bat", "_obf.bat")

                self.check_output(file_path, new_file_path)

                try:
                    os.remove(new_file_path)
                except FileNotFoundError:
                    pass

        time.sleep(3)

        try:
            os.remove("output1.txt")
            os.remove("output2.txt")
        except FileNotFoundError:
            pass

if __name__ == "__main__":
    while True:
        RunAll()
        input("Press any key to continue...")
        os.system("cls")


import os
from Components.config import config, ConfigOnOff, ConfigText, ConfigSelection, ConfigYesNo, ConfigDirectory, ConfigSubsection, ConfigLocations
from .Debug import logger, log_levels

medialist = [n.split()[1] for n in open('/proc/mounts', 'r').readlines() if any(x in n for x in ('vfat', 'ext4', 'ext3', 'ext2', 'fat32', 'fat16', 'ntfs', 'fuseblk')) and 'media' in n]

def listDir(adir):
	cfg_list = []
	try:
		for afile in os.listdir(adir):
			filename, ext = os.path.splitext(afile)
			if ext == ".cfg":
				cfg_list.append(filename)
	except OSError as e:
		logger.error("failed: e: %s", e)
	return cfg_list

search_engines = listDir("/usr/lib/enigma2/python/Plugins/Extensions/Hydra/addons")

def next_search_engine(search_engine):
	i = search_engines.index(search_engine)
	i = i + 1 if i < len(search_engines) - 1 else 0
	return search_engines[i]

class ConfigInit():

	def __init__(self):
		logger.info("...")
		config.plugins.hydra = ConfigSubsection()
		config.plugins.hydra.debug_log_level = ConfigSelection(default="DEBUG", choices=log_levels.keys())
		config.plugins.hydra.autostart = ConfigOnOff(default=False)
		config.plugins.hydra.remember_last_search = ConfigYesNo()
		config.plugins.hydra.last_search = ConfigText(default="Bond")
		config.plugins.hydra.last_positions = ConfigText(default="{}")
		config.plugins.hydra.config_path = ConfigDirectory("/etc/enigma2")
		config.plugins.hydra.config_bookmarks = ConfigLocations(default=medialist + ["/data"])
		config.plugins.hydra.poster_path = ConfigDirectory("/tmp")
		config.plugins.hydra.poster_bookmarks = ConfigLocations(default=medialist + ["/tmp"])
		config.plugins.hydra.search_engine = ConfigSelection(default="demo", choices=search_engines)
		config.plugins.hydra.vpn_start = ConfigOnOff(default=True)
		config.plugins.hydra.vpn_stop = ConfigOnOff(default=True)


import numpy as np
import pandas as pd
import random as rm
import math

def MarkovChainPoint(p):
    prob = np.random.rand()
    if prob <= p:
        Winner = 'Server'
    else:
        Winner = 'Returner'
    return Winner

def MarkovChainGame(p):
    # Initial state does not matter as transition probabilites are the same:
    SPts = 0
    RPts = 0
    while ((SPts < 4) and (RPts < 4)):
        if MarkovChainPoint(p) == 'Server':
            # Point was won by server:
            SPts = SPts + 1
        else:
            # Point was won by returner:
            RPts = RPts + 1
        # Check for 'duece':
        if ((SPts == 3) and (RPts == 3)):
            count = 0
            while (abs(count) != 2):
                if MarkovChainPoint(p) == 'Server':
                    count = count + 1
                else:
                    count = count - 1
            # Check who won the duece battle:
            if count == 2:
                # Server won:
                SPts = SPts + 1
            else:
                RPts = RPts + 1
    # Find out who won:
    if SPts == 4:
        Winner = 'Server'
    else:
        Winner = 'Returner'
    # Return the winner:
    return (Winner)

def MarkovChainSet(pi, pj, FirstServer, FirstTo):
    # Initial state is who is serving first (i or j):
    if (FirstServer == 'i'):
        Serving = 'i'
    else:
        Serving = 'j'
    iGames = 0
    jGames = 0
    while ((iGames < 6) and (jGames < 6)):
        if Serving == 'i':
            # Player A Serving:
            if MarkovChainGame(pi) == 'Server':
                iGames = iGames + 1
            else:
                jGames = jGames + 1

            # Change Server:
            Serving = 'j'
        else:
            # Player B Serving:
            if MarkovChainGame(pj) == 'Returner':
                iGames = iGames + 1
            else:
                jGames = jGames + 1

            # Change Server:
            Serving = 'i'

    # Check for 'tie-breaker':
    if (abs(iGames - jGames) < 2):
        # Play another game:
        if Serving == 'i':
            if MarkovChainGame(pi) == 'Server':
                iGames = iGames + 1
            else:
                jGames = jGames + 1
            Serving == 'j'
        else:
            if MarkovChainGame(pj) == 'Returner':
                iGames = iGames + 1
            else:
                jGames = jGames + 1
            Serving == 'i'

        # Check if a tie-breaker is needed: (set score = 6-6)
        if ((iGames == 6) and (jGames == 6)):
            # A Tie-Breaker is needed:
            Winner = MarkovChainTieBreaker(pi, pj, Serving, FirstTo)
            # Update set score:
            if Winner == 'i':
                iGames = 7
                jGames = 5
            else:
                iGames = 5
                jGames = 7
            # The server needs to be changed for the next set:
            if Serving == 'i':
                Serving = 'j'
            else:
                Serving = 'i'
        else:
            # Won won the 12th game:
            if iGames == 7:
                Winner = 'i'
            else:
                Winner = 'j'
    else:
        # See who won the set:
        if iGames == 6:
            Winner = 'i'
        else:
            Winner = 'j'

    SetScore = [iGames, jGames]
    # Return the winner, set score and player to start serving in the next set:
    return (Winner, SetScore, Serving)

def MarkovChainTieBreaker(pi, pj, Serving, FirstTo):
    # FirstTo tells us if it is a 7 or 10 point tie breaker ("normal" or "super" TB)
    # The person that recieved in the 12th game of the set starts serving
    # The serving goes as follows: (let A = the person with service initially)
    # Player A, Player B, Player B, Player A, Player A, Player B, Player B, Player A, Player A...
    iPoints = 0
    jPoints = 0

    # Perform first point:
    if Serving == 'i':
        if MarkovChainPoint(pi) == 'Server':
            iPoints = iPoints + 1
        else:
            jPoints = jPoints + 1
        Serving = 'j'
    else:
        if MarkovChainPoint(pj) == 'Returner':
            iPoints = iPoints + 1
        else:
            jPoints = jPoints + 1
        Serving = 'i'

    Point = 2
    while ((iPoints < FirstTo) and (jPoints < FirstTo)):
        if Serving == 'i':
            if MarkovChainPoint(pi) == 'Server':
                iPoints = iPoints + 1
            else:
                jPoints = jPoints + 1
        else:
            if MarkovChainPoint(pj) == 'Returner':
                iPoints = iPoints + 1
            else:
                jPoints = jPoints + 1

        # Change server if required:
        if Point % 2 == 1:
            if Serving == 'i':
                Serving = 'j'
            else:
                Serving = 'i'
        Point = Point + 1

    # Check the winner won by at least 2:
    if (abs(iPoints - jPoints) < 2):
        while (abs(iPoints - jPoints) < 2):
            if Serving == 'i':
                if MarkovChainPoint(pi) == 'Server':
                    iPoints = iPoints + 1
                else:
                    jPoints = jPoints + 1
            else:
                if MarkovChainPoint(pj) == 'Returner':
                    iPoints = iPoints + 1
                else:
                    jPoints = jPoints + 1

            # Change server if required:
            if Point % 2 == 1:
                if Serving == 'i':
                    Serving = 'j'
                else:
                    Serving = 'i'
            Point = Point + 1

    # Check who won the tie-breaker:
    if (iPoints > jPoints):
        Winner = 'i'
    else:
        Winner = 'j'
    return Winner

def MarkovChainMatch(pi, pj, FirstServer, FirstToSets, FirstToTB):
    # Initial state does not matter as transition probabilites are the same:
    iSets = 0
    jSets = 0
    SetScores = []
    while ((iSets < FirstToSets) and (jSets < FirstToSets)):
        [Winner, SetScore, Serving] = MarkovChainSet(pi, pj, FirstServer, FirstToTB)
        SetScores.append(SetScore)
        if Winner == 'i':
            iSets = iSets + 1
        else:
            jSets = jSets + 1

        # Update first server for the next set:
        FirstServer = Serving

    # Check who won the Match:
    if iSets == FirstToSets:
        # Server won:
        Winner = 'i'
    else:
        Winner = 'j'

    # Return the winner and Set Scores
    return (Winner, SetScores)


from django.db import models
from product.models import Product

# Create your models here.
class CartItem(models.Model):
	cart = models.ForeignKey('Cart', null=True, blank=True)
	product = models.ForeignKey(Product)
	quantity = models.IntegerField(default=1)
	timestamp = models.DateField(auto_now_add=True)
	line_total = models.DecimalField(default=10.99,max_digits=1000, decimal_places=2)
	def __str__(self):
		try:
			return str(self.cart.id)
		except:
			return self.product.title

class Cart(models.Model):
	#items = models.ManyToManyField(CartItem, null=True, blank=True)
	#products = models.ManyToManyField(Product, null=True, blank=True)
	total = models.DecimalField(max_digits=100, decimal_places=2, default=0.00)
	timestamp = models.DateField(auto_now_add=True)

	def __str__(self):
		return "Cart id: " + str(self.id)


# core modules
import random
import math
import gym
import numpy as np
from gym import spaces
import tensorflow as tf
from itertools import chain, combinations
# import matplotlib.pyplot as plt
from collections import deque
import numpy as np
import matlab
# import matplotlib.pyplot as plt
import matlab.engine
from mat4py import loadmat, savemat
import logging
import h5py

# import subprocess
import os

LINE_VOLTAGE_MAX_LIMIT = 900
LINE_VOLTAGE_MIN_LIMIT = 650
LINE_CURRENT_MAX_LIMIT = 50
LINE_CURRENT_MIN_LIMIT = 2

LINE_CURRENT_RATED = 10
LINE_VOLTAGE_RATED = 750

SAMPLE_TIME = 0.01
TOTAL_SIM_TIME = 8
TOTAL_TIME_STEPS = int(TOTAL_SIM_TIME / SAMPLE_TIME)
REWARD_AMOUNT_COMMON = 100
"""

Custom implementation of openAI Gym environment API ( https://gym.openai.com/docs )

-- > Multi-agent system with each controller as agent

input state : output of each controller's voltage and current
output state : Increase or decrease del_V to the primary droop controller ( Ops of neural network is equivalent to getting all other V and I values and averaging them, passing them through a PI controller and summing them )
obs dim ( dim of input )        :   num_controllers * 3 ( contimuous values )
action_dim ( dim of output )    :   num_controllers * 2 ( since action space is for the whole env and not for single agent ) ( discrete values )

each step runs the simulation till the current time step.
V and I for all agents are taken
only the local V and I are input to each neural network ( no communication )

xval is created as a timeseries to inpout to the sim in reqd format

input to the NN [ state ]   :   ( timestep, v, i )  //
output [ action ]           :   del_V               //  [0 or 1]  ( inc or dec )]

reward is calculated based on voltage and current levels

"""

class Agent():

    def __init__(self, agent_num):

        self.silent = True
        self.v_level_failed= False
        self.i_level_failed= False
        self.vl = 750
        self.il = 10
        self.del_v = 0
        self.del_i = 0
        self.state = np.asarray([0, LINE_VOLTAGE_RATED / LINE_VOLTAGE_RATED, LINE_CURRENT_RATED / LINE_CURRENT_RATED])
        self.input = np.zeros(TOTAL_TIME_STEPS)
        self.input_timeseries = np.stack([np.around(np.linspace(0, 8, TOTAL_TIME_STEPS), 2), self.input],axis=1)

        # if os.path.exists(self.input_file_name):
        #     os.remove(self.input_file_name)
        # else:
        #     logging.debug("not able to remove file...")

        # with open(self.input_file_name, 'w') as f : pass # .close()
        self.input_file_name = "D:\\maddpg_sec_conrtoller\\custom_microgrid\\input_" + str(agent_num) + ".mat"
        savemat(self.input_file_name, {'input_'+str(agent_num) : np.transpose(self.input_timeseries).tolist()})
        # self.check_input_file = h5py.File(self.input_file_name, "r")
        # self.check_input = self.check_input_file.get('input_' + str(agent_num))
        # self.check_input = np.array(self.check_input)
        self.check_input = loadmat(self.input_file_name)
        self.cost = 0
        self.reward = 0

    def reset(self, agent_num):
        self.state = np.asarray([0, LINE_VOLTAGE_RATED / LINE_VOLTAGE_RATED, LINE_CURRENT_RATED / LINE_CURRENT_RATED])
        self.v_level_failed= False
        self.i_level_failed= False
        self.vl = 750
        self.il = 10
        self.del_v = 0
        self.del_i = 0
        self.input = np.zeros(TOTAL_TIME_STEPS)
        self.input_timeseries = np.stack([np.around(np.linspace(0, 8, TOTAL_TIME_STEPS), 2), self.input],axis=1)
        savemat(self.input_file_name, {'input_'+str(agent_num) : np.transpose(self.input_timeseries).tolist()})
        self.check_input = loadmat(self.input_file_name)
        # open(self.input_file_name, 'w').close()

        self.cost = 0
        self.reward = 0

class Make_World():
    def __init__(self, num_agents = 3):
        self.agents = []
        self.dim_phasors = 3    # may come into use later
        self.dim_c = 0          # may come into use later

        logging.debug('init microgrid .... !!')

        for i in range(num_agents):
            logging.debug("agent_ {0}".format (i))

            self.agents.append(Agent(agent_num = i))

    def get_agents(self):
        return self.agents

class SecondaryController(gym.Env) :

    def __init__(self, num_agents = 3,  eng_name = None):

        self.num_agents = num_agents
        self.n = num_agents

        self.action_space = []
        self.observation_space = []
        self.discrete_action_space = True
        self.world = Make_World(num_agents=self.num_agents)
        self.agents = self.world.get_agents()
        logging.debug(len(self.agents))
        self.curr_episode = 0

        self.penalty = 10
        self.del_v = 0
        self.del_i = 0
        self.delta_v_change = 10 # (V) for changes in voltage to be multiplied to NN output
        # self.delta_i_change = 2 # (A)

        self.prev_len = 0
        self.full_signal = []

        self.tim = np.linspace(0, 10, num=TOTAL_TIME_STEPS)
        # self.xval = np.ones((1000, 2), dtype=float)

        # ------ action spaces init ------------
        action_dim = 3 # inc, dec and no change
        for agent in self.agents:
            total_action_space = []
            # physical action space
            if self.discrete_action_space:
                # it can either increase or decrease voltage in steps. Dim = 2
                u_action_space = spaces.Discrete(action_dim) # self.world.dim_phasors *  2
                logging.debug("discrete {0}".format( u_action_space))
                # comm action space : for future work
                c_action_space = spaces.Discrete(self.world.dim_c)
            else:
                # can remove since it is not needed
                u_action_space = spaces.Box(low=LINE_VOLTAGE_MIN_LIMIT, high=LINE_VOLTAGE_MAX_LIMIT, shape=(2,2)) # ,dtype=np.float32
                logging.debug("absas {0}".format(u_action_space))
                c_action_space = spaces.Box(low=0.0, high=1.0, shape=(self.world.dim_c,)) # ,dtype=np.float32

            total_action_space.append(u_action_space)
            logging.debug("asas {0}".format( total_action_space))

            if not agent.silent:
                total_action_space.append(c_action_space)

            # Total action space
            # only for comm case
            # not needed
            if len(total_action_space) > 1:
                # all action spaces are discrete, so simplify to MultiDiscrete action space
                if all([isinstance(act_space, spaces.Discrete) for act_space in total_action_space]):
                    act_space = spaces.MultiDiscrete([[0,act_space.n-1] for act_space in total_action_space])
                else:
                    act_space = spaces.Tuple(total_action_space)
                self.action_space.append(act_space)
            else:
                self.action_space.append(total_action_space[0])

            # -------------------------------------- removed print -----------------------------
            # print(np.asarray(self.action_space).shape)
            # ----------------------------------------------------------------

            # Is this Correct?
            # Voltage and current are observed
            obs_dim = 3
            # should spaces be limited to rated values?
            self.observation_space.append(spaces.Box(low=-np.inf, high=+np.inf, shape=(obs_dim,))) # ,dtype=np.float32
            # ------------------------------------------
            # agent.action.c = np.zeros(self.world.dim_c)

        logging.debug("len act sp : {0}".format(len(self.action_space)))
        logging.debug("len obs sp : {0}".format(len(self.observation_space)))

        # ---------- matlab engine init -------------
        if eng_name is None:
            names = matlab.engine.find_matlab()
            logging.debug(names)
            self.eng = matlab.engine.connect_matlab(names[0])

        logging.debug('succesfully connected\n\n')
        logging.debug('starting controls .. \n\n')

    def step(self, action_n):

        obs_n = []
        reward_n = []
        done_n = []
        info_n = {'n': []}

        # check for init state and start simulation:
        if self.curr_step ==0:
            self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','start',nargout=0)

        if self.time_is_over :
            # raise RuntimeError("Episode is done")
            self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','stop',nargout=0)
            logging.debug("Episode done : {0}".format(self.curr_episode))

        # set action for each agent and
        # advance microgrid state
        ## for i, agent in enumerate(self.agents):
        logging.debug("step : {0}".format(self.curr_step))
        self._set_action(action_n)

        # record observation,reward, done and info for each agent
        for k,agent in enumerate(self.agents):
            obs_n.append(self._get_obs(agent))
            reward_n.append(self._get_reward(agent))
            done_n.append(self._get_done())
            info_n['n'].append(self._get_info())

        if not self.time_is_over:
            self.curr_step += 1
        return obs_n, reward_n, done_n, info_n

    def _get_info(self):
        # not implemented
        # for logging
        return {}

    # advance state by one timestep and also give actions to the agents
    # is action_space reqd ?
    def _set_action(self, action_n):

        # logging.debug("len agents : {0}".format(len(self.agents)))
        # logging.debug(len(action_n))
        # generate inputs for each controller chip
        for i, agent in enumerate(self.agents):

            if np.argmax(action_n[i]) == 0 :
                delv = self.delta_v_change
            elif np.argmax(action_n[i]) == 1:
                delv = -self.delta_v_change
            else:
                delv= 0
            logging.debug("delv ----> : {0}".format(agent.del_v))
            if not self.curr_step >= 800: # TOTAL_TIME_STEPS
                # agent.input_timeseries[self.curr_step +1] = [self.tim[self.curr_step +1], agent.del_v]
                agent.input_timeseries[self.curr_step][1] = agent.del_v

            # write to file :
            savemat(agent.input_file_name, {'input' : np.transpose(agent.input_timeseries).tolist()})
            agent.check_input = loadmat(agent.input_file_name)
            logging.debug("checking the last written voltage : {0}".format(agent.check_input))

        # self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','start',nargout=0)
        # and simulate the microgrid
        # while self.eng.get_param('test_v_control_and_i_control_with_droop_copy','SimulationStatus')!=('stopped' or 'terminating'):
        if self.eng.get_param('test_v_control_and_i_control_with_droop_copy','SimulationStatus')=='paused':
            # Trying changing constant value
            for i, agent in enumerate(self.agents):
                if np.argmax(action_n[i]) == 0:
                    curr_ref = int(self.eng.get_param('test_v_control_and_i_control_with_droop_copy/Vref'+str(i),'Value')) # ,nargout=0)
                    print("0", curr_ref, type(curr_ref))
                    self.eng.set_param('test_v_control_and_i_control_with_droop_copy/Vref'+str(i),'Value',str(curr_ref+1),nargout=0)
                if np.argmax(action_n[i]) == 1:
                    curr_ref = int(self.eng.get_param('test_v_control_and_i_control_with_droop_copy/Vref'+str(i),'Value')) # ,nargout=0)
                    print("1", curr_ref, type(curr_ref))
                    self.eng.set_param('test_v_control_and_i_control_with_droop_copy/Vref'+str(i),'Value',str(curr_ref-1),nargout=0)
                if np.argmax(action_n[i]) == 2:
                    curr_ref = int(self.eng.get_param('test_v_control_and_i_control_with_droop_copy/Vref'+str(i),'Value')) # ,nargout=0)
                    print("2", curr_ref, type(curr_ref))
                    self.eng.set_param('test_v_control_and_i_control_with_droop_copy/Vref'+str(i),'Value',str(curr_ref),nargout=0)

            # ToDo : operations check
            logging.debug("curr step : {0}".format(self.curr_step))
            self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','update',nargout=0) #if you have updated any simulation parameters

            if self.curr_step >= TOTAL_TIME_STEPS : # * SAMPLE_TIME:
                logging.debug("stopping.. : \t self.curr_step : {1}".format(self.curr_step))
                self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','stop',nargout=0)

            self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','continue',nargout=0)

        else:
            self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','stop',nargout=0)
            logging.debug("stopped *************************** error")

        self.full_signal = self.eng.workspace['V_out_1'].get('signals').get('values')

        if self.curr_step <= 0 :
            # return some safe value and wait till the transient settles
            return 0

        # generate inputs to NN
        for i, agent in enumerate(self.agents):
            agent.vl = np.array(self.eng.workspace['V_out_' + str(i)].get('signals').get('values')[-1], dtype=float)[0]
            logging.debug("Vl : {0}".format(agent.vl))
            agent.il = np.array(self.eng.workspace['I_out_' + str(i)].get('signals').get('values')[-1], dtype=float)[0]
            logging.debug("Il : {0}".format(agent.il))

            # not needed
            # agent.vl = agent.vl + action_n[i,0] * self.delta_v_change
            # agent.il = agent.il + action_n[i,1] * self.delta_i_change
            agent.del_v = float(LINE_VOLTAGE_RATED) - agent.vl
            agent.del_i = float(LINE_CURRENT_RATED) - agent.il

            if  agent.vl  <= LINE_VOLTAGE_MIN_LIMIT and agent.vl >=LINE_VOLTAGE_MAX_LIMIT:
                logging.debug("V failed:")
                agent.v_level_failed = True

            if agent.il  <= LINE_CURRENT_MIN_LIMIT and agent.il >=LINE_CURRENT_MAX_LIMIT:
                logging.debug("I failed:")
                agent.i_level_failed = True
        self.prev_len = len(self.full_signal)

    def reset(self):
        self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','stop',nargout=0)

    def render(self):
        return

    def _get_reward(self, agent):

        if not(agent.v_level_failed) and not(agent.i_level_failed):
            agent.cost = agent.del_v *  self.penalty + agent.del_i * self.penalty
        elif agent.v_level_failed and not(agent.i_level_failed):
            agent.cost = 100 + agent.del_i * self.penalty
        elif agent.i_level_failed and not(agent.v_level_failed):
            agent.cost = agent.del_v * self.penalty + 100
        else:
            agent.cost = 200
        agent.reward = -agent.cost + REWARD_AMOUNT_COMMON

        return agent.reward

    def _get_obs(self, agent):

        agent.state = np.zeros(3)
        if not self.time_is_over:
            agent.state[0] =  self.curr_step+1
        else:
            agent.state[0] =  0
        agent.state[1] =  agent.vl / LINE_VOLTAGE_RATED
        agent.state[2] =  agent.il / LINE_CURRENT_RATED
        # ---------------------------------------- remove print -------------------------------
        logging.debug("state : {0}".format(agent.state))
        # ---------------------------------------------------------
        return agent.state

    def _get_done(self):

        remaining_steps = TOTAL_TIME_STEPS - self.curr_step+1
        self.time_is_over = (remaining_steps <= 0)

        return self.time_is_over

    def _get_initial_state(self):

        self.curr_episode += 1

        self.time_is_over = False
        self.total_rew = 0
        self.curr_step = 0
        self.prev_len = 0
        self.del_v = 0
        self.del_i = 0

        # self.agents = [Agent() for i in range(self.num_agents) ]
        for agent_num, agent in enumerate(self.agents):
            agent.reset(agent_num)

        initial_state_batch = [agent.state for agent in self.agents]

        return initial_state_batch

        # ---------------------------------- old set action ------------------------------------

    #     def _set_action(self, action_n):

    #     print("len agents : ", len(self.agents))
    #     print(len(action_n))
    #     # generate inputs for each controller chip
    #     for i, agent in enumerate(self.agents):

    #         if np.argmax(action_n[i]) == 0 :
    #             delv = self.delta_v_change
    #         elif np.argmax(action_n[i]) == 1:
    #             delv = -self.delta_v_change
    #         else:
    #             delv= 0

    #         # print(agent.input.shape)
    #         # print(np.full((TOTAL_TIME_STEPS - self.prev_len), delv).shape)
    #         agent.input[self.prev_len : ]=np.full((TOTAL_TIME_STEPS - self.prev_len), delv)

    #         agent.input_timeseries = np.stack([self.tim, agent.input], axis=1)
    #         agent.input_timeseries = matlab.double(agent.input_timeseries.tolist())
    #         self.eng.workspace['input_' + str(i)] = agent.input_timeseries

    #     self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','start',nargout=0)

    #     # and simulate the microgrid
    #     j=0
    #     while self.eng.get_param('test_v_control_and_i_control_with_droop_copy','SimulationStatus')!=('stopped' or 'terminating'):
    #         if self.eng.get_param('test_v_control_and_i_control_with_droop_copy','SimulationStatus')=='paused':
    #             # operations check
    # #             print('%f  : %f' ,prev_len, len(self.eng.workspace['ScopeData'].get('signals').get('values')))
    # #             print(self.eng.workspace['ScopeData'].get('signals').get('values')) # [prev_len:]

    #             # print("j : ", j)
    #             # print("curr step : ", self.curr_step)

    #             self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','update',nargout=0) #if you have updated any simulation parameters

    #             if j >= self.curr_step : # * SAMPLE_TIME:
    #                 print("stopping.. : ", j, " : step : ", self.curr_step)
    #                 self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','stop',nargout=0)

    #             self.eng.set_param('test_v_control_and_i_control_with_droop_copy','SimulationCommand','continue',nargout=0)

    #             j+=1

    #     self.full_signal = self.eng.workspace['V_out_1'].get('signals').get('values')

    #     if self.curr_step <= 0 :
    #         # return some safe value and wait till the transient settles
    #         return 0

    #     # generate inputs to NN
    #     for i, agent in enumerate(self.agents):

    #         agent.vl = np.array(self.eng.workspace['V_out_' + str(i)].get('signals').get('values')[-1], dtype=float)[0]
    #         print("Vl : ", agent.vl)
    #         agent.il = np.array(self.eng.workspace['I_out_' + str(i)].get('signals').get('values')[-1], dtype=float)[0]

    #         print("Il : ", agent.il)

    #         # not needed
    #         # agent.vl = agent.vl + action_n[i,0] * self.delta_v_change
    #         # agent.il = agent.il + action_n[i,1] * self.delta_i_change

    #         agent.del_v = float(LINE_VOLTAGE_RATED) - agent.vl
    #         agent.del_i = float(LINE_CURRENT_RATED) - agent.il

    #         if not (agent.vl  <= LINE_VOLTAGE_MAX_LIMIT) and not (agent.vl >=LINE_VOLTAGE_MIN_LIMIT):
    #             print("V failed:")
    #             agent.v_level_failed = True

    #         if not (agent.il  <= LINE_CURRENT_MAX_LIMIT) and not (agent.il >=LINE_CURRENT_MIN_LIMIT):
    #             print("I failed:")
    #             agent.i_level_failed = True

    #     self.prev_len = len(self.full_signal)


import swagger_client
from swagger_client import FileBlobStoreApiCreateRequest, HostedStorageAttributes, DockerHostedRepositoryApiRequest, \
    HelmHostedRepositoryApiRequest
from swagger_client import DockerAttributes

from swagger_storage import SwaggerStorage

class SwaggerRepositories:
    api_client = None
    swagger_storage = None

    def __init__(self, api_client: swagger_client.api_client, swagger_storage: SwaggerStorage):
        self.api_client = api_client
        self.swagger_storage = swagger_storage

    def list_repositories(self):
        repository_api = swagger_client.RepositoriesApi(self.api_client)
        repositories = repository_api.get_repositories1()

        for repo in repositories:
            print('Your repo name is---> ', repo.name)
            print('Your repo type is---> ', repo.format)
            print('Your repo type is---> ', repo.type)
            print('Your repo url is---> ', repo.url)

    def get_all_repositories(self):
        repository_api = swagger_client.RepositoriesApi(self.api_client)
        results = repository_api.get_repositories1()
        return results

    def get_repositories(self, repo_format, repo_type):
        repositories = self.get_all_repositories()
        if len(repositories) == 0:
            return []
        filtered_list = [x for x in repositories if x.format == repo_format and x.type == repo_type]
        return filtered_list

    def get_repository(self, repo_name):
        repositories = self.get_all_repositories()
        if len(repositories) == 0:
            return []
        filtered_list = [x for x in repositories if x.name == repo_name]
        if len(filtered_list) == 0:
            return None
        return filtered_list[0]

    def is_repo(self, name):
        repository = self.get_repository(name)
        if repository:
            return True
        else:
            return False

    def delete_repository(self, name):
        if not self.is_repo(name):
            return;
        repository_api = swagger_client.RepositoryManagementApi(self.api_client)
        repository_api.delete_repository(name)

    def create_docker_hosted_repository(self, docker_blob_store_name, docker_repo_name):
        if self.is_repo(docker_repo_name):
            return;
        if not self.swagger_storage.is_blob_store(docker_blob_store_name):
            self.swagger_storage.create_blob_store(docker_blob_store_name)

        repository_api = swagger_client.RepositoryManagementApi(self.api_client)
        docker_attributes = DockerAttributes(https_port=8085,
                                             force_basic_auth=True,
                                             v1_enabled=True)

        docker_blob_store_attributes = HostedStorageAttributes(
            blob_store_name=docker_blob_store_name,
            strict_content_type_validation=True,
            write_policy="allow_once"
        )

        request = DockerHostedRepositoryApiRequest(name=docker_repo_name,
                                                   storage=docker_blob_store_attributes,
                                                   online=True,
                                                   cleanup=None,
                                                   docker=docker_attributes)

        repository_api.create_repository35(body=request)  # Swagger doesn't define a good name for creating docker
        # repositories

    def create_helm_hosted_repository(self, helm_blob_store_name, helm_repo_name):
        if self.is_repo(helm_repo_name):
            return;
        if not self.swagger_storage.is_blob_store(helm_blob_store_name):
            self.swagger_storage.create_blob_store(helm_blob_store_name)

        repository_api = swagger_client.RepositoryManagementApi(self.api_client)

        helm_storage_attributes = HostedStorageAttributes(
            blob_store_name=helm_blob_store_name,
            strict_content_type_validation=True,
            write_policy="allow_once"
        )

        request = HelmHostedRepositoryApiRequest(name=helm_repo_name,
                                                 storage=helm_storage_attributes,
                                                 online=True,
                                                 cleanup=None)

        repository_api.create_repository9(body=request)  # Swagger doesn't define a good name for creating helm
        # repositories


# -*- coding: utf-8 -*-
"""
Created on Mon Apr 16 08:28:01 2018

@author: Chastine
"""

from keras.models import Sequential, load_model
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers.normalization import BatchNormalization
from keras.callbacks import ModelCheckpoint, TensorBoard, EarlyStopping
from keras import backend as K
from keras.engine.topology import Layer, InputSpec
from keras.preprocessing.image import ImageDataGenerator
from keras.utils import to_categorical
import matplotlib.pyplot as plt
from imutils import paths
import numpy as np
import os
import cv2
from PIL import Image
from PIL import ImageEnhance
from PIL.Image import core as _imaging
from quiver_engine import server

value_shift = 0.1
value_range = 0.2
rotation_degree = 20

train_set = '../dataset/image/training_set/'

test_set = '../dataset/image/test_set/'

original_set = '../dataset/image/original/'

train_set_augmented_zca = '../dataset/image/training_set_augmented_zca/'

#train_set = original_set

file_to_write = open('log.txt', mode='w+')

dirs = next(os.walk(train_set))[1]

classes = dirs
num_classes = len(dirs)

total_train_set = 0
current_index = 0

for subdir in dirs:
    image_total_per_dir = len([name for name in os.listdir(train_set + subdir)])
    total_train_set = total_train_set + image_total_per_dir

x_train = np.empty([total_train_set, 64, 64, 3], dtype = 'uint8')

y_train = np.empty([total_train_set, 1], dtype = 'uint8')

for index_dir, subdir in enumerate(dirs):
    image_total_per_dir = len([name for name in os.listdir(train_set + subdir)])
    for subdir, dirs, files in os.walk(train_set + subdir):
        for index_file, file in enumerate(files):
            complete_filepath = subdir + os.sep + file
            image = Image.open(complete_filepath)
            if image.format != 'JPG':
                image = image.convert('RGB')
            image_as_array = np.asarray(image)
            image_array_resized = cv2.resize(image_as_array, (64,64), interpolation = cv2.INTER_AREA)
            x_train[current_index] = image_array_resized
            y_train[current_index] = index_dir
            current_index = current_index + 1
        print('Loaded ' + subdir + ' folder into array.')

y_train = to_categorical(y_train, num_classes = num_classes)

dirs = next(os.walk(test_set))[1]
num_classes = len(dirs)

total_test_set = 0
current_index = 0

for subdir in dirs:
    image_total_per_dir = len([name for name in os.listdir(test_set + subdir)])
    total_test_set = total_test_set + image_total_per_dir

x_test = np.empty([total_test_set, 64, 64, 3], dtype = 'uint8')

y_test = np.empty([total_test_set, 1], dtype = 'uint8')

for index_dir, subdir in enumerate(dirs):
    image_total_per_dir = len([name for name in os.listdir(test_set + subdir)])

    for subdir, dirs, files in os.walk(test_set + subdir):
        for index_file, file in enumerate(files):
            complete_filepath = subdir + os.sep + file
            image = Image.open(complete_filepath)
            if image.format != 'JPG':
                image = image.convert('RGB')
            image_as_array = np.asarray(image)
            image_array_resized = cv2.resize(image_as_array, (64,64), interpolation = cv2.INTER_AREA)
            x_test[current_index] = image_array_resized
            y_test[current_index] = index_dir
            current_index = current_index + 1
        print('Loaded ' + subdir + ' folder into array.')

y_test = to_categorical(y_test, num_classes = num_classes)

key_classes = dict((index, category) for index, category in enumerate(classes))

augmented_flow = dict((index, []) for index, category in enumerate(classes))

#train_datagen = ImageDataGenerator(rescale = 1./255,
#                                  shear_range = value_range,
#                                  zoom_range = value_range,
#                                  rotation_range = rotation_degree,
#                                  width_shift_range = value_shift,
#                                  height_shift_range = value_shift,
#                                  horizontal_flip = True,
#                                  samplewise_center = True,
#                                  samplewise_std_normalization = True)
#
#train_datagen = ImageDataGenerator(samplewise_center = True,
#                                   samplewise_std_normalization = True)
#
#test_datagen = ImageDataGenerator(samplewise_center = True,
#                                   samplewise_std_normalization = True)

train_datagen = ImageDataGenerator(zca_whitening = True)

test_datagen = ImageDataGenerator(zca_whitening = True)

#train_datagen = ImageDataGenerator(zca_whitening = True)

#test_datagen = ImageDataGenerator(rescale = 1./255,
#                                  shear_range = value_range,
#                                  zoom_range = value_range,
#                                  rotation_range = rotation_degree,
#                                  width_shift_range = value_shift,
#                                  height_shift_range = value_shift,
#                                  horizontal_flip = True,
#                                  samplewise_center = True,
#                                  samplewise_std_normalization = True)

print('Fitting x_train')
train_datagen.fit(x_train)

print('Fitting x_test')
test_datagen.fit(x_test)
training_set = train_datagen.flow(x_train, y_train, shuffle = False)

test_set = test_datagen.flow(x_test, y_test, shuffle = False)

#training_set = train_datagen.flow_from_directory('../dataset/image/original',
#                                                 target_size = (227, 227),
#                                                 batch_size = 32,
#                                                 class_mode = 'categorical')
#test_set = test_datagen.flow(x_test, y_test)

#generated_x, generated_y = training_set.next()

#generated_x = (generated_x * 255 / np.max(generated_x)).astype('uint8')

counter_data = [0] * num_classes
limit_each_category = 500
limit_data_augmented = limit_each_category * num_classes

data_created = 0

flag = 1

x_train_zca = np.empty([0, 64, 64, 3])
y_train_zca = np.empty([0, 6])

for generated_x, generated_y in training_set:
    flag = 1
    x_train_zca = np.append(x_train_zca, generated_x, axis = 0)
    y_train_zca = np.append(y_train_zca, generated_y, axis = 0)
    count = [sum(x) for x in zip(*generated_y)]
    count = [int(x) for x in count]
    for index, c in enumerate(count):
        counter_data[index] = counter_data[index] + c
    data_created = data_created + len(generated_x)
    print(data_created)
    for amount in counter_data:
        if amount < limit_each_category:
            flag = 0
    if flag == 1:
        break

counter_data = [0] * num_classes
limit_each_category = 500
limit_data_augmented = limit_each_category * num_classes

data_created = 0

flag = 1

x_test_zca = np.empty([0, 64, 64, 3])
y_test_zca = np.empty([0, 6])

for generated_x, generated_y in test_set:
    flag = 1
    x_test_zca = np.append(x_test_zca, generated_x, axis = 0)
    y_test_zca = np.append(y_test_zca, generated_y, axis = 0)
    count = [sum(x) for x in zip(*generated_y)]
    count = [int(x) for x in count]
    for index, c in enumerate(count):
        counter_data[index] = counter_data[index] + c
    data_created = data_created + len(generated_x)
    print(data_created)
    for amount in counter_data:
        if amount < limit_each_category:
            flag = 0
    if flag == 1:
        break

#training_set = (x_train, y_train)
#test_set = (x_test, y_test)

#train_set_augmented = '../dataset/image/training_set_augmented_zca/'
#
#test_set_augmented = '../dataset/image/test_set_augmented_zca/'
#
#counter_data = [0] * num_classes
#limit_each_category = 5000
#limit_data_augmented = limit_each_category * num_classes
#
#data_created = 0
#
#flag = 1
#
#for generated_x, generated_y in training_set:
#    flag = 1
#    for index in range(0, len(generated_x)):
#        image_to_save = generated_x[index]
#        image_to_save = (image_to_save * 255 / np.max(image_to_save)).astype('uint8')
#        image_to_save = Image.fromarray(image_to_save)
#        index_highest = np.argmax(generated_y[index])
#        cat_highest = str(key_classes[index_highest])
#        directory_to_save = train_set_augmented + cat_highest
#        if not os.path.exists(directory_to_save):
#            os.makedirs(directory_to_save)
#        if(counter_data[index_highest] < 5000):
#            image_to_save.save(train_set_augmented + cat_highest + '/' + cat_highest + '_' + str(counter_data[index_highest]) + '.png')
#            counter_data[index_highest] = counter_data[index_highest] + 1
#            data_created = data_created + 1
#            print(data_created)
#    for amount in counter_data:
#        if amount < 5000:
#            flag = 0
#    if flag == 1:
#        break

#fig = plt.figure(figsize = (10, 10))
##
#columns = 5
#rows = 5

#arr_uint8 = x_generated[0]
#arr_uint8 = (arr_uint8 * 255 / np.max(arr_uint8)).astype('uint8')
#img = Image.fromarray(arr_uint8)
#img.save('test.png')

#for i in range(1, columns * rows + 1):
#    image = generated_x[i]
#    fig.add_subplot(rows, columns, i)
#    plt.imshow(image)
#
#plt.show()

#classifier.fit(x_train, y_train, validation_data = (x_test, y_test), epochs = 50, callbacks = callbacks)

#classifier = Sequential()
#classifier.add(Conv2D(16, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(Conv2D(16, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(MaxPooling2D(pool_size = (2, 2), strides = 2))
#classifier.add(Conv2D(32, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(Conv2D(32, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(MaxPooling2D(pool_size = (2, 2), strides = 2))
#classifier.add(Conv2D(64, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(Conv2D(64, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(MaxPooling2D(pool_size = (2, 2), strides = 2))
#classifier.add(Conv2D(128, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(Conv2D(128, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(MaxPooling2D(pool_size = (2, 2), strides = 2))
#classifier.add(Conv2D(128, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(Conv2D(128, (3, 3), strides = 1, input_shape = (227, 227, 3), padding = 'same', activation = 'relu'))
#classifier.add(MaxPooling2D(pool_size = (2, 2), strides = 2))
#classifier.add(Flatten())
#classifier.add(Dense(units = 1024, activation = 'relu'))
#classifier.add(Dense(units = 1024, activation = 'relu'))
#classifier.add(Dense(units = num_classes, activation = 'softmax'))
#classifier.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])
#classifier.fit(x_train_zca, y_train_zca, epochs = 50)


l = [3, 1, 4, 2, 2, 1]

def partition_rec(l, i, totalSum, calculatedSum):
    if i < 0:
        return abs((totalSum-calculatedSum) - calculatedSum)

    return min(partition_rec(l, i-1, totalSum, calculatedSum),
               partition_rec(l, i-1, totalSum, calculatedSum+l[i])
               )

def partition(l):
    print(partition_rec(l, len(l)-1, sum(l), 0))

partition(l)

for _ in range(int(input())):
	s = input()
	l = []
	for i in range(len(s)):
		for j in range(i, len(s)):
			l.append(s[i: j+1])
	l.sort()
	for i in l:
		print(''.join(i))


from collections import deque
import random

import gym
import numpy as np
import tensorflow as tf

EPSILON_DECAY = 0.99
EPSILON_MIN = 0.1
BATCH_SIZE = 50

class CartPoleAgent:
    def __init__(self, environment):
        self.state_dim = environment.observation_space.shape
        self.action_dim = environment.action_space.n
        self.q_network: QNetwork = QNetwork(self.state_dim, self.action_dim)
        self.gamma = 0.95
        self.epsilon = 0.99
        self.replay_buffer = ReplayBuffer(maxlen=10000)
        self.buffer_size = BATCH_SIZE

    def get_action(self, state):
        if np.random.rand() < self.epsilon:
            return env.action_space.sample()
        q_vals = self.q_network.evaluate(np.array([state]))
        action = np.argmax(q_vals)
        return action

    def train_with_replay(self, state, action, next_state, reward, done):
        self.replay_buffer.add((state, action, next_state, reward, done))

        samples = self.replay_buffer.sample(min(self.buffer_size, BATCH_SIZE))
        states, actions, next_states, rewards, dones = samples
        states.append(state)
        states = np.array(states)

        actions.append(action)
        next_states.append(next_state)
        rewards.append(reward)
        dones.append(done)

        q_next_states = self.q_network.evaluate(next_states)
        q_next_states[dones] = np.zeros(self.action_dim)  # if done then set to 0
        q_target = reward + self.gamma * np.max(q_next_states, axis=1)
        one_hot_action = tf.one_hot(actions, depth=self.action_dim)

        with tf.GradientTape() as tape:
            q_values = self.q_network.model(states)
            extracted = tf.reduce_sum(tf.multiply(q_values, one_hot_action), axis=1)
            loss = tf.reduce_sum((extracted - q_target) ** 2)

        grads = tape.gradient(loss, self.q_network.model.trainable_variables)
        self.q_network.minimizer.apply_gradients(list(zip(grads, self.q_network.model.trainable_variables)))

        if done:
            self.epsilon = max(EPSILON_MIN, EPSILON_DECAY * self.epsilon)

    def train(self, state, action, next_state, reward, done):

        q_next_states = self.q_network.evaluate([next_state])
        q_next_states[[done]] = np.zeros(self.action_dim)  # if done then set to 0
        q_target = reward + self.gamma * np.max(q_next_states, axis=1)
        one_hot_action = tf.one_hot([action], depth=self.action_dim)

        with tf.GradientTape() as tape:
            q_values = self.q_network.model(np.array([state]))
            extracted = tf.reduce_sum(tf.multiply(q_values, one_hot_action), axis=1)
            loss = tf.reduce_sum((extracted - q_target) ** 2)

        grads = tape.gradient(loss, self.q_network.model.trainable_variables)
        self.q_network.minimizer.apply_gradients(list(zip(grads, self.q_network.model.trainable_variables)))

        if done:
            self.epsilon = max(EPSILON_MIN, EPSILON_DECAY * self.epsilon)

class ReplayBuffer:
    def __init__(self, maxlen):
        self.buffer = deque(maxlen=maxlen)

    def add(self, experience):
        self.buffer.append(experience)

    def sample(self, batch_size):
        sample_size = min(len(self.buffer), batch_size)

        samples = random.choices(self.buffer, k=sample_size)

        return list(map(list, zip(*samples)))

class QNetwork:
    def __init__(self, state_dimension, action_dimension):
        model = tf.keras.models.Sequential([
            tf.keras.layers.Dense(120, activation='relu', input_shape=state_dimension),
            tf.keras.layers.Dense(action_dimension)
        ])
        self.model: tf.keras.Model = model
        self.minimizer = tf.optimizers.Adam(learning_rate=1e-3)

    def evaluate(self, states):
        arg = np.array(states)
        return self.model.predict(arg)

if __name__ == '__main__':

    env_names = ['CartPole-v0', 'MountainCar-v0', 'MsPacman-v0', 'Hopper-v2', 'Acrobot-v1']

    env = gym.make(env_names[0])

    env.reset()

    agent = CartPoleAgent(env)
    num_episodes = 500
    for ep in range(num_episodes):
        total_reward = 0
        done = False
        state = env.reset()
        while not done:
            action = agent.get_action(state)
            next_state, reward, done, info = env.step(action)
            # agent.train(state, action, next_state, reward, done)
            agent.train_with_replay(state, action, next_state, reward, done)
            env.render()
            total_reward += reward
            state = next_state

        print(f'episode: {ep}, total reward: {total_reward}')


#coding:utf-8
import re
import time
import queue
import threading

import chardet

from model.book.book import Book

class Book_parser(object):
    def __init__(self):
        # 读取文件, user_id=None, book_path=None
        # 创建队列
        self.Q = queue.Queue()
        def loop():
            while True:
                if self.Q.empty():
                    time.sleep(5)
                else:
                    self.parser(book_info=self.Q.get())

        threading.Thread(target=loop).start()

    def parser(self,book_info=None):
        # 检查文本中的章卷节等结构
        user_id = book_info["user_id"]
        book_id = book_info["book_id"]
        book_path = book_info["book_path"]

        # 打开文件
        with open(book_path,"rb")as f:
            # 读取少量字节做编码测试
            b = f.read(1024)
            encoding = chardet.detect(b)["encoding"]
            if not encoding:
                # 不支持的编码类型
                Book().update_book_status(user_id=user_id,book_id=book_id,book_status=-2)

            else:
                b = b + f.read()
                lines = b.decode(encoding,'ignore')
                c = re.compile(r'\S{1,10}?[章节卷回篇册集话]\s+.{1,31}?\n')
                m = c.findall(lines)
                l = c.split(lines)
                if m and l:
                    del l[0]
                    for i in range(len(m)):
                        title = m[i].replace("\n","")
                        content = l[i]
                        time.sleep(0.05)
                        Book().new_chapter(book_id=book_id,chapter_index=i,chapter_title=title,chapter_content=content)
                    # 解析完成
                    Book().update_book_status(user_id=user_id,book_id=book_id,book_status=1)
                else:
                    # 正则匹配失败
                    Book().update_book_status(user_id=user_id,book_id=book_id,book_status=-1)


# coding:utf-8
import json

import requests
import urllib3
from operation.user import get_edit_user_info

url = "https://dev-api.banco.com.sg"
url_A = "/ucenter/user/login"
header = {
    "content-type": "application/json; charset=utf-8",
    "Platform": "app.banco.com.sg",
}
data = {

}
params = {
    "receiver_cid":"Nm7FHNF483YQyt53RQsGM",
    "category_id":"1",
    "page":"1",
    "limit":"10"
}
urlC = 'https://dev-api.banco.com.sg/ucenter/document/dpo/list'

urlB = url + url_A
print(urlB)
res = requests.post(url=urlB,headers=header,json=data)
print(res.cookies)
data = get_edit_user_info(token = res.cookies)
resA = requests.get(url=urlC,params=params,cookies=res.cookies,headers=header)
print(resA.json())


import numpy as np
import skvideo.io
import skimage.io
from collections import namedtuple
import gco

def cPixel(x, y):
    return Pixel(x=x, y=y)
def cCoord(i, j):
    return Coord(i=i, j=j)

Pixel = namedtuple("Pixel", "x,y")
Label = namedtuple("Label", "start,period")
Coord = namedtuple("Coord", "i,j")

filename = "assets/marine_01-5s-300x200.mp4"
vid = skvideo.io.vread(filename,
                       outputdict={"-pix_fmt": "gray"})[:, :, :, 0]
T, M, N = vid.shape
M, N = 8, 10
width = N

def id_to_loc(id):
    if id < 0: raise Exception("ID must be >= 0")
    key = id
    return cCoord(key // width, key % width)

def loc_to_id(loc):
    i, j = loc
    return i*width + j

out_img_c = np.empty((M,N,3), dtype="uint8")
out_img_g = np.empty((M,N),  dtype="float")
max_id = M * N
def get_color(id):
    RGBint = id / max_id
    # RGBint *= 255**3
    RGBint *= 255
    RGBint = int(RGBint)
    blue = RGBint & 255
    green = (RGBint >> 8) & 255
    red = (RGBint >> 16) & 255
    red = 255
    return [red, green, blue]

###############################################################################
# Unit Tests, of sorts, to make sure mapping works as intended
###############################################################################

assert id_to_loc(0).i == 0
assert id_to_loc(0).j == 0

assert id_to_loc(1).i == 0
assert id_to_loc(1).j == 1

true_id = 0
for i in range(M):
    for j in range(N):
        here = cCoord(i, j)
        got_id = loc_to_id(here)

        assert got_id == true_id

        got_loc = id_to_loc(true_id)
        assert got_loc.i == i
        assert got_loc.j == j

        out_img_c[i, j] = get_color(got_id)
        out_img_g[i, j] = got_id / max_id

        true_id += 1

gc = gco.GCO()
# M*N nodes in graph, and start frame from 0..period
gc.create_general_graph(M*N, 5)
for i in range(M):
    for j in range(N):
        here = cCoord(i, j)
        down = cCoord(i+1, j)
        rite = cCoord(i, j+1)
        idh = loc_to_id(here)
        idd = loc_to_id(down)
        idr = loc_to_id(rite)
        if i < M-1:
            # Add neighbor below us
            gc.set_neighbor_pair(idh, idd, 1)
        if j < N-1:
            # Add neighbor to the right of us
            gc.set_neighbor_pair(idh, idr, 1)

# Uncomment to make gradient images. Must be small size (~ 10x30) to see them well.
# skimage.io.imsave("labels-c.png", out_img_c)
# print("------------")
# skimage.io.imsave("labels-g.png", out_img_g)


#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
import argparse
import cfgparser
from cfgparser import cfg, shared
import getpass
import time
import os
import pwd
import sys
import toml

def main(args):
    # Import here since the modules need to be imported based on args
    import statuses
    status_config = statuses.StatusConfig(
        status_loc=args.database_loc,
        status_table=shared.status_tablename
    )
    status = statuses.get_status(
        pwd.getpwnam(args.username).pw_uid,
        status_config=status_config
    )
    timeout = float("inf")
    if statuses.lookup_is_penalty(status.current):
        timeout = statuses.lookup_status_prop(status.current).timeout
    timeleft = timeout - (time.time() - status.timestamp)
    # Cannot cast inf to int
    timeleft = int(timeleft) if timeleft != float("inf") else timeleft
    properties = {
        "Status": status.current,
        "Time Left": f"{timeleft}{'s' if timeleft != float('inf') else ''}",
        "Penalty Occurrences": status.occurrences,
        "Default Status": status.default,
    }
    print(format_properties(properties))

def format_properties(properties):
    """
    Returns user readable status string.
    """
    return "\n".join(
        [f"{name + ':':<20}{val:>10}" for name, val in properties.items()]
    )

def configure(args):
    """
    Configures the program so that it can function correctly.
    """
    try:
        if not cfgparser.load_config(*args.configs):
            print("There was an issue with the specified configuration (see "
                  "above). You can investigate this with the cfgparser.py "
                  "tool.")
            sys.exit(2)
        if not args.database_loc:
            args.database_loc = cfg.database.log_location + "/" + shared.statusdb_name
    except (TypeError, toml.decoder.TomlDecodeError) as err:
        print("Configuration error:", str(err), file=sys.stderr)
        sys.exit(2)

def append(context):
    """
    Appends a path to into the python path.
    """
    context_path = os.path.dirname(__file__)
    sys.path.insert(0, os.path.abspath(os.path.join(context_path, context)))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Arbiter status reporter")
    parser.add_argument("username",
                        nargs="?",
                        help="Queries the status of the user by username.",
                        default=getpass.getuser(),
                        type=str)
    parser.add_argument("-a", "--arbdir",
                        type=str,
                        help="Sets the directory in which arbiter modules "
                             "are loaded from. Defaults to ../arbiter.",
                        default="/usr/sbin/arbiter",
                        dest="arbdir")
    parser.add_argument("-g", "--config",
                        type=str,
                        nargs="+",
                        default=["/etc/arbiter/config.toml"],
                        help="The configuration files to use. Configs will be "
                             "cascaded together starting at the leftmost (the "
                             "primary config) going right (the overwriting "
                             "configs).",
                        dest="configs")
    parser.add_argument("-d", "--database",
                        type=str,
                        help="Pulls from the specified database. Defaults "
                             "to the location specified in the configuration.",
                        dest="database_loc")
    args = parser.parse_args()
    append(args.arbdir)  # Pull from the specified arbiter/ directory
    configure(args)
    main(args)


#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2006-2010 (ita)

"""
This tool is totally deprecated

Try using:
	.pc.in files for .pc files
	the feature intltool_in - see demos/intltool
	make-like rules
"""

import shutil, re, os
from waflib import TaskGen, Node, Task, Utils, Build, Errors
from waflib.TaskGen import feature, after_method, before_method
from waflib.Logs import debug

def copy_attrs(orig, dest, names, only_if_set=False):
	"""
	copy class attributes from an object to another
	"""
	for a in Utils.to_list(names):
		u = getattr(orig, a, ())
		if u or not only_if_set:
			setattr(dest, a, u)

def copy_func(tsk):
	"Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"
	env = tsk.env
	infile = tsk.inputs[0].abspath()
	outfile = tsk.outputs[0].abspath()
	try:
		shutil.copy2(infile, outfile)
	except (OSError, IOError):
		return 1
	else:
		if tsk.chmod: os.chmod(outfile, tsk.chmod)
		return 0

def action_process_file_func(tsk):
	"Ask the function attached to the task to process it"
	if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!')
	return tsk.fun(tsk)

@feature('cmd')
def apply_cmd(self):
	"call a command everytime"
	if not self.fun: raise Errors.WafError('cmdobj needs a function!')
	tsk = Task.TaskBase()
	tsk.fun = self.fun
	tsk.env = self.env
	self.tasks.append(tsk)
	tsk.install_path = self.install_path

@feature('copy')
@before_method('process_source')
def apply_copy(self):
	Utils.def_attrs(self, fun=copy_func)
	self.default_install_path = 0

	lst = self.to_list(self.source)
	self.meths.remove('process_source')

	for filename in lst:
		node = self.path.find_resource(filename)
		if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)

		target = self.target
		if not target or len(lst)>1: target = node.name

		# TODO the file path may be incorrect
		newnode = self.path.find_or_declare(target)

		tsk = self.create_task('copy', node, newnode)
		tsk.fun = self.fun
		tsk.chmod = getattr(self, 'chmod', Utils.O644)

		if not tsk.env:
			tsk.debug()
			raise Errors.WafError('task without an environment')

def subst_func(tsk):
	"Substitutes variables in a .in file"

	m4_re = re.compile('@(\w+)@', re.M)

	code = tsk.inputs[0].read() #Utils.readf(infile)

	# replace all % by %% to prevent errors by % signs in the input file while string formatting
	code = code.replace('%', '%%')

	s = m4_re.sub(r'%(\1)s', code)

	env = tsk.env
	di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {})
	if not di:
		names = m4_re.findall(code)
		for i in names:
			di[i] = env.get_flat(i) or env.get_flat(i.upper())

	tsk.outputs[0].write(s % di)

@feature('subst')
@before_method('process_source')
def apply_subst(self):
	Utils.def_attrs(self, fun=subst_func)
	lst = self.to_list(self.source)
	self.meths.remove('process_source')

	self.dict = getattr(self, 'dict', {})

	for filename in lst:
		node = self.path.find_resource(filename)
		if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)

		if self.target:
			newnode = self.path.find_or_declare(self.target)
		else:
			newnode = node.change_ext('')

		try:
			self.dict = self.dict.get_merged_dict()
		except AttributeError:
			pass

		if self.dict and not self.env['DICT_HASH']:
			self.env = self.env.derive()
			keys = list(self.dict.keys())
			keys.sort()
			lst = [self.dict[x] for x in keys]
			self.env['DICT_HASH'] = str(Utils.h_list(lst))

		tsk = self.create_task('copy', node, newnode)
		tsk.fun = self.fun
		tsk.dict = self.dict
		tsk.dep_vars = ['DICT_HASH']
		tsk.chmod = getattr(self, 'chmod', Utils.O644)

		if not tsk.env:
			tsk.debug()
			raise Errors.WafError('task without an environment')

####################
## command-output ####
####################

class cmd_arg(object):
	"""command-output arguments for representing files or folders"""
	def __init__(self, name, template='%s'):
		self.name = name
		self.template = template
		self.node = None

class input_file(cmd_arg):
	def find_node(self, base_path):
		assert isinstance(base_path, Node.Node)
		self.node = base_path.find_resource(self.name)
		if self.node is None:
			raise Errors.WafError("Input file %s not found in " % (self.name, base_path))

	def get_path(self, env, absolute):
		if absolute:
			return self.template % self.node.abspath()
		else:
			return self.template % self.node.srcpath()

class output_file(cmd_arg):
	def find_node(self, base_path):
		assert isinstance(base_path, Node.Node)
		self.node = base_path.find_or_declare(self.name)
		if self.node is None:
			raise Errors.WafError("Output file %s not found in " % (self.name, base_path))

	def get_path(self, env, absolute):
		if absolute:
			return self.template % self.node.abspath()
		else:
			return self.template % self.node.bldpath()

class cmd_dir_arg(cmd_arg):
	def find_node(self, base_path):
		assert isinstance(base_path, Node.Node)
		self.node = base_path.find_dir(self.name)
		if self.node is None:
			raise Errors.WafError("Directory %s not found in " % (self.name, base_path))

class input_dir(cmd_dir_arg):
	def get_path(self, dummy_env, dummy_absolute):
		return self.template % self.node.abspath()

class output_dir(cmd_dir_arg):
	def get_path(self, env, dummy_absolute):
		return self.template % self.node.abspath()

class command_output(Task.Task):
	color = "BLUE"
	def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):
		Task.Task.__init__(self, env=env)
		assert isinstance(command, (str, Node.Node))
		self.command = command
		self.command_args = command_args
		self.stdin = stdin
		self.stdout = stdout
		self.cwd = cwd
		self.os_env = os_env
		self.stderr = stderr

		if command_node is not None: self.dep_nodes = [command_node]
		self.dep_vars = [] # additional environment variables to look

	def run(self):
		task = self
		#assert len(task.inputs) > 0

		def input_path(node, template):
			if task.cwd is None:
				return template % node.bldpath()
			else:
				return template % node.abspath()
		def output_path(node, template):
			fun = node.abspath
			if task.cwd is None: fun = node.bldpath
			return template % fun()

		if isinstance(task.command, Node.Node):
			argv = [input_path(task.command, '%s')]
		else:
			argv = [task.command]

		for arg in task.command_args:
			if isinstance(arg, str):
				argv.append(arg)
			else:
				assert isinstance(arg, cmd_arg)
				argv.append(arg.get_path(task.env, (task.cwd is not None)))

		if task.stdin:
			stdin = open(input_path(task.stdin, '%s'))
		else:
			stdin = None

		if task.stdout:
			stdout = open(output_path(task.stdout, '%s'), "w")
		else:
			stdout = None

		if task.stderr:
			stderr = open(output_path(task.stderr, '%s'), "w")
		else:
			stderr = None

		if task.cwd is None:
			cwd = ('None (actually %r)' % os.getcwd())
		else:
			cwd = repr(task.cwd)
		debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %
			     (cwd, stdin, stdout, argv))

		if task.os_env is None:
			os_env = os.environ
		else:
			os_env = task.os_env
		command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)
		return command.wait()

@feature('command-output')
def init_cmd_output(self):
	Utils.def_attrs(self,
		stdin = None,
		stdout = None,
		stderr = None,
		# the command to execute
		command = None,

		# whether it is an external command; otherwise it is assumed
		# to be an executable binary or script that lives in the
		# source or build tree.
		command_is_external = False,

		# extra parameters (argv) to pass to the command (excluding
		# the command itself)
		argv = [],

		# dependencies to other objects -> this is probably not what you want (ita)
		# values must be 'task_gen' instances (not names!)
		dependencies = [],

		# dependencies on env variable contents
		dep_vars = [],

		# input files that are implicit, i.e. they are not
		# stdin, nor are they mentioned explicitly in argv
		hidden_inputs = [],

		# output files that are implicit, i.e. they are not
		# stdout, nor are they mentioned explicitly in argv
		hidden_outputs = [],

		# change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)
		cwd = None,

		# OS environment variables to pass to the subprocess
		# if None, use the default environment variables unchanged
		os_env = None)

@feature('command-output')
@after_method('init_cmd_output')
def apply_cmd_output(self):
	if self.command is None:
		raise Errors.WafError("command-output missing command")
	if self.command_is_external:
		cmd = self.command
		cmd_node = None
	else:
		cmd_node = self.path.find_resource(self.command)
		assert cmd_node is not None, ('''Could not find command '%s' in source tree.
Hint: if this is an external command,
use command_is_external=True''') % (self.command,)
		cmd = cmd_node

	if self.cwd is None:
		cwd = None

	args = []
	inputs = []
	outputs = []

	for arg in self.argv:
		if isinstance(arg, cmd_arg):
			arg.find_node(self.path)
			if isinstance(arg, input_file):
				inputs.append(arg.node)
			if isinstance(arg, output_file):
				outputs.append(arg.node)

	if self.stdout is None:
		stdout = None
	else:
		assert isinstance(self.stdout, str)
		stdout = self.path.find_or_declare(self.stdout)
		if stdout is None:
			raise Errors.WafError("File %s not found" % (self.stdout,))
		outputs.append(stdout)

	if self.stderr is None:
		stderr = None
	else:
		assert isinstance(self.stderr, str)
		stderr = self.path.find_or_declare(self.stderr)
		if stderr is None:
			raise Errors.WafError("File %s not found" % (self.stderr,))
		outputs.append(stderr)

	if self.stdin is None:
		stdin = None
	else:
		assert isinstance(self.stdin, str)
		stdin = self.path.find_resource(self.stdin)
		if stdin is None:
			raise Errors.WafError("File %s not found" % (self.stdin,))
		inputs.append(stdin)

	for hidden_input in self.to_list(self.hidden_inputs):
		node = self.path.find_resource(hidden_input)
		if node is None:
			raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path))
		inputs.append(node)

	for hidden_output in self.to_list(self.hidden_outputs):
		node = self.path.find_or_declare(hidden_output)
		if node is None:
			raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path))
		outputs.append(node)

	if not (inputs or getattr(self, 'no_inputs', None)):
		raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs')
	if not (outputs or getattr(self, 'no_outputs', None)):
		raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs')

	cwd = self.bld.variant_dir
	task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)
	task.generator = self
	copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)
	self.tasks.append(task)

	task.inputs = inputs
	task.outputs = outputs
	task.dep_vars = self.to_list(self.dep_vars)

	for dep in self.dependencies:
		assert dep is not self
		dep.post()
		for dep_task in dep.tasks:
			task.set_run_after(dep_task)

	if not task.inputs:
		# the case for svnversion, always run, and update the output nodes
		task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run
		task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)

	# TODO the case with no outputs?

def post_run(self):
	for x in self.outputs:
		x.sig = Utils.h_file(x.abspath())

def runnable_status(self):
	return self.RUN_ME

Task.task_factory('copy', vars=[], func=action_process_file_func)