from flask_restx import Namespace, Resource, fields
from flask_jwt_extended import jwt_required, get_jwt_identity
from http import HTTPStatus
from ..models.courses import Course
from ..models.students import Student

course_namespace = Namespace('course', description='name space for course')

course_model = course_namespace.model(
    'Course', {
        'course_id': fields.Integer(description='An ID'),
        'course_code': fields.String(description='course_code'),
        'course_title': fields.String(description='course title'),
        'credit_unit': fields.Integer(description='course unit')
        }
)

@course_namespace.route('/courses')
class CourseGetCreate(Resource):

    @course_namespace.marshal_with(course_model)
    @jwt_required()
    def get(self):
        """
            Get all courses
        """
        courses = Course.query.all()

        return courses, HTTPStatus.OK

    @course_namespace.expect(course_model)
    @course_namespace.marshal_with(course_model)
    @jwt_required()
    def post(self):
        """
            register a course
        """

        name = get_jwt_identity()

        current_student = Student.query.filter_by(name=name).first()

        data = course_namespace.payload

        new_course = Course (
            course_code = data['course_code'],
            course_title = data['course_title'],
            credit_unit = data['credit_unit'],
            teacher_id = data['teacher_id']
        )

        new_course.student = current_student

        new_course.save()

        return new_course, HTTPStatus.CREATED

@course_namespace.route('/course/<int:course_id>')
class GetUpdateDelete(Resource):

    @course_namespace.expect(course_model)
    @course_namespace.marshal_with(course_model)
    @jwt_required()
    def get(self, course_id):
        """
            Retrieve a course by id
        """
        course = Course.get_by_id(course_id)

        return course, HTTPStatus.OK

@course_namespace.route('/course/<int:student_id>/courses')
class StudentCourses(Resource):

    @course_namespace.marshal_list_with(course_model)
    def get(self, student_id):
        """
        Get all Student courses
        """
        student = Student.get_by_id(student_id)

        courses = student.courses

        return courses, HTTPStatus.OK

@course_namespace.route('/student/<int:student_id>/course/<int:course_id>')
class getSpecificCourseByStudent(Resource):

    @course_namespace.marshal_with(course_model)
    def get (self, student_id, course_id):
        """
        Get a student specific course
        """
        student = Student.get_by_id(student_id)

        course = Course.query.filter_by(id=course_id).filter_by(student=student).first()

        return course, HTTPStatus.OK


from __future__ import absolute_import, division, print_function, unicode_literals

# THIS MODULE HAS TO WORK WITH PYTHON 2.7!

import argparse
import errno
import logging
import multiprocessing
import os
import resource
import signal
import subprocess
import sys
import threading
import time
import tempfile
sys.dont_write_bytecode = True # prevent creation of .pyc files

from benchexec import baseexecutor
from benchexec.baseexecutor import BaseExecutor
from benchexec.cgroups import *
from benchexec import oomhandler
from benchexec import systeminfo
from benchexec import util

_WALLTIME_LIMIT_DEFAULT_OVERHEAD = 30 # seconds more than cputime limit
_ULIMIT_DEFAULT_OVERHEAD = 30 # seconds after cgroups cputime limit
_BYTE_FACTOR = 1000 # byte in kilobyte
_LOG_SHRINK_MARKER = "\n\n\nWARNING: YOUR LOGFILE WAS TOO LONG, SOME LINES IN THE MIDDLE WERE REMOVED.\n\n\n\n"
_SUDO_ARGS = ['sudo', '--non-interactive', '-u']

try:
    from subprocess import DEVNULL
except ImportError:
    DEVNULL = open(os.devnull, 'rb')

def main(argv=None):
    """
    A simple command-line interface for the runexecutor module of BenchExec.
    """
    if argv is None:
        argv = sys.argv

    # parse options
    parser = argparse.ArgumentParser(
        fromfile_prefix_chars='@',
        description=
        """Execute a command with resource limits and measurements.
           Command-line parameters can additionally be read from a file if file name prefixed with '@' is given as argument.
           Part of BenchExec: https://github.com/sosy-lab/benchexec/""")

    resource_args = parser.add_argument_group("optional arguments for resource limits")
    resource_args.add_argument("--memlimit", type=util.parse_memory_value, metavar="BYTES",
        help="memory limit in bytes")
    resource_args.add_argument("--timelimit", type=util.parse_timespan_value, metavar="SECONDS",
        help="CPU time limit in seconds")
    resource_args.add_argument("--softtimelimit", type=util.parse_timespan_value, metavar="SECONDS",
        help='"soft" CPU time limit in seconds (command will be send the TERM signal at this time)')
    resource_args.add_argument("--walltimelimit", type=util.parse_timespan_value, metavar="SECONDS",
        help='wall time limit in seconds (default is CPU time limit plus a few seconds)')
    resource_args.add_argument("--cores", type=util.parse_int_list, metavar="N,M-K",
        help="list of CPU cores to use")
    resource_args.add_argument("--memoryNodes", type=util.parse_int_list, metavar="N,M-K",
        help="list of memory nodes to use")

    io_args = parser.add_argument_group("optional arguments for run I/O")
    io_args.add_argument("--input", metavar="FILE",
        help="name of file used as stdin for command "
            "(default: /dev/null; use - for stdin passthrough)")
    io_args.add_argument("--output", default="output.log", metavar="FILE",
        help="name of file where command output is written")
    io_args.add_argument("--maxOutputSize", type=util.parse_memory_value, metavar="BYTES",
        help="shrink output file to approximately this size if necessary "
            "(by removing lines from the middle of the output)")
    io_args.add_argument("--skip-cleanup", action="store_false", dest="cleanup",
        help="do not delete files created by the tool in temp directory")

    environment_args = parser.add_argument_group("optional arguments for run environment")
    environment_args.add_argument("--require-cgroup-subsystem", action="append", default=[], metavar="SUBSYSTEM",
        help="additional cgroup system that should be enabled for runs "
            "(may be specified multiple times)")
    environment_args.add_argument("--set-cgroup-value", action="append", dest="cgroup_values", default=[],
        metavar="SUBSYSTEM.OPTION=VALUE",
        help="additional cgroup values that should be set for runs (e.g., 'cpu.shares=1000')")
    environment_args.add_argument("--dir", metavar="DIR",
        help="working directory for executing the command (default is current directory)")
    environment_args.add_argument("--user", metavar="USER",
        help="execute tool under given user account (needs password-less sudo setup)")

    baseexecutor.add_basic_executor_options(parser)

    options = parser.parse_args(argv[1:])
    baseexecutor.handle_basic_executor_options(options)

    # For integrating into some benchmarking frameworks,
    # there is a DEPRECATED special mode
    # where the first and only command-line argument is a serialized dict
    # with additional options
    env = {}
    if len(options.args) == 1 and options.args[0].startswith("{"):
        data = eval(options.args[0])
        options.args = data["args"]
        env = data.get("env", {})
        options.debug = data.get("debug", options.debug)
        if "maxLogfileSize" in data:
            try:
                options.maxOutputSize = int(data["maxLogfileSize"]) * _BYTE_FACTOR * _BYTE_FACTOR # MB to bytes
            except ValueError:
                options.maxOutputSize = util.parse_memory_value(data["maxLogfileSize"])

    if options.input == '-':
        stdin = sys.stdin
    elif options.input is not None:
        if options.input == options.output:
            sys.exit("Input and output files cannot be the same.")
        try:
            stdin = open(options.input, 'rt')
        except IOError as e:
            sys.exit(e)
    else:
        stdin = None

    cgroup_subsystems = set(options.require_cgroup_subsystem)
    cgroup_values = {}
    for arg in options.cgroup_values:
        try:
            key, value = arg.split("=", 1)
            subsystem, option = key.split(".", 1)
            if not subsystem or not option:
                raise ValueError()
        except ValueError:
            sys.exit('Cgroup value "{}" has invalid format, needs to be "subsystem.option=value".'
                     .format(arg))
        cgroup_values[(subsystem, option)] = value
        cgroup_subsystems.add(subsystem)

    executor = RunExecutor(user=options.user, cleanup_temp_dir=options.cleanup,
                           additional_cgroup_subsystems=list(cgroup_subsystems))

    # ensure that process gets killed on interrupt/kill signal
    def signal_handler_kill(signum, frame):
        executor.stop()
    signal.signal(signal.SIGTERM, signal_handler_kill)
    signal.signal(signal.SIGINT,  signal_handler_kill)

    formatted_args = " ".join(map(util.escape_string_shell, options.args))
    logging.info('Starting command %s', formatted_args)
    logging.info('Writing output to %s', options.output)

    # actual run execution
    try:
        result = executor.execute_run(
                            args=options.args,
                            output_filename=options.output,
                            stdin=stdin,
                            hardtimelimit=options.timelimit,
                            softtimelimit=options.softtimelimit,
                            walltimelimit=options.walltimelimit,
                            cores=options.cores,
                            memlimit=options.memlimit,
                            memory_nodes=options.memoryNodes,
                            cgroupValues=cgroup_values,
                            environments=env,
                            workingDir=options.dir,
                            maxLogfileSize=options.maxOutputSize)
    finally:
        if stdin:
            stdin.close()

    executor.check_for_new_files_in_home()

    # exit_code is a special number:
    exit_code = util.ProcessExitCode.from_raw(result['exitcode'])

    def print_optional_result(key):
        if key in result:
            # avoid unicode literals such that the string can be parsed by Python 3.2
            print(key + "=" + str(result[key]).replace("'u", ''))

    # output results
    print_optional_result('terminationreason')
    print("exitcode=" + str(exit_code.raw))
    if exit_code.value is not None:
        print("returnvalue=" + str(exit_code.value))
    if exit_code.signal is not None:
        print("exitsignal=" + str(exit_code.signal))
    print("walltime=" + str(result['walltime']) + "s")
    print("cputime=" + str(result['cputime']) + "s")
    for key in sorted(result.keys()):
        if key.startswith('cputime-'):
            print("{}={:.9f}s".format(key, result[key]))
    print_optional_result('memory')
    if 'energy' in result:
        for key, value in result['energy'].items():
            print("energy-{0}={1}".format(key, value))

class RunExecutor(BaseExecutor):

    # --- object initialization ---

    def __init__(self, user=None, cleanup_temp_dir=True, additional_cgroup_subsystems=[],
                 *args, **kwargs):
        """
        Create an instance of of RunExecutor.
        @param user None or an OS user as which the benchmarked process should be executed (via sudo).
        @param cleanup_temp_dir Whether to remove the temporary directories created for the run.
        @param additional_cgroup_subsystems List of additional cgroup subsystems that should be required and used for runs.
        """
        super(RunExecutor, self).__init__(*args, **kwargs)
        self._termination_reason = None
        self._user = user
        self._should_cleanup_temp_dir = cleanup_temp_dir
        self._cgroup_subsystems = additional_cgroup_subsystems

        if user is not None:
            # Check if we are allowed to execute 'kill' with dummy signal.
            sudo_check = self._build_cmdline(['kill', '-0', '0'])
            logging.debug('Checking for capability to run with sudo as user %s.', user)
            p = subprocess.Popen(sudo_check, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            try:
                if p.wait():
                    logging.error(
                        'Calling "%s" failed with error code %s and the following output: %s\n%s',
                        ' '.join(sudo_check),
                        p.returncode,
                        p.stdout.read().decode().strip(),
                        p.stderr.read().decode().strip())
                    sys.exit('Cannot execute benchmark as user "{0}", please fix your sudo setup.'.format(user))
            finally:
                p.stdout.close()
                p.stderr.close()

            # Check home directory of user
            try:
                self._home_dir = _get_user_account_info(user).pw_dir
            except (KeyError, ValueError) as e:
                sys.exit('Unknown user {}: {}'.format(user, e))
            try:
                self._home_dir_content = set(self._listdir(self._home_dir))
            except (subprocess.CalledProcessError, IOError):
                # Probably directory does not exist
                self._home_dir_content = []
            if self._home_dir_content:
                logging.warning(
                    'Home directory %s of user %s contains files and/or directories, it is '
                    'recommended to do benchmarks with empty home to prevent undesired influences.',
                    self._home_dir, user)

        self._init_cgroups()

    def _init_cgroups(self):
        """
        This function initializes the cgroups for the limitations and measurements.
        """
        self.cgroups = find_my_cgroups()

        for subsystem in self._cgroup_subsystems:
            self.cgroups.require_subsystem(subsystem)
            if subsystem not in self.cgroups:
                sys.exit('Required cgroup subsystem "{}" is missing.'.format(subsystem))

        self.cgroups.require_subsystem(CPUACCT)
        if CPUACCT not in self.cgroups:
            logging.warning('Without cpuacct cgroups, cputime measurement and limit '
                            'might not work correctly if subprocesses are started.')

        self.cgroups.require_subsystem(FREEZER)
        if FREEZER not in self.cgroups:
            if self._user is not None:
                # In sudo mode, we absolutely need at least one cgroup subsystem
                # to be able to find the process where we need to send signals to
                sys.exit('Cannot reliably kill sub-processes without freezer cgroup,'
                         + ' this is necessary if --user is specified.'
                         + ' Please enable this cgroup or do not specify --user.')
            else:
                logging.warning('Cannot reliably kill sub-processes without freezer cgroup.')

        self.cgroups.require_subsystem(MEMORY)
        if MEMORY not in self.cgroups:
            logging.warning('Cannot measure memory consumption without memory cgroup.')
        else:
            if systeminfo.has_swap() and (
                    not self.cgroups.has_value(MEMORY, 'memsw.max_usage_in_bytes')):
                logging.warning(
                    'Kernel misses feature for accounting swap memory, but machine has swap. '
                    'Memory usage may be measured inaccurately. '
                    'Please set swapaccount=1 on your kernel command line or disable swap with '
                    '"sudo swapoff -a".')

        self.cgroups.require_subsystem(CPUSET)
        self.cpus = None # to indicate that we cannot limit cores
        self.memory_nodes = None # to indicate that we cannot limit cores
        if CPUSET in self.cgroups:
            # Read available cpus/memory nodes:
            try:
                self.cpus = util.parse_int_list(self.cgroups.get_value(CPUSET, 'cpus'))
            except ValueError as e:
                logging.warning("Could not read available CPU cores from kernel: %s", e.strerror)
            logging.debug("List of available CPU cores is %s.", self.cpus)

            try:
                self.memory_nodes = util.parse_int_list(self.cgroups.get_value(CPUSET, 'mems'))
            except ValueError as e:
                logging.warning("Could not read available memory nodes from kernel: %s",
                                e.strerror)
            logging.debug("List of available memory nodes is %s.", self.memory_nodes)

    # --- utility functions ---

    def _build_cmdline(self, args, env={}):
        """
        Build the final command line for executing the given command,
        using sudo if necessary.
        """
        if self._user is None:
            return args
        result = _SUDO_ARGS + [self._user]
        for var, value in env.items():
            result.append(var + '=' + value)
        return result + ['--'] + args

    def _kill_process(self, pid, cgroups=None, sig=signal.SIGKILL):
        """
        Try to send signal to given process, either directly of with sudo.
        Because we cannot send signals to the sudo process itself,
        this method checks whether the target is the sudo process
        and redirects the signal to sudo's child in this case.
        """
        if self._user is not None:
            if not cgroups:
                cgroups = find_cgroups_of_process(pid)
            # In case we started a tool with sudo, we cannot kill the started
            # process itself, because sudo always runs as root.
            # So if we are asked to kill the started process itself (the first
            # process in the cgroup), we instead kill the child of sudo
            # (the second process in the cgroup).
            pids = cgroups.get_all_tasks(FREEZER)
            try:
                if pid == next(pids):
                    pid = next(pids)
            except StopIteration:
                # pids seems to not have enough values
                pass
            finally:
                pids.close()
        self._kill_process0(pid, sig)

    def _kill_process0(self, pid, sig=signal.SIGKILL):
        """
        Send signal to given process, either directly or with sudo.
        If the target is the sudo process itself, the signal will be lost,
        because we do not have the rights to send signals to sudo.
        Use _kill_process() because of this.
        """
        if self._user is None:
            super(RunExecutor, self)._kill_process(pid, sig)
        else:
            logging.debug('Sending signal %s to %s with sudo.', sig, pid)
            try:
                # Cast sig to int, under Python 3.5 the signal.SIG* constants are nums, not ints.
                subprocess.check_call(args=self._build_cmdline(['kill', '-'+str(int(sig)), str(pid)]))
            except subprocess.CalledProcessError as e:
                # may happen for example if process no longer exists
                logging.debug(e)

    def _listdir(self, path):
        """Return the list of files in a directory, assuming that our user can read it."""
        if self._user is None:
            return os.listdir(path)
        else:
            args = self._build_cmdline(['/bin/ls', '-1', path])
            return subprocess.check_output(args, stderr=DEVNULL).decode('utf-8', errors='ignore').split('\n')

    def _set_termination_reason(self, reason):
        if not self._termination_reason:
            self._termination_reason = reason

    # --- setup and cleanup for a single run ---

    def _setup_cgroups(self, my_cpus, memlimit, memory_nodes, cgroup_values):
        """
        This method creates the CGroups for the following execution.
        @param my_cpus: None or a list of the CPU cores to use
        @param memlimit: None or memory limit in bytes
        @param memory_nodes: None or a list of memory nodes of a NUMA system to use
        @param cgroup_values: dict of additional values to set
        @return cgroups: a map of all the necessary cgroups for the following execution.
                         Please add the process of the following execution to all those cgroups!
        """
        logging.debug("Setting up cgroups for run.")

        # Setup cgroups, need a single call to create_cgroup() for all subsystems
        subsystems = [CPUACCT, FREEZER, MEMORY] + self._cgroup_subsystems
        if my_cpus is not None:
            subsystems.append(CPUSET)
        subsystems = [s for s in subsystems if s in self.cgroups]

        cgroups = self.cgroups.create_fresh_child_cgroup(*subsystems)

        logging.debug("Created cgroups %s.", cgroups)

        # First, set user-specified values such that they get overridden by our settings if necessary.
        for ((subsystem, option), value) in cgroup_values.items():
            try:
                cgroups.set_value(subsystem, option, value)
            except EnvironmentError as e:
                cgroups.remove()
                sys.exit('{} for setting cgroup option {}.{} to "{}" (error code {}).'
                         .format(e.strerror, subsystem, option, value, e.errno))
            logging.debug('Cgroup value %s.%s was set to "%s", new value is now "%s".',
                          subsystem, option, value, cgroups.get_value(subsystem, option))

        # Setup cpuset cgroup if necessary to limit the CPU cores/memory nodes to be used.
        if my_cpus is not None:
            my_cpus_str = ','.join(map(str, my_cpus))
            cgroups.set_value(CPUSET, 'cpus', my_cpus_str)
            my_cpus_str = cgroups.get_value(CPUSET, 'cpus')
            logging.debug('Using cpu cores [%s].', my_cpus_str)

        if memory_nodes is not None:
            cgroups.set_value(CPUSET, 'mems', ','.join(map(str, memory_nodes)))
            memory_nodesStr = cgroups.get_value(CPUSET, 'mems')
            logging.debug('Using memory nodes [%s].', memory_nodesStr)

        # Setup memory limit
        if memlimit is not None:
            limit = 'limit_in_bytes'
            cgroups.set_value(MEMORY, limit, memlimit)

            swap_limit = 'memsw.limit_in_bytes'
            # We need swap limit because otherwise the kernel just starts swapping
            # out our process if the limit is reached.
            # Some kernels might not have this feature,
            # which is ok if there is actually no swap.
            if not cgroups.has_value(MEMORY, swap_limit):
                if systeminfo.has_swap():
                    sys.exit('Kernel misses feature for accounting swap memory, but machine has swap. Please set swapaccount=1 on your kernel command line or disable swap with "sudo swapoff -a".')
            else:
                try:
                    cgroups.set_value(MEMORY, swap_limit, memlimit)
                except IOError as e:
                    if e.errno == errno.ENOTSUP: # kernel responds with operation unsupported if this is disabled
                        sys.exit('Memory limit specified, but kernel does not allow limiting swap memory. Please set swapaccount=1 on your kernel command line or disable swap with "sudo swapoff -a".')
                    raise e

            memlimit = cgroups.get_value(MEMORY, limit)
            logging.debug('Effective memory limit is %s bytes.', memlimit)

        if MEMORY in cgroups:
            try:
                # Note that this disables swapping completely according to
                # https://www.kernel.org/doc/Documentation/cgroups/memory.txt
                # (unlike setting the global swappiness to 0).
                # Our process might get killed because of this.
                cgroups.set_value(MEMORY, 'swappiness', '0')
            except IOError as e:
                logging.warning('Could not disable swapping for benchmarked process: %s', e)

        return cgroups

    def _setup_temp_dir(self):
        """Setup the temporary directories for the run.
        @return a triple of base directory, home directory, and temp directory
            (all can be removed after the run)
        """
        if self._user is None:
            base_dir = tempfile.mkdtemp(prefix="BenchExec_run_")
        else:
            create_temp_dir = self._build_cmdline([
                'python', '-c',
                'import tempfile;'
                'print(tempfile.mkdtemp(prefix="BenchExec_run_"))'
                ])
            base_dir = subprocess.check_output(create_temp_dir).decode().strip()
        temp_dir = os.path.join(base_dir, "tmp")
        home_dir = os.path.join(base_dir, "home")
        if self._user is None:
            os.mkdir(temp_dir)
            os.mkdir(home_dir)
        else:
            subprocess.check_call(self._build_cmdline(["mkdir", "--mode=700", temp_dir, home_dir]))

        logging.debug("Executing run with $HOME and $TMPDIR below %s.", base_dir)
        return base_dir, home_dir, temp_dir

    def _cleanup_temp_dir(self, base_dir):
        """Delete given temporary directory and all its contents."""
        if self._should_cleanup_temp_dir:
            logging.debug('Cleaning up temporary directory.')
            if self._user is None:
                util.rmtree(base_dir, onerror=util.log_rmtree_error)
            else:
                rm = subprocess.Popen(self._build_cmdline(['rm', '-rf', '--', base_dir]),
                                      stderr=subprocess.PIPE)
                rm_output = rm.stderr.read().decode()
                rm.stderr.close()
                if rm.wait() != 0 or rm_output:
                    logging.warning("Failed to clean up temp directory %s: %s.",
                                    base_dir, rm_output)
        else:
            logging.info("Skipping cleanup of temporary directory %s.", base_dir)

    def _setup_environment(self, environments, home_dir, temp_dir):
        """Return map with desired environment variables for run."""
        # If keepEnv is set or sudo is used, start from a fresh environment,
        # otherwise with the current one.
        # Set HOME and TMPDIR to the temporary directories create above.
        # keepEnv specifies variables to copy from the current environment,
        # newEnv specifies variables to set to a new value,
        # additionalEnv specifies variables where some value should be appended, and
        # clearEnv specifies variables to delete.
        if self._user is not None or environments.get("keepEnv", None) is not None:
            run_environment = {}
        else :
            run_environment = os.environ.copy()
        run_environment["HOME"] = home_dir
        run_environment["TMPDIR"] = temp_dir
        run_environment["TMP"] = temp_dir
        run_environment["TEMPDIR"] = temp_dir
        run_environment["TEMP"] = temp_dir
        for key, value in environments.get("keepEnv", {}).items():
            if key in os.environ:
                run_environment[key] = os.environ[key]
        for key, value in environments.get("newEnv", {}).items():
            run_environment[key] = value
        for key, value in environments.get("additionalEnv", {}).items():
            run_environment[key] = os.environ.get(key, "") + value
        for key in environments.get("clearEnv", {}).items():
            run_environment.pop(key, None)

        logging.debug("Using additional environment %s.", environments)
        return run_environment

    def _setup_output_file(self, output_filename, args):
        """Open and prepare output file."""
        # write command line into outputFile
        # (without environment variables, they are documented by benchexec)
        try:
            output_file = open(output_filename, 'w') # override existing file
        except IOError as e:
            sys.exit(e)
        output_file.write(' '.join(map(util.escape_string_shell, self._build_cmdline(args)))
                          + '\n\n\n' + '-' * 80 + '\n\n\n')
        output_file.flush()
        return output_file

    def _setup_cgroup_time_limit(self, hardtimelimit, softtimelimit, walltimelimit,
                                 cgroups, cores, pid_to_kill):
        """Start time-limit handler.
        @return None or the time-limit handler for calling cancel()
        """
        # hard time limit with cgroups is optional (additionally enforce by ulimit)
        cgroup_hardtimelimit = hardtimelimit if CPUACCT in cgroups else None

        if any([cgroup_hardtimelimit, softtimelimit, walltimelimit]):
            # Start a timer to periodically check timelimit
            timelimitThread = _TimelimitThread(cgroups=cgroups,
                                               hardtimelimit=cgroup_hardtimelimit,
                                               softtimelimit=softtimelimit,
                                               walltimelimit=walltimelimit,
                                               pid_to_kill=pid_to_kill,
                                               cores=cores,
                                               callbackFn=self._set_termination_reason,
                                               kill_process_fn=self._kill_process)
            timelimitThread.start()
            return timelimitThread
        return None

    def _setup_cgroup_memory_limit(self, memlimit, cgroups, pid_to_kill):
        """Start memory-limit handler.
        @return None or the memory-limit handler for calling cancel()
        """
        if memlimit is not None:
            try:
                oomThread = oomhandler.KillProcessOnOomThread(
                    cgroups=cgroups, pid_to_kill=pid_to_kill,
                    callbackFn=self._set_termination_reason,
                    kill_process_fn=self._kill_process)
                oomThread.start()
                return oomThread
            except OSError as e:
                logging.critical("OSError %s during setup of OomEventListenerThread: %s.",
                                 e.errno, e.strerror)
        return None

    def _setup_ulimit_time_limit(self, hardtimelimit, cgroups):
        """Setup time limit with ulimit for the current process."""
        if hardtimelimit is not None:
            # Also use ulimit for CPU time limit as a fallback if cgroups don't work.
            if CPUACCT in cgroups:
                # Use a slightly higher limit to ensure cgroups get used
                # (otherwise we cannot detect the timeout properly).
                ulimit = hardtimelimit + _ULIMIT_DEFAULT_OVERHEAD
            else:
                ulimit = hardtimelimit
            resource.setrlimit(resource.RLIMIT_CPU, (ulimit, ulimit))

    # --- run execution ---

    def execute_run(self, args, output_filename, stdin=None,
                   hardtimelimit=None, softtimelimit=None, walltimelimit=None,
                   cores=None, memlimit=None, memory_nodes=None,
                   environments={}, workingDir=None, maxLogfileSize=None,
                   cgroupValues={}):
        """
        This function executes a given command with resource limits,
        and writes the output to a file.
        @param args: the command line to run
        @param output_filename: the file where the output should be written to
        @param stdin: What to uses as stdin for the process (None: /dev/null, a file descriptor, or a file object)
        @param hardtimelimit: None or the CPU time in seconds after which the tool is forcefully killed.
        @param softtimelimit: None or the CPU time in seconds after which the tool is sent a kill signal.
        @param walltimelimit: None or the wall time in seconds after which the tool is forcefully killed (default: hardtimelimit + a few seconds)
        @param cores: None or a list of the CPU cores to use
        @param memlimit: None or memory limit in bytes
        @param memory_nodes: None or a list of memory nodes in a NUMA system to use
        @param environments: special environments for running the command
        @param workingDir: None or a directory which the execution should use as working directory
        @param maxLogfileSize: None or a number of bytes to which the output of the tool should be truncated approximately if there is too much output.
        @param cgroupValues: dict of additional cgroup values to set (key is tuple of subsystem and option, respective subsystem needs to be enabled in RunExecutor; cannot be used to override values set by BenchExec)
        @return: dict with result of run (measurement results and process exitcode)
        """
        # Check argument values and call the actual method _execute()

        if stdin == subprocess.PIPE:
            sys.exit('Illegal value subprocess.PIPE for stdin')
        elif stdin is None:
            stdin = DEVNULL

        if hardtimelimit is not None:
            if hardtimelimit <= 0:
                sys.exit("Invalid time limit {0}.".format(hardtimelimit))
        if softtimelimit is not None:
            if softtimelimit <= 0:
                sys.exit("Invalid soft time limit {0}.".format(softtimelimit))
            if hardtimelimit and (softtimelimit > hardtimelimit):
                sys.exit("Soft time limit cannot be larger than the hard time limit.")
            if not CPUACCT in self.cgroups:
                sys.exit("Soft time limit cannot be specified without cpuacct cgroup.")

        if walltimelimit is None:
            if hardtimelimit is not None:
                walltimelimit = hardtimelimit + _WALLTIME_LIMIT_DEFAULT_OVERHEAD
            elif softtimelimit is not None:
                walltimelimit = softtimelimit + _WALLTIME_LIMIT_DEFAULT_OVERHEAD
        else:
            if walltimelimit <= 0:
                sys.exit("Invalid wall time limit {0}.".format(walltimelimit))

        if cores is not None:
            if self.cpus is None:
                sys.exit("Cannot limit CPU cores without cpuset cgroup.")
            if not cores:
                sys.exit("Cannot execute run without any CPU core.")
            if not set(cores).issubset(self.cpus):
                sys.exit("Cores {0} are not allowed to be used".format(list(set(cores).difference(self.cpus))))

        if memlimit is not None:
            if memlimit <= 0:
                sys.exit("Invalid memory limit {0}.".format(memlimit))
            if not MEMORY in self.cgroups:
                sys.exit("Memory limit specified, but cannot be implemented without cgroup support.")

        if memory_nodes is not None:
            if self.memory_nodes is None:
                sys.exit("Cannot restrict memory nodes without cpuset cgroup.")
            if len(memory_nodes) == 0:
                sys.exit("Cannot execute run without any memory node.")
            if not set(memory_nodes).issubset(self.memory_nodes):
                sys.exit("Memory nodes {0} are not allowed to be used".format(list(set(memory_nodes).difference(self.memory_nodes))))

        if workingDir:
            if not os.path.exists(workingDir):
                sys.exit("Working directory {0} does not exist.".format(workingDir))
            if not os.path.isdir(workingDir):
                sys.exit("Working directory {0} is not a directory.".format(workingDir))
            if not os.access(workingDir, os.X_OK):
                sys.exit("Permission denied for working directory {0}.".format(workingDir))

        for ((subsystem, option), _) in cgroupValues.items():
            if not subsystem in self._cgroup_subsystems:
                sys.exit('Cannot set option "{option}" for subsystem "{subsystem}" that is not enabled. '
                         'Please specify "--require-cgroup-subsystem {subsystem}".'.format(
                            option=option, subsystem=subsystem))
            if not self.cgroups.has_value(subsystem, option):
                sys.exit('Cannot set option "{option}" for subsystem "{subsystem}", it does not exist.'
                         .format(option=option, subsystem=subsystem))

        try:
            return self._execute(args, output_filename, stdin,
                                 hardtimelimit, softtimelimit, walltimelimit, memlimit,
                                 cores, memory_nodes,
                                 cgroupValues,
                                 environments, workingDir, maxLogfileSize)

        except OSError as e:
            logging.critical("OSError %s while starting '%s' in '%s': %s.",
                             e.errno, args[0], workingDir or '.', e.strerror)
            return {'terminationreason': 'failed', 'exitcode': 0,
                    'cputime': 0, 'walltime': 0}

    def _execute(self, args, output_filename, stdin,
                 hardtimelimit, softtimelimit, walltimelimit, memlimit,
                 cores, memory_nodes,
                 cgroup_values,
                 environments, workingDir, max_output_size):
        """
        This method executes the command line and waits for the termination of it,
        handling all setup and cleanup, but does not check whether arguments are valid.
        """

        def preParent():
            """Setup that is executed in the parent process immediately before the actual tool is started."""
            # start measurements
            energy_before = util.measure_energy()
            walltime_before = util.read_monotonic_time()
            return (walltime_before, energy_before)

        def postParent(preParent_result):
            """Cleanup that is executed in the parent process immediately after the actual tool terminated."""
            # finish measurements
            walltime_before, energy_before = preParent_result
            walltime = util.read_monotonic_time() - walltime_before
            energy = util.measure_energy(energy_before)
            return (walltime, energy)

        def preSubprocess():
            """Setup that is executed in the forked process before the actual tool is started."""
            os.setpgrp() # make subprocess to group-leader
            os.nice(5) # increase niceness of subprocess
            self._setup_ulimit_time_limit(hardtimelimit, cgroups)

        # preparations that are not time critical
        cgroups = self._setup_cgroups(cores, memlimit, memory_nodes, cgroup_values)
        base_dir, home_dir, temp_dir = self._setup_temp_dir()
        run_environment = self._setup_environment(environments, home_dir, temp_dir)
        outputFile = self._setup_output_file(output_filename, args)
        args = self._build_cmdline(args, env=run_environment)

        timelimitThread = None
        oomThread = None
        pid = None
        returnvalue = 0
        ru_child = None
        self._termination_reason = None

        throttle_check = systeminfo.CPUThrottleCheck(cores)
        swap_check = systeminfo.SwapCheck()

        logging.debug('Starting process.')

        try:
            pid, result_fn = self._start_execution(args=args,
                stdin=stdin, stdout=outputFile, stderr=outputFile,
                env=run_environment, cwd=workingDir,
                cgroups=cgroups,
                parent_setup_fn=preParent, child_setup_fn=preSubprocess,
                parent_cleanup_fn=postParent)

            with self.SUB_PROCESS_PIDS_LOCK:
                self.SUB_PROCESS_PIDS.add(pid)

            timelimitThread = self._setup_cgroup_time_limit(
                hardtimelimit, softtimelimit, walltimelimit, cgroups, cores, pid)
            oomThread = self._setup_cgroup_memory_limit(memlimit, cgroups, pid)

            returnvalue, ru_child, (walltime, energy) = result_fn() # blocks until process has terminated

            result = {}
            result['walltime'] = walltime
            if energy:
                result['energy'] = energy

            # needs to come before cgroups.remove()
            self._get_cgroup_measurements(cgroups, ru_child, result)

        finally:
            # cleanup steps that need to get executed even in case of failure
            logging.debug('Process terminated, exit code %s.', returnvalue)

            with self.SUB_PROCESS_PIDS_LOCK:
                self.SUB_PROCESS_PIDS.discard(pid)

            if timelimitThread:
                timelimitThread.cancel()

            if oomThread:
                oomThread.cancel()

            # Kill all remaining processes if some managed to survive.
            # Because we send signals to all processes anyway we use the
            # internal function.
            cgroups.kill_all_tasks(self._kill_process0)

            # normally subprocess closes file, we do this again after all tasks terminated
            outputFile.close()

            logging.debug("Cleaning up cgroups.")
            cgroups.remove()

            self._cleanup_temp_dir(base_dir)

        # cleanup steps that are only relevant in case of success
        if throttle_check.has_throttled():
            logging.warning('CPU throttled itself during benchmarking due to overheating. '
                            'Benchmark results are unreliable!')
        if swap_check.has_swapped():
            logging.warning('System has swapped during benchmarking. '
                            'Benchmark results are unreliable!')

        _reduce_file_size_if_necessary(output_filename, max_output_size)

        if returnvalue not in [0,1]:
            _get_debug_output_after_crash(output_filename)

        result['exitcode'] = returnvalue
        if self._termination_reason:
            result['terminationreason'] = self._termination_reason
        elif memlimit and 'memory' in result and result['memory'] >= memlimit:
            # The kernel does not always issue OOM notifications and thus the OOMHandler
            # does not always run even in case of OOM. We detect this there and report OOM.
            result['terminationreason'] = 'memory'

        return result

    def _get_cgroup_measurements(self, cgroups, ru_child, result):
        """
        This method calculates the exact results for time and memory measurements.
        It is not important to call this method as soon as possible after the run.
        """
        logging.debug("Getting cgroup measurements.")

        cputime_wait = ru_child.ru_utime + ru_child.ru_stime if ru_child else 0
        cputime_cgroups = None
        if CPUACCT in cgroups:
            # We want to read the value from the cgroup.
            # The documentation warns about outdated values.
            # So we read twice with 0.1s time difference,
            # and continue reading as long as the values differ.
            # This has never happened except when interrupting the script with Ctrl+C,
            # but just try to be on the safe side here.
            tmp = cgroups.read_cputime()
            tmp2 = None
            while tmp != tmp2:
                time.sleep(0.1)
                tmp2 = tmp
                tmp = cgroups.read_cputime()
            cputime_cgroups = tmp

            # Usually cputime_cgroups seems to be 0.01s greater than cputime_wait.
            # Furthermore, cputime_wait might miss some subprocesses,
            # therefore we expect cputime_cgroups to be always greater (and more correct).
            # However, sometimes cputime_wait is a little bit bigger than cputime2.
            # For small values, this is probably because cputime_wait counts since fork,
            # whereas cputime_cgroups counts only after cgroups.add_task()
            # (so overhead from runexecutor is correctly excluded in cputime_cgroups).
            # For large values, a difference may also indicate a problem with cgroups,
            # for example another process moving our benchmarked process between cgroups,
            # thus we warn if the difference is substantial and take the larger cputime_wait value.
            if cputime_wait > 0.5 and (cputime_wait * 0.95) > cputime_cgroups:
                logging.warning(
                    'Cputime measured by wait was %s, cputime measured by cgroup was only %s, '
                    'perhaps measurement is flawed.',
                    cputime_wait, cputime_cgroups)
                result['cputime'] = cputime_wait
            else:
                result['cputime'] = cputime_cgroups

            for (core, coretime) in enumerate(cgroups.get_value(CPUACCT, 'usage_percpu').split(" ")):
                try:
                    coretime = int(coretime)
                    if coretime != 0:
                        result['cputime-cpu'+str(core)] = coretime/1000000000 # nano-seconds to seconds
                except (OSError, ValueError) as e:
                    logging.debug("Could not read CPU time for core %s from kernel: %s", core, e)

        if MEMORY in cgroups:
            # This measurement reads the maximum number of bytes of RAM+Swap the process used.
            # For more details, c.f. the kernel documentation:
            # https://www.kernel.org/doc/Documentation/cgroups/memory.txt
            memUsageFile = 'memsw.max_usage_in_bytes'
            if not cgroups.has_value(MEMORY, memUsageFile):
                memUsageFile = 'max_usage_in_bytes'
            if not cgroups.has_value(MEMORY, memUsageFile):
                logging.warning('Memory-usage is not available due to missing files.')
            else:
                try:
                    result['memory'] = int(cgroups.get_value(MEMORY, memUsageFile))
                except IOError as e:
                    if e.errno == errno.ENOTSUP: # kernel responds with operation unsupported if this is disabled
                        logging.critical(
                            "Kernel does not track swap memory usage, cannot measure memory usage."
                            " Please set swapaccount=1 on your kernel command line.")
                    else:
                        raise e

        logging.debug(
            'Resource usage of run: walltime=%s, cputime=%s, cgroup-cputime=%s, memory=%s',
            result['walltime'], cputime_wait, cputime_cgroups, result.get('memory', None))

    # --- other public functions ---

    def stop(self):
        self._set_termination_reason('killed')
        super(RunExecutor, self).stop()

    def check_for_new_files_in_home(self):
        """Check that the user account's home directory now does not contain more files than
        when this instance was created, and warn otherwise.
        Does nothing if no user account was given to RunExecutor.
        @return set of newly created files
        """
        if not self._user:
            return None
        try:
            created_files = set(self._listdir(self._home_dir)).difference(self._home_dir_content)
        except (subprocess.CalledProcessError, IOError):
            # Probably home directory does not exist
            created_files = []
        if created_files:
            logging.warning('The tool created the following files in %s, '
                            'this may influence later runs:\n\t%s',
                            self._home_dir, '\n\t'.join(created_files))
        return created_files

def _get_user_account_info(user):
    """Get the user account info from the passwd database. Only works on Linux.
    @param user The name of a user account or a numeric uid prefixed with '#'
    @return a tuple that corresponds to the members of the passwd structure
    @raise KeyError: If user account is unknown
    @raise ValueError: If uid is not a valid number
    """
    import pwd # Import here to avoid problems on other platforms
    if user[0] == '#':
        return pwd.getpwuid(int(user[1:]))
    else:
        return pwd.getpwnam(user)

def _reduce_file_size_if_necessary(fileName, maxSize):
    """
    This function shrinks a file.
    We remove only the middle part of a file,
    the file-start and the file-end remain unchanged.
    """
    fileSize = os.path.getsize(fileName)

    if maxSize is None:
        logging.debug("Size of logfile '%s' is %s bytes, size limit disabled.", fileName, fileSize)
        return # disabled, nothing to do

    if fileSize < (maxSize + 500):
        logging.debug("Size of logfile '%s' is %s bytes, nothing to do.", fileName, fileSize)
        return

    logging.warning("Logfile '%s' is too big (size %s bytes). Removing lines.", fileName, fileSize)
    util.shrink_text_file(fileName, maxSize, _LOG_SHRINK_MARKER)

def _get_debug_output_after_crash(output_filename):
    """
    Segmentation faults and some memory failures reference a file
    with more information (hs_err_pid_*). We append this file to the log.
    The format that we expect is a line
    "# An error report file with more information is saved as:"
    and the file name of the dump file on the next line.
    """
    logging.debug("Analysing output for crash info.")
    foundDumpFile = False
    with open(output_filename, 'r+') as outputFile:
        for line in outputFile:
            if foundDumpFile:
                try:
                    dumpFileName = line.strip(' #\n')
                    outputFile.seek(0, os.SEEK_END) # jump to end of log file
                    with open(dumpFileName, 'r') as dumpFile:
                        util.copy_all_lines_from_to(dumpFile, outputFile)
                    os.remove(dumpFileName)
                except IOError as e:
                    logging.warning('Could not append additional segmentation fault information '
                                    'from %s (%s)',
                                    dumpFile, e.strerror)
                break
            try:
                if util.decode_to_string(line).startswith('# An error report file with more information is saved as:'):
                    logging.debug('Going to append error report file')
                    foundDumpFile = True
            except UnicodeDecodeError:
                pass
                # ignore invalid chars from logfile

class _TimelimitThread(threading.Thread):
    """
    Thread that periodically checks whether the given process has already
    reached its timelimit. After this happens, the process is terminated.
    """
    def __init__(self, cgroups, kill_process_fn, hardtimelimit, softtimelimit, walltimelimit, pid_to_kill, cores,
                 callbackFn=lambda reason: None):
        super(_TimelimitThread, self).__init__()

        if hardtimelimit or softtimelimit:
            assert CPUACCT in cgroups
        assert walltimelimit is not None

        if cores:
            self.cpuCount = len(cores)
        else:
            try:
                self.cpuCount = multiprocessing.cpu_count()
            except NotImplementedError:
                self.cpuCount = 1

        self.daemon = True
        self.cgroups = cgroups
        self.timelimit = hardtimelimit or (60*60*24*365*100) # large dummy value
        self.softtimelimit = softtimelimit or (60*60*24*365*100) # large dummy value
        self.latestKillTime = util.read_monotonic_time() + walltimelimit
        self.pid_to_kill = pid_to_kill
        self.callback = callbackFn
        self.kill_process = kill_process_fn
        self.finished = threading.Event()

    def read_cputime(self):
        while True:
            try:
                return self.cgroups.read_cputime()
            except ValueError:
                # Sometimes the kernel produces strange values with linebreaks in them
                time.sleep(1)

    def run(self):
        while not self.finished.is_set():
            usedCpuTime = self.read_cputime() if CPUACCT in self.cgroups else 0
            remainingCpuTime = self.timelimit - usedCpuTime
            remainingSoftCpuTime = self.softtimelimit - usedCpuTime
            remainingWallTime = self.latestKillTime - util.read_monotonic_time()
            logging.debug(
                "TimelimitThread for process %s: used CPU time: %s, remaining CPU time: %s, "
                "remaining soft CPU time: %s, remaining wall time: %s.",
                self.pid_to_kill, usedCpuTime, remainingCpuTime,
                remainingSoftCpuTime, remainingWallTime)
            if remainingCpuTime <= 0:
                self.callback('cputime')
                logging.debug('Killing process %s due to CPU time timeout.', self.pid_to_kill)
                self.kill_process(self.pid_to_kill, self.cgroups)
                self.finished.set()
                return
            if remainingWallTime <= 0:
                self.callback('walltime')
                logging.warning('Killing process %s due to wall time timeout.', self.pid_to_kill)
                self.kill_process(self.pid_to_kill, self.cgroups)
                self.finished.set()
                return

            if remainingSoftCpuTime <= 0:
                self.callback('cputime-soft')
                # soft time limit violated, ask process to terminate
                self.kill_process(self.pid_to_kill, self.cgroups, signal.SIGTERM)
                self.softtimelimit = self.timelimit

            remainingTime = min(remainingCpuTime/self.cpuCount,
                                remainingSoftCpuTime/self.cpuCount,
                                remainingWallTime)
            self.finished.wait(remainingTime + 1)

    def cancel(self):
        self.finished.set()

if __name__ == '__main__':
    main()


n=int(input())
a,b=0,0 #윗칸, 아래칸
ans=0
while not(a==n and b==n): #이동안 계속 해준다.
    if a>b:
        b+=1
    else:
        a+=1
        b=0
    ans += a+b #계속해서 더하기
print(ans)


import random
from operator import itemgetter

import requests
from bs4 import BeautifulSoup
from discord.ext import commands

res_stem = 'https://www.youtube.com/results'
link_stem = 'https://www.youtube.com{}'

def extract_search_res(parsed):

    return [
        t for t in map(itemgetter('href'), parsed.find_all(
            'a', attrs={"aria-hidden": "true"}
        )) if (
            (
                u'doubleclick' not in t
            ) and (
                u'watch' in t
            ) and (
                u'googleadservices' not in t
            )
        )
    ][:20]

def search(query, exact):
    search_payload = {'search_query': query.encode('utf-8')}
    search_resp = requests.get(res_stem, params=search_payload)

    if not search_resp.ok:
        return 'I can\'t into internetz', False
    parsed = BeautifulSoup(search_resp.text, "html.parser")

    # magic
    search_res = extract_search_res(parsed)
    if not search_res:
        return (
            'Somehow, I can\'t find anything; '
            'anyways, here\'s Wonderwall: '
            'https://www.youtube.com/watch?v=bx1Bh8ZvH84'
        ), False
    return link_stem.format(
        search_res[0] if exact else random.choice(search_res)
    ), True

class YoutubeSearches(commands.Cog):

    def __init__(self, bot):
        self.bot = bot

    @commands.command(
        description="Tekin searches youtube given a keyword.",
        help="""
        Usage: @TekinBot youtube [exactly] keyword
        Tekinbot will search youtube with keyword, and return randomly one of
        the top 20 results. If "exactly" was specified, Tekin will always
        return the first result.
        """,
    )
    async def youtube(self, ctx, *keyword):
        exact = keyword[0] == 'exactly'
        query = " ".join(keyword if not exact else keyword[1:])
        query = query if query else ''
        await ctx.send(search(query, exact)[0])

def setup(bot):
    bot.add_cog(YoutubeSearches(bot))


import time
import numpy as np
import matplotlib.pyplot as plt
from torchtext.data.metrics import bleu_score
import pandas as pd
import seaborn as sns
from .metric import bleu as b
from .metric import edit_distance as ed

def calc_time(start_time):
    total = time.time() - start_time
    return int(total/60), int(total%60)

def calcAverage(data, tick, ngram, choice=None, spliter=None):
    if spliter is not None:
        data = spliter(data, tick=tick, choice=choice)
    NUM_DATA, KEYS, BLEU, BLEU_pre, BLEU_bp, EDIT, EDIT_N = [],[],[],[],[],[],[]
    for key, value in sorted(data.items(), key=lambda x: x[0]):
        KEYS.append(str(key*tick))
        NUM_DATA.append(len(value))

        arr = np.array(value)
        bleu_score = b.bleu_corpus(arr[:,1].tolist(), arr[:,2].tolist(), ngram)
        if isinstance(bleu_score, list):
            BLEU_pre.append(bleu_score[0])
            BLEU_bp.append(bleu_score[1])
            BLEU.append(bleu_score[2])
        else:
            BLEU_bp.append(0)
            BLEU_pre.append(0)
            BLEU.append(0)
        start_time = time.time()
        edist = ed.edit_distance_corpus(arr[:,1].tolist(), arr[:,2].tolist())
        EDIT.append(edist[0])
        EDIT_N.append(edist[1])
    return NUM_DATA, KEYS, BLEU, BLEU_pre, BLEU_bp, EDIT, EDIT_N

def get_factors(data):
    num_unks_src = [triple[0].count('<unk>') for triple in data]
    num_unks_ref = [triple[1].count('<<unk>>') for triple in data]
    frac_unks_src = [round(triple[0].count('<unk>')/len(triple[0]),2) for triple in data]
    frac_unks_ref = [round(triple[1].count('<<unk>>')/len(triple[1]),2) for triple in data]
    src_len = [len(triple[0]) for triple in data]
    ref_len = [len(triple[1]) for triple in data]
    return (('Source Length', src_len), \
            ('# Unknowns in Source',num_unks_src), \
            ('% Unknowns in Source', frac_unks_src), \
            ('Refenrence Length', ref_len), \
            ('# Unknowns in Reference', num_unks_ref), \
            ('% Unknowns in Reference', frac_unks_ref))

def get_metrics(data, n_gram):
    assert isinstance(data, np.ndarray), \
        'data should be numpy array with 3 dimension (source, reference, hypothesis)'

    start_time = time.time()
    edit_dists = ed.edit_distance_points(data[:,1].tolist(), data[:,2].tolist())
    min, sec = calc_time(start_time)
    print(f'Edit Distance takes: {min} min {sec} sec')

    start_lime = time.time()
    bleus = b.bleu_points(data[:,1].tolist(), data[:,2].tolist(), n_gram)
    min, sec = calc_time(start_time)
    print(f'BLEU score takes: {min} min {sec} sec')

    edit_dist = [dist[0] for dist in edit_dists]
    edit_dist_norm = [dist[1] for dist in edit_dists]
    bleu_pre = [bleu[0] for bleu in bleus]
    bleu_bp = [bleu[1] for bleu in bleus]
    bleu_score = [bleu[2] for bleu in bleus]
    return (('Edit Distance', edit_dist), \
            ('Normalized Edit Distance', edit_dist_norm), \
            ('Bleu Precision', bleu_pre), \
            ('Bleu Brevity Penalty', bleu_bp), \
            ('Bleu Score', bleu_score))

def plot_factors_hist(factors, nbin):
    for factor in factors:
        max_val = max(factor[1])
        plt.hist(factor[1], bins=nbin)
        plt.title(f'Distribution of {factor[0]} - max={max_val}')
        plt.xlim(0,max_val)
        plt.show()

def plot_metric(metric, factors, xbins=10, remove_zero=False):
    for factor in factors:
        if remove_zero:
            pair = np.array(list(filter(lambda x: x[1]>0, zip(factor[1], metric[1]))))
        else:
            pair = np.array(list(zip(factor[1], metric[1])))
        plt.figure(figsize=(10,6))
        plt.title(f'{metric[0]} with {factor[0]}')
        plt.scatter(pair[:,0], pair[:,1], color='green')

def plot_scatter_line(metrics_scatter, factor_scatter, metrics_line, factor_line, xlim, remove_zero=False):
    for metric_scatter, metric_line in zip(metrics_scatter, metrics_line):
        if remove_zero:
            pair = np.array(list(filter(lambda x: x[1]>0, zip(factor_scatter[1], metric_scatter[1]))))
        else:
            pair = np.array(list(zip(factor_scatter[1], metric_scatter[1])))
        plt.figure(figsize=(10,6))
        plt.title(f'{metric_scatter[0]} with {factor_scatter[0]}')
        plt.plot(factor_line, metric_line, marker='D', color='orange', markersize=8)
        plt.scatter(pair[:,0], pair[:,1])
        plt.xlim(0,xlim)
        if metric_scatter[0]=='Normalized Edit Distance':
            plt.ylim(0,3.1)
        plt.show()

def plotResults(NUM_DATA, KEYS, BLEU, BLEU_pre, BLEU_bp, EDIT, EDIT_N):
    plt.plot(KEYS, NUM_DATA)
    plt.title('Number of Sentences')
    plt.show()

    plt.plot(KEYS, BLEU_pre)
    plt.title('BLEU Precision')
    plt.show()

    plt.plot(KEYS, BLEU_bp)
    plt.title('BLEU Brevity Penalty')
    plt.show()

    plt.plot(KEYS, BLEU)
    plt.title('BLEU')
    plt.show()

    plt.plot(KEYS, EDIT)
    plt.title('Edit Distance')
    plt.show()

    plt.plot(KEYS, EDIT_N)
    plt.title('Normalize Edit Distance')
    plt.show()


import os
import subprocess
import argschema
import renderapi

class RenderClientParameters(argschema.schemas.mm.Schema):
    host = argschema.fields.Str(required=True, metadata={
                         'description': 'render host'})
    port = argschema.fields.Int(required=True, metadata={
                         'description': 'render post integer'})
    owner = argschema.fields.Str(required=True, metadata={
                          'description': 'render default owner'})
    project = argschema.fields.Str(required=True, metadata={
                            'description': 'render default project'})
    client_scripts = argschema.fields.Str(
        required=True, metadata={
            'description': 'path to render client scripts'})
    memGB = argschema.fields.Str(
        required=False, default='5G', metadata={
            'description': 'string describing java heap memory (default 5G)'})

class RenderParameters(argschema.ArgSchema):
    render = argschema.fields.Nested(RenderClientParameters)

class RenderTrakEM2Parameters(RenderParameters):
    renderHome = argschema.fields.InputDir(
        required=True, metadata={
            'description': 'root path of standard render install'})

class TEM2ProjectTransfer(RenderTrakEM2Parameters):
    minX = argschema.fields.Int(required=True,
                                metadata={'description': 'minimum x'})
    minY = argschema.fields.Int(required=True,
                                metadata={'description': 'minimum y'})
    maxX = argschema.fields.Int(required=True,
                                metadata={'description': 'maximum x'})
    maxY = argschema.fields.Int(required=True,
                                metadata={'description': 'maximum y'})
    minZ = argschema.fields.Int(required=False,
                                metadata={'description': 'minimum z'})
    maxZ = argschema.fields.Int(required=False,
                                metadata={'description': 'maximum z'})
    inputStack = argschema.fields.Str(
        required=True, metadata={
            'description': 'stack to import from'})
    outputStack = argschema.fields.Str(
        required=True, metadata={
            'description': 'stack to output to'})
    outputXMLdir = argschema.fields.Str(
        required=True, metadata={
            'description': 'path to save xml files'})
    doChunk = argschema.fields.Boolean(
        required=False, default=False, metadata={
            'description': 'split the input into chunks'})
    chunkSize = argschema.fields.Int(
        required=False, default=50, metadata={
            'description': 'size of chunks'})

class EMLMRegistrationParameters(TEM2ProjectTransfer):
    LMstack = argschema.fields.Str(
        required=True, metadata={
            'description': 'name of LM stack to use for registration'})
    minX = argschema.fields.Int(
        required=False, metadata={
            'description': 'minimum x (default to EM stack bounds)'})
    minY = argschema.fields.Int(
        required=False, metadata={
            'description': 'minimum y (default to EM stack bounds)'})
    maxX = argschema.fields.Int(
        required=False, metadata={
            'description': 'maximum x (default to EM stack bounds)'})
    maxY = argschema.fields.Int(
        required=False, metadata={
            'description': 'maximum y (default to EM stack bounds)'})
    minZ = argschema.fields.Int(
        required=False, metadata={
            'description': 'minimum z (default to EM stack bounds)'})
    maxZ = argschema.fields.Int(
        required=False, metadata={
            'description': 'maximum z (default to EM stack bounds)'})

class RenderModule(argschema.ArgSchemaParser):
    def __init__(self, schema_type=None, *args, **kwargs):
        if schema_type is None:
            schema_type = RenderParameters
        super(RenderModule, self).__init__(
            schema_type=schema_type, *args, **kwargs)
        self.render = renderapi.render.connect(**self.args['render'])

class TrakEM2RenderModule(RenderModule):
    def __init__(self, schema_type=None, *args, **kwargs):
        if schema_type is None:
            schema_type = RenderTrakEM2Parameters
        super(TrakEM2RenderModule, self).__init__(
            schema_type=schema_type, *args, **kwargs)
        jarDir = os.path.join(self.args['renderHome'], 'render-app', 'target')
        self.renderjarFile = next(os.path.join(jarDir, f) for f in os.listdir(
            jarDir) if f.endswith('jar-with-dependencies.jar'))
        self.trakem2cmd = ['java', '-cp', self.renderjarFile,
                           'org.janelia.alignment.trakem2.Converter']

    def convert_trakem2_project(self, xmlFile, projectPath, json_path):
        cmd = self.trakem2cmd + ['%s' % xmlFile, '%s' %
                                 projectPath, '%s' % json_path]
        proc = subprocess.Popen(
            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        while proc.poll() is None:
            line = proc.stdout.readline()
            if 'ERROR' in line:
                self.logger.error(line)
            else:
                self.logger.debug(line)
        while proc.poll() is None:
            line = proc.stdout.readline()
            if 'ERROR' in line:
                self.logger.error(line)
            else:
                self.logger.debug(line)

if __name__ == '__main__':
    example_input = {
        "render": {
            "host": "ibs-forrestc-ux1",
            "port": 8080,
            "owner": "NewOwner",
            "project": "H1706003_z150",
            "client_scripts": "/pipeline/render/render-ws-java-client/src/main/scripts"
        }
    }
    module = RenderModule(input_data=example_input)
    module.run()

    bad_input = {
        "render": {
            "host": "ibs-forrestc-ux1",
            "port": '8080',
            "owner": "Forrest",
            "project": "H1706003_z150",
            "client_scripts": "/pipeline/render/render-ws-java-client/src/main/scripts"
        }
    }
    module = RenderModule(input_data=bad_input)
    module.run()


matriz = [[1,25,8,3,50],[4,8,50,100,21]]
diferencia_total = 0
for numeros in matriz:
    print(numeros)
# con esto pasamos por cada item de la lista que tengo pensada crea.
    position = -1
    comparador = 0
    for numero in numeros:
        position += 1

        if numero <= numeros[position]:
            comparador += 1

            if comparador == len(numeros):
                diferencia_total -= numero
        else:
            continue

print(diferencia_total)


def romanToInt(s):
    """
    :type s: str
    :rtype: int
    """

    sum = 0
    roman_dict = {"I": 1,
                  "V": 5,
                  "X": 10,
                  "L": 50,
                  "C": 100,
                  "D": 500,
                  "M": 1000}
    count = 0
    num_lst = [roman_dict[st] for st in s]

    while count < len(num_lst):
        crr = num_lst[count]
        count += 1
        nxt = num_lst[count] if count < len(num_lst) else crr
        if crr >= nxt:
            sum += crr
        else:
            sum += nxt - crr
            count += 1

    return sum

s = "MCMXCIV"
print(romanToInt(s))


import matplotlib.pyplot as plt
 ## plt is a shortened version of matplotlib.pyplot
x = [2,4,6,8,10]
y = [6,7,8,2,4]

x2 = [1,3,5,7,9]
y2 = [7,8,2,4,2]
plt.bar(x, y, label = 'Bars 1', color = 'blue')
plt.bar(x2, y2, label = 'Bars 2', color = 'red')

# creating legends, titles, and lables
# Titles and labels
plt.xlabel('x') ## labels x-coordinate
plt.ylabel('y') ## labels y-coordinate
plt.title('A Very Interesting Title\nUwU') ## creates a title
# Legends
plt.legend()
plt.show() ## initiates graphics window


import requests
import json
from bs4 import BeautifulSoup
import streamlit as st
import openai
import replicate
import os

BROWSERLESS_API_KEY = 'your key'
openai.api_key = 'your key'
os.environ["REPLICATE_API_TOKEN"] = "your key"

def scrape_website(url: str):
    headers = {'Cache-Control': 'no-cache', 'Content-Type': 'application/json'}
    data = {"url":url}
    data_json = json.dumps(data)
    post_url = f"https://chrome.browserless.io/content?token={BROWSERLESS_API_KEY}"
    response = requests.post(post_url, headers=headers, data=data_json)
    if response.status_code == 200:
        soup = BeautifulSoup(response.content, "html.parser")
        text = soup.get_text()
        if text != "" and text != None:
            return text
        else:
            st.text("Couldn't fetch article")
            return None

    else:
        print(f"HTTP request failed with status code {response.status_code}")

st.markdown("
Summarize Anything
", unsafe_allow_html=True)

# Centered text
st.markdown("
PASTE URL BELOW:
", unsafe_allow_html=True)

def generate_summary(article):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user",
                   "content": f"summarize the following article only mentioning the main ideas, don't go on a seperate tangent, as if a reporter wrote it, use over 180 words: {article}"}],
        temperature=.88
    )
    total_tokens_used_c = response['usage']['total_tokens']
    price = (total_tokens_used_c / 1000) * .0015
    actual_response = response['choices'][0]['message']['content']
    return actual_response

def generate_images(text):
    response = openai.ChatCompletion.create(
        model="ft:gpt-3.5-turbo-0613:personal::7ytneB65",
        messages=[{"role": "system",
                   "content": "You are a prompt engineer who is tasked to write simple visual descriptions to encapsulate abstract text summaries. You will create 3 visual description prompts that take a summary and generate these prompts."},
                  {"role": "user","content": text}],
        temperature=.88
    )
    total_tokens_used_c = response['usage']['total_tokens']
    price = (total_tokens_used_c / 1000) * .0015
    actual_response = response['choices'][0]['message']['content']
    for i in range(2, 4):
        actual_response = actual_response.replace(f"{i}.", "#")
    p = actual_response.split("#")
    for i in p:
        output = replicate.run(
            "stability-ai/sdxl:d830ba5dabf8090ec0db6c10fc862c6eb1c929e1a194a5411852d25fd954ac82",
            input={
                "prompt": f"{i}, RAW candid cinema, 16mm, color graded portra 400 film, remarkable color, ultra realistic, textured skin",
                "negative_prompt": "scary, evil, horrible, ugly, disfigured, disgusting, destroyed"}
        )
        st.image(output[0])

url = st.text_input("")
if url != "":
    print(f"url: {url}")
    try:
        article_text = scrape_website(url)
        #st.write(article_text)
        if article_text != None:
            summary = generate_summary(article_text)

            st.title("Summary:")

            st.write(summary)
            st.text("Generating Images")
            generate_images(summary)
    except:
        st.text("ERROR: THIS ARTICLE CAN'T BE SUMMARIZED")


import struct, os

class CFGAlignment:
  ALIGN_NONE = 0
  ALIGN_START = 1
  ALIGN_END = 2

class CFG(object):
  CFG_FMT = struct.Struct("<L")

  def __init__(self, data):
    self.data = data
    self.num_records, = self.CFG_FMT.unpack_from(self.data)
    self.records = []
    self.files = []

    data_offset = self.CFG_FMT.size + (self.num_records * CFGRecord.RECORD_FMT.size)
    total_data = 0
    path = ["/"]
    parent = None
    for i in xrange(self.num_records):
        record = CFGRecord(self.data, i)
        #assert (record.isDirectory() and record.offset == data_offset) or \
        #  (not record.isDirectory() and record.offset == data_offset + total_data)
        total_data += record.size
        if record.name == "..":
          assert len(path) > 1
          file = self.getFile(os.path.join(*path))
          assert file and file.isDirectory()
          assert file.record.mode == record.mode
          path.pop()
        else:
          file = CFGFile(os.path.join(*path + [record.name]), record, self.data, parent)
          self.files.append(file)
          if record.isDirectory():
            path.append(record.name)
        parent = self.getFile(os.path.join(*path))
        self.records.append(record)

  def getFile(self, path):
    for file in self.files:
      if file.path == path:
        return file
    return None

  def removeFile(self, path, recursive = False):
    file = self.getFile(path)
    if file:
      if len(file.children) > 0 and not recursive:
        return False
      # Copy list of children since we're modifying the list
      for child in file.children[:]:
        self.removeFile(child.path, recursive)
      self.files.remove(file)
      if file.parent:
        file.parent.removeChild(file)
      return True
    else:
      return False

  def addFile(self, path, data, mode, opt, uid, gid):
    file = self.getFile(path)
    if file:
      return False
    directory = False
    (parent_path, filename) = os.path.split(path)
    if filename == "":
      directory = True
      (parent_path, filename) = os.path.split(parent_path)

    parent = self.getFile(parent_path)
    if parent is None:
      return False
    record = CFGRecord.createRecord(filename, mode, opt, uid, gid, len(data), 0)
    file = CFGFile(path, record, data, parent)
    self.files.append(file)
    return True

  def generate(self, alignment):
    self.records = []
    file_data = ""
    if len(self.files) > 0:
      (self.records, file_data) = self.files[0].generateRecords(alignment=alignment)
    self.num_records = len(self.records)
    self.data = self.CFG_FMT.pack(self.num_records)
    data_offset = len(self.data) + CFGRecord.RECORD_FMT.size * self.num_records
    alignment_data = ""
    if alignment != CFGAlignment.ALIGN_NONE:
      alignment_extra = data_offset % 0x40
      if alignment_extra > 0:
          alignment_data += struct.pack("<B", 0) * (0x40 - alignment_extra)
          data_offset += 0x40 - alignment_extra
    data_size = 0
    for record in self.records:
      record.offset += data_offset
      record.generate()
      self.data += record.data
    self.data += alignment_data
    self.data += file_data

  def __str__(self):
    ret = "Number of records : %d\n" % self.num_records
    path = ["/"]
    for record in self.records:
      ret += "%s %s\n" % (str(record), os.path.join(*path + ([] if record.name == ".." else [record.name])))
      if record.name == "..":
        path.pop()
      elif record.isDirectory():
        path.append(record.name)

    return ret

  @staticmethod
  def modeToStr(mode):
    assert mode & 0xE000 == 0
    modeStr = "dAEIrwxrwxrwx"
    ret = ""
    for i in xrange(13):
      if mode & (0x1000 >> i):
        ret += modeStr[i]
      else:
        ret += "-"
    return ret

  @staticmethod
  def strToMode(str):
    modeStr = "dAEIrwxrwxrwx"
    assert len(str) == len(modeStr)
    mode = 0
    for i in xrange(13):
      if str[i] == modeStr[i]:
        mode |= (0x1000 >> i)
      else:
        assert str[i] == '-' or str[i] == ' '
    return mode

  @staticmethod
  def optToStr(opt):
    assert opt & 0xFFF0 == 0
    optStr = "?!MF"
    ret = ""
    for i in xrange(4):
      if opt & (8 >> i):
        ret += optStr[i]
      else:
        ret += "-"
    return ret

  @staticmethod
  def strToOpt(str):
    optStr = "?!MF"
    assert len(str) == len(optStr)
    opt = 0
    for i in xrange(4):
      if str[i] == optStr[i]:
        opt |= (8 >> i)
      else:
        assert str[i] == '-' or str[i] == ' '
    return opt

class CFGRecord(object):
  RECORD_FMT = struct.Struct("<12sHHHHHHL")

  def __init__(self, data, index):
      offset = CFG.CFG_FMT.size + self.RECORD_FMT.size * index
      self.data = data[offset:offset + self.RECORD_FMT.size]
      (self.name, zero, self.mode, self.opt, self.size,
       self.uid, self.gid, self.offset) = self.RECORD_FMT.unpack(self.data)
      self.name = self.name.strip('\0')
      if self.name == "..":
        assert self.isDirectory()
        assert self.opt == 0
      if self.isDirectory():
        assert self.size == 0

  def isDirectory(self):
    return self.mode & 0x1000 == 0x1000

  def generate(self):
    self.data = CFGRecord.RECORD_FMT.pack(self.name, 0, self.mode, self.opt,
                                          self.size, self.uid, self.gid, self.offset)

  @staticmethod
  def createRecord(name, mode, opt, uid, gid, size, offset):
    data = '\0' * CFG.CFG_FMT.size + CFGRecord.RECORD_FMT.pack(name, 0, mode, opt, size,
                                                               uid, gid, offset)
    return CFGRecord(data, 0)

  def copy(self):
    return self.createRecord(self.name, self.mode, self.opt,
                             self.uid, self.gid, self.size, self.offset)

  def __str__(self):
    return "%-12s (%04X:%04X) [%4d bytes @ %8X] %s _ %s" % (self.name, self.uid, self.gid,
                                                            self.size, self.offset,
                                                            CFG.modeToStr(self.mode),
                                                            CFG.optToStr(self.opt))

class CFGFile(object):
  def __init__(self, path, record, data, parent=None):
    self.path = path
    self.record = record
    self.data = data[record.offset:record.offset + record.size]
    self.parent = parent
    self.children = []
    #print "New %-10s : %-32s with parent %s" % ("directory" if self.isDirectory() else "file", self.path, self.parent.path if parent else "NONE")
    if parent:
      parent.addChild(self)

  @property
  def size(self):
    return self.record.size

  def isDirectory(self):
    return self.record.isDirectory()

  def addChild(self, child):
    assert self.isDirectory()
    self.children.append(child)
    self.children.sort()

  def removeChild(self, child):
    assert self.isDirectory() and child in self.children
    self.children.remove(child)

  def generateRecords(self, data = "", alignment=CFGAlignment.ALIGN_NONE):
    self.record.size = 0 if self.isDirectory() else self.size
    self.record.offset = 0 if self.isDirectory() else len(data)
    records = [self.record]
    if self.isDirectory():
      for child in self.children:
        (sub_records, new_data) = child.generateRecords(data, alignment)
        records += sub_records
        data = new_data

      dotdot = self.record.copy()
      dotdot.name = '..'
      dotdot.opt = 0
      records.append(dotdot)
    else:
      alignment_extra = 0
      if alignment == CFGAlignment.ALIGN_START:
        alignment_extra = self.record.offset % 0x40
      elif self.record.size != 0 and alignment == CFGAlignment.ALIGN_END:
        alignment_extra = (self.record.offset + self.record.size) % 0x40
      if alignment_extra > 0:
          data += struct.pack("<B", 0) * (0x40 - alignment_extra)
          self.record.offset += 0x40 - alignment_extra
      data += self.data

    return (records, data)

  def __str__(self):
    return "%-32s [%4d bytes]" % (self.path, self.size)

  def __cmp__(self, other):
    if self.isDirectory() == other.isDirectory():
      return cmp(self.path, other.path)
    elif self.isDirectory():
      return -1
    else:
      return 1


import json
import numpy as np
import sqlite_utils
from sqlite_utils.db import Table
from typing import cast, List, Tuple, Optional, Union, Dict, Any
from .base_vectordb import VectorDatabase
from nchain.models.core import Entry
from annoy import AnnoyIndex
import struct
import time
import os

def encode(values):
    return struct.pack("<" + "f" * len(values), *values)

def encode_as_numpy(values):
    return np.array(values, dtype=np.float32).tobytes()

def decode(binary):
    return struct.unpack("<" + "f" * (len(binary) // 4), binary)

def decode_from_numpy_to_list(binary):
    numpy_array = np.frombuffer(binary, dtype=np.float32)
    return numpy_array.tolist()

class SQLiteVectorDB(VectorDatabase):

    def __init__(self, dimension: int, indexdb_path: str, db_path=None, metric: str = "angular", collection:str="default"):
        self.dimension = dimension
        self.indexdb_path = indexdb_path
        if db_path:
            self.db = sqlite_utils.Database(db_path)
        else:
            self.db = sqlite_utils.Database(memory=True)
        # Create the 'collections' table
        self.db["collections"].create({
            "id": int,     # unique identifier for each collection
            "name": str,   # name of the collection
            "model": str,   # identifier (or model ID) for the embedding model associated with the collection
            "dimension": int,
            "metric": str,
            "indexed_at":int,
            "stored_at": int,
        }, pk="id", not_null=["name", "model"], if_not_exists=True)
        self.db["collections"].create_index(["name"], unique=True, if_not_exists=True)

        # Create the 'embeddings' table
        self.db["embeddings"].create({
            "collection_id": int,     # foreign key to reference the 'collections' table
            "id": int,                # identifier for the entry
            "embedding": "BLOB",      # embedded vector
            "content": str,           # content in text format
            "content_blob": "BLOB",   # content in binary format
            "content_hash": "BLOB",   # hash of the content for deduplication
            "metadata": str,          # additional metadata
            "updated": int            # timestamp
        }, pk=("id"), foreign_keys=[("collection_id", "collections", "id")], not_null=["collection_id", "id"], if_not_exists=True)
        rows = list(self.db["collections"].rows_where("name = ?", [collection]))
        if len(rows) > 0:
            self.collection = rows[0]
            self.collection["metric"] = metric
            self.db["collections"].update(self.collection["id"], {"metric":metric} )
        else:
            collection_row = {
                "name": collection,
                "model": "SentenceTransformers",
                "dimension": dimension,
                "metric": metric,
                "indexed_at": None,
                "stored_at": None
            }
            self.db["collections"].insert(collection_row, replace=True)
            self.collection = list(self.db["collections"].rows_where("name = ?", [collection]))[0]
        if  os.path.exists(indexdb_path):
            self.index = AnnoyIndex(self.dimension, self.collection["metric"])
            self.index.load(indexdb_path)  # Load the Annoy index from disk
            self.vectors_updated = False
        else:
            self.vectors_updated = True

    def store_vectors(self, vectors: List[List[float]], metadata_list: List[dict], chunks: list[Union[str, bytes]], store:bool) -> None:
        hashes = [self.content_hash(content) for content in chunks]
        # Create a mapping of hash to its index for quick look-up
        hash_to_index = {hash: index for index, hash in enumerate(hashes)}

        # Fetch rows that match the provided hashes
        matching_rows = self.db.query(
            """
            select id, content_hash from embeddings
            where collection_id = ? and content_hash in ({})
            """.format(",".join("?" for _ in hashes)),
            [self.collection["id"]] + hashes
        )

        # Get the hash_index for each matching row
        existing_ids = [hash_to_index[row['content_hash']] for row in matching_rows]
        filtered_items = [item + (hashes[idx], ) for idx, item in enumerate(zip(vectors, metadata_list, chunks)) if idx not in existing_ids]
        if len(filtered_items) > 0:
            with self.db.conn:
                cast(Table, self.db["embeddings"]).insert_all(
                    (
                        {
                            "collection_id": self.collection["id"],
                            "embedding": encode_as_numpy(embedding),
                            "content": content
                            if (store and isinstance(content, str))
                            else None,
                            "content_blob": content
                            if (store and isinstance(content, bytes))
                            else None,
                            "content_hash": content_hash,
                            "metadata": json.dumps(metadata) if metadata else None,
                            "updated": int(time.time()),
                        }
                        for (embedding, metadata, content, content_hash) in filtered_items

                    ),
                    replace=True,
                )

            self.collection["stored_at"] = int(time.time())
            self.db["collections"].update(self.collection["id"], {"stored_at":self.collection["stored_at"]})
            self.vectors_updated = True

    def build_index(self):
        self.index = AnnoyIndex(self.dimension, self.collection["metric"])
        for row in self.db["embeddings"].rows_where():
            numpy_array = np.frombuffer(row["embedding"], dtype=np.float32)
            self.index.add_item(row["id"], numpy_array.tolist())
        self.index.build(10)
        self.collection["indexed_at"] = int(time.time())
        self.db["collections"].update(self.collection["id"], {"indexed_at":self.collection["indexed_at"]})
        print("Index built", self.indexdb_path)
        self.index.save(self.indexdb_path)

    def refresh_index(self):
        if self.collection["stored_at"]:
            if self.collection["indexed_at"] is None or self.collection["stored_at"] > self.collection["indexed_at"]:
                self.build_index()

        self.vectors_updated = False

    def search_vectors(self, query_vector: List[float], top_k: int) -> List[Entry]:
        if self.vectors_updated:
            self.refresh_index()

        indices, distances = self.index.get_nns_by_vector(query_vector, top_k, include_distances=True)
        results = []
        for idx, distance in zip(indices, distances):
            row = self.db["embeddings"].get(idx)
            metadata = json.loads(row["metadata"])
            similar_entry = Entry(id=row["id"], score=distance, content=row["content"], metadata=metadata)
            results.append(similar_entry)
        return results

    def update_vector(self, index: int, new_vector: List[float], new_metadata: Optional[dict] = None) -> None:
        # Convert vector to BLOB
        numpy_array = np.array(new_vector, dtype=np.float32)
        blob = numpy_array.tobytes()
        # Update in SQLite
        self.db["vectors"].update(index, {"vector": blob, "metadata": json.dumps(new_metadata or {})})

        # Update in Annoy
        self.index.add_item(index, new_vector)
        self.index_built = False

    def delete_vector(self, index: int) -> None:
        self.db["vectors"].delete_where("id = ?", [index])
        self.vector_updated = True
        # Note: Deletion in Annoy isn't straightforward. One way is to rebuild the index excluding the deleted vector.
        # However, for simplicity, we're not handling it here. The deleted vector may still appear in search results.


## Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
## Input: nums = [2,7,11,15], target = 9
## Output: [0,1]

class Solution:
    def twoSums(self, l:list, t:int) -> list:
        for i in range(len(l)):
            for j in range(i+1, len(l)):
                sum = l[i] + l[j]
                if sum == t:
                    return [i,j]

obj = Solution()
res = obj.twoSums([2,7,11,15],18)
print(res)


import os
from typing import Optional

import requests

from app.constants import APP_VERSION
from app.constants import MAPBOX_ACCESS_TOKEN

ALLOWED_MAPBOX_PROFILE = {
    'mapbox/driving-traffic',
    'mapbox/driving',
    'mapbox/walking',
    'mapbox/cycling'
}

def _Session(access_token: Optional[str] = None) -> requests.Session:
    access_token = (
        access_token or
        os.environ.get('MAPBOX_ACCESS_TOKEN') or
        MAPBOX_ACCESS_TOKEN)

    session = requests.Session()
    session.params.update(access_token=access_token)
    session.headers.update({
        'User-Agent': f'flask-chariots/v{APP_VERSION}'
    })
    return session

class Service:
    MAPBOX_DEFAULT_HOST = 'https://api.mapbox.com'

    def __init__(self,
                 access_token: Optional[str] = None,
                 host: Optional[str] = None):
        self.session = _Session(access_token)
        self.host = host or self.MAPBOX_DEFAULT_HOST

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.session.close()

    def response_handler(self, response: requests.Response) -> None:
        if response.status_code == 200:
            return
        else:
            print('Warning: HTTP request failed')


# @Time : 2021/2/20 15:26
# @Author : LiuBin
# @File : basic_classifier.py
# @Description :
# @Software: PyCharm
from overrides import overrides
from typing import Dict, Optional

import torch
import torch.nn.functional as F
from allennlp.data import Vocabulary, TextFieldTensors
from allennlp.modules import FeedForward, TextFieldEmbedder, Seq2VecEncoder, Seq2SeqEncoder
from allennlp.nn import util, InitializerApplicator
from allennlp.models import Model, BasicClassifier
from allennlp.training.metrics import F1Measure
from allennlp.nn.util import get_text_field_mask

@Model.register('basic_classifier_f')  # 注册一个Model名称
class BasicClassifierF(BasicClassifier):
    def __init__(
            self,
            vocab: Vocabulary,
            text_field_embedder: TextFieldEmbedder,
            seq2vec_encoder: Seq2VecEncoder,
            seq2seq_encoder: Seq2SeqEncoder = None,
            feedforward: Optional[FeedForward] = None,
            dropout: float = None,
            num_labels: int = None,
            label_namespace: str = "labels",
            namespace: str = "tokens",
            initializer: InitializerApplicator = InitializerApplicator()):
        super().__init__(vocab, text_field_embedder, seq2vec_encoder, seq2seq_encoder, feedforward, dropout, num_labels,
                         label_namespace, namespace, initializer)

        self._f1 = F1Measure(1)

    def forward(self,
                tokens: TextFieldTensors,
                label: torch.Tensor = None) -> Dict[str, torch.Tensor]:
        embedded_text = self._text_field_embedder(tokens)
        mask = get_text_field_mask(tokens)

        if self._seq2seq_encoder:
            embedded_text = self._seq2seq_encoder(embedded_text, mask=mask)

        embedded_text = self._seq2vec_encoder(embedded_text, mask=mask)

        if self._dropout:
            embedded_text = self._dropout(embedded_text)

        if self._feedforward is not None:
            embedded_text = self._feedforward(embedded_text)

        logits = self._classification_layer(embedded_text)
        probs = torch.nn.functional.softmax(logits, dim=-1)

        output_dict = {"logits": logits, "probs": probs}
        output_dict["token_ids"] = util.get_token_ids_from_text_field_tensors(tokens)
        if label is not None:
            loss = self._loss(logits, label.long().view(-1))
            output_dict["loss"] = loss
            self._accuracy(logits, label)
            self._f1(logits, label)

        return output_dict

    @overrides
    def make_output_human_readable(
            self, output_dict: Dict[str, torch.Tensor]
    ) -> Dict[str, torch.Tensor]:
        """
        Does a simple argmax over the probabilities, converts index to string label, and
        add `"label"` key to the dictionary with the result.
        """
        predictions = output_dict["probs"]
        if predictions.dim() == 2:
            predictions_list = [predictions[i] for i in range(predictions.shape[0])]
        else:
            predictions_list = [predictions]
        classes = []
        for prediction in predictions_list:
            label_idx = prediction.argmax(dim=-1).item()
            label_str = self.vocab.get_index_to_token_vocabulary(self._label_namespace).get(
                label_idx, str(label_idx)
            )
            classes.append(label_str)
        output_dict["label"] = classes
        output_dict.pop("probs")
        output_dict.pop("logits")
        output_dict.pop("token_ids")
        return output_dict

    def get_metrics(self, reset: bool = False) -> Dict[str, float]:
        metrics = {"accuracy": self._accuracy.get_metric(reset)}
        metrics.update(self._f1.get_metric(reset))
        return metrics