from odoo import api, models

class ConnectorSnippet(models.TransientModel):
    _name = "connector.snippet"
    _description = "Connector Snippet"

    @api.model
    def _get_ecomm_extensions(self):
        return []

    def open_configuration(self):
        connection_id = False
        active_conn = self.env['connector.instance'].search(
            [('active', '=', True)], limit=1)
        if active_conn:
            connection_id = active_conn.id
        return {
            'type': 'ir.actions.act_window',
            'name': 'Configure Connection',
            'view_mode': 'form',
            'res_model': 'connector.instance',
            'res_id': connection_id,
            'domain': '[]',
        }

    def export_attributes_and_their_values(self):
        display_message = "
 Error in ecommerce connection kindly check connection
"
        connection = self.env['connector.instance']._create_connection()
        if type(connection) is dict and connection.get('status', 'False'):
            display_message = self.sync_ecomm_attribute(connection)
        return self.env['message.wizard'].genrated_message(display_message)

    def sync_operations(self, model, mapping_model, domain, oprmodel):
        display_message = "
 Error in ecommerce connection kindly check connection
"
        connection = self.env['connector.instance']._create_connection()
        if type(connection) is dict and connection.get('status', 'False'):
            ctx = dict(self._context or {})
            sync_opr = ctx.get('sync_opr')
            instance_id = ctx.get('instance_id')
            channel = ctx.get('ecomm_channel', False)
            record_objs = self.env[model].browse(ctx.get('active_ids', [])) if ctx.get('active_model') == model else self.env[model].search(domain)
            if record_objs:
                exup_record_objs = self.get_map_updt_objs(record_objs, instance_id, sync_opr, mapping_model)
                if exup_record_objs:
                    if hasattr(self, 'sync_ecomm_%s' % oprmodel):
                        display_message = getattr(self, 'sync_ecomm_%s' % oprmodel)(exup_record_objs, channel, instance_id, sync_opr, connection)
                else:
                    display_message = 'Information!\nListed {}(s) has been already exported/updated.'.format(oprmodel)
            else:
                display_message = 'Information!\nNo new {}(s) found to be Sync.'.format(oprmodel)
        return self.env['message.wizard'].genrated_message(display_message)

    @api.model
    def get_map_updt_objs(self, record_objs, instance_id, sync_opr, model):
        mapped_objs = self.env[model].search([('instance_id', '=', instance_id)])
        if sync_opr == 'export':
            return list(set(record_objs) - set(mapped_objs.mapped('name')))
        elif sync_opr == 'update':
            return mapped_objs.filtered(
                lambda obj: obj.need_sync == 'Yes' and
                int(obj.name.id) in record_objs.ids)
        return []

    def create_odoo_connector_mapping(self, model, ecomm_id, odoo_id, instance_id, **kwargs):
        mapping_data = {
            'name' : odoo_id,
            'odoo_id' : odoo_id,
            'ecomm_id' : ecomm_id,
            'created_by' : 'odoo',
            'instance_id' : instance_id,
        }
        channel = kwargs.pop('channel', False)
        if not channel and instance_id:
            channel = self.env['connector.instance'].browse(instance_id).ecomm_type
        mapping_data.update(kwargs)
        if channel:
            if hasattr(self, 'create_%s_connector_odoo_mapping' % channel):
                mapping_data = getattr(self, 'create_%s_connector_odoo_mapping' % channel)(mapping_data, model)
        self.env[model].create(mapping_data)
        return True

    def create_ecomm_connector_mapping(self, model, channel, data, connection):
        if hasattr(self, 'create_%s_connector_mapping' % channel):
            getattr(self, 'create_%s_connector_mapping' % channel)(model, data, connection)
        return True

    def update_ecomm_connector_mapping(self, model, channel, data, connection):
        if hasattr(self, 'update_%s_connector_mapping' % channel):
            getattr(self, 'update_%s_connector_mapping' % channel)(model, data, connection)
        return True

    def update_odoo_mapping(self, model, mapping_ids, data):
        return self.env[model].browse(mapping_ids).write(data) if mapping_ids else False

    @api.model
    def update_quantity(self, data):
        """ Changes the Product Quantity by making a Physical Inventory.
        @param self: The object pointer.
        @param data: List of product_id and new_quantity
        @return: True
        """
        ctx = dict(self._context or {})
        if 'instance_id' in ctx:
            connection_obj = self.env['connector.instance'].browse(ctx.get('instance_id'))
            location_objs = connection_obj.warehouse_id if connection_obj.active else self.env['stock.warehouse'].search([], limit=1)
            if location_objs:
                ctx['inventory_mode'] = True
                self.env['stock.quant'].with_context(ctx).create({
                            'product_id': data.get('product_id'),
                            'location_id': location_objs.lot_stock_id.id,
                            'inventory_quantity': int(data.get('new_quantity', 0)),
                })
                return True
        return False

    @api.model
    def _get_journal_code(self, name, sep=' '):
        name_sep_list = []
        for namp_split in name.split(sep):
            if namp_split:
                name_seprtd = namp_split.title()[0]
                if name_seprtd.isalnum():
                    name_sep_list.append(name_seprtd)
        code = ''.join(name_sep_list)
        code = code[0:3]
        journal_model = self.env['account.journal']
        exist_obj = journal_model.search([('code', '=', code)])
        if exist_obj:
            for i in range(1, 200):
                exist_obj = journal_model.search(
                    [('code', '=', code + str(i))])
                if not exist_obj:
                    return (code + str(i))[-5:]
        return code

    @api.model
    def create_payment_method(self, data):
        """create Journal by any webservice like xmlrpc.
        @param name: journal name.
        @return: payment_id
        """
        payment_id = 0
        status = True
        status_message = "Payment method created successfully."
        try:
            journal_model = self.env['account.journal']
            res = journal_model.search(
                [('type', '=', 'cash')], limit=1)
            if res:
                data['default_credit_account_id'] = res[
                    0].default_credit_account_id.id
                data['default_debit_account_id'] = res[
                    0].default_debit_account_id.id
                data['code'] = self._get_journal_code(data.get('name'), ' ')
                paymentObj = journal_model.create(data)
                payment_id = paymentObj.id
            else:
                status_message = 'No cash journal exists!!'
                status = False
        except Exception as e:
            status = False
            status_message = "Exception in creating payment method . Reason: %s" % str(e)
        finally:
            return {
                'status_message': status_message,
                'status': status,
                'odoo_id' : payment_id,
            }

    # code for update an inventry of a product......

    @api.model
    def create_pricelist(self, data):
        """create and search pricelist by any webservice like xmlrpc.
        @param code: currency code.
        @return: pricelist_id
        """
        currencyObj = self.env['res.currency'].search(
            [('name', '=', data['code'])], limit=1)
        priceListModel = self.env['product.pricelist']
        if currencyObj:
            pricelistObj = priceListModel.search(
                [('currency_id', '=', currencyObj.id)], limit=1)
            if not pricelistObj:
                pricelistDict = {
                    'name' : 'Mage_' + data['code'],
                    'active' : True,
                    'currency_id' : currencyObj.id
                }
                pricelistObj = priceListModel.create(pricelistDict)
                return pricelistObj.id
            else:
                return pricelistObj.id
        return 0

    def manual_connector_order_operation(self, opr, ecomm, sale_order, opr_obj=False):
        text, status, session, mage_shipment, response = '', 'no', False, False, {}
        order_map_obj = self.env['connector.order.mapping'].search(
            [('odoo_order_id', '=', sale_order.id)], limit=1)
        if order_map_obj:
            increment_id = order_map_obj.name
            ecomm_order_id = order_map_obj.ecommerce_order_id or 0
            connection_obj = order_map_obj.instance_id
            instance_id = connection_obj.id
            if connection_obj.active and connection_obj.state == 'enable' and getattr(connection_obj, 'connector_sale_order_%s' % (opr)):
                ctx = dict(self._context or {})
                ctx['instance_id'] = instance_id
                if 'itemData' in ctx:
                    ctx['itemData']['send_email'] = connection_obj.notify
                connection = self.env[
                    'connector.instance'].with_context(ctx)._create_connection()
                if hasattr(self, '%s_after_order_%s' % (ecomm, opr)):
                    response = getattr(self, '%s_after_order_%s' % (ecomm, opr))(connection, increment_id, ecomm_order_id)
                self._cr.commit()
            else :
                response.update({
                    'status': 'no',
                    'text': '{0} {1} Error For Order {2} >> {0} instance is not connected.'.format(ecomm.capitalize(), opr, increment_id),
                })
            self.env['connector.sync.history'].create({
                'status': response.get('status', 'no'),
                'action_on': 'order',
                'action': 'b',
                'instance_id':instance_id,
                'error_message': response.get('text', 'no')
            })
        return response


# encoding: utf-8
#
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
#
# THIS THREADING MODULE IS PERMEATED BY THE please_stop SIGNAL.
# THIS SIGNAL IS IMPORTANT FOR PROPER SIGNALLING WHICH ALLOWS
# FOR FAST AND PREDICTABLE SHUTDOWN AND CLEANUP OF THREADS

import signal as _signal
import sys
import threading
import traceback
from collections import namedtuple
from datetime import datetime, timedelta
from time import sleep

from mo_dots import unwraplist, Null
from mo_future import (
    allocate_lock,
    get_function_name,
    get_ident,
    decorate,
)
from mo_imports import export
from mo_logs import Except, logger, raise_from_none
from mo_logs.exceptions import ERROR

from mo_threads.signals import AndSignals, Signal
from mo_threads.till import Till, TIMERS_NAME

DEBUG = False
KNOWN_DEBUGGERS = ["pydevd.py"]

PLEASE_STOP = "please_stop"  # REQUIRED thread PARAMETER TO SIGNAL STOP
PARENT_THREAD = "parent_thread"  # OPTIONAL PARAMETER TO ASSIGN THREAD TO SOMETHING OTHER THAN CURRENT THREAD
MAX_DATETIME = datetime(2286, 11, 20, 17, 46, 39)
DEFAULT_WAIT_TIME = timedelta(minutes=10)
THREAD_STOP = "stop"
THREAD_TIMEOUT = "Thread {name} timeout"
COVERAGE_COLLECTOR = None  # Detect Coverage.py

datetime.strptime("2012-01-01", "%Y-%m-%d")  # http://bugs.python.org/issue7980

cprofiler_stats = None  # ACCUMULATION OF STATS FROM ALL THREADS

try:
    STDOUT = sys.stdout.buffer
    STDERR = sys.stderr.buffer
    STDIN = sys.stdin.buffer
except Exception:
    STDOUT = sys.stdout
    STDERR = sys.stderr
    STDIN = sys.stdin

if sys.version_info[1] > 9:

    def is_daemon(thread):
        return thread.daemon

else:

    def is_daemon(thread):
        return thread.isDaemon()

IN_DEBUGGER = any(debugger in line.filename for line in traceback.extract_stack() for debugger in KNOWN_DEBUGGERS)

class BaseThread(object):
    __slots__ = [
        "_ident",
        "threading_thread",
        "child_locker",
        "children",
        "parent",
        "cprofiler",
    ]

    def __init__(self, ident, threading_thread, name=None):
        if threading_thread.name.startswith("Dummy"):
            threading_thread.name = name or f"Unknown Thread {ident}"
        self._ident = ident
        self.threading_thread = threading_thread
        self.child_locker = allocate_lock()
        self.children = []
        self.parent = MAIN_THREAD
        self.cprofiler = None

    @property
    def ident(self):
        return self._ident

    @property
    def id(self):
        return self._ident

    @property
    def name(self):
        return self.threading_thread.name

    def add_child(self, child):
        if DEBUG:
            if child.name == TIMERS_NAME:
                logger.error("timer thread should not be added as child")
            if child is self:
                logger.error("parent thread should not be added as child")
            logger.info("adding child {child} to {parent}", child=child.name, parent=self.name)

        with self.child_locker:
            self.children.append(child)

    def remove_child(self, child):
        try:
            with self.child_locker:
                self.children.remove(child)
        except Exception:
            pass

    def stop(self):
        pass

    def join(self, till=None):
        DEBUG and logger.info("{thread} joining on thread {name|quote}", name=self.name)
        thread = self.threading_thread
        try:
            if not is_daemon(thread):
                while not till and thread.is_alive():
                    thread.join(1.0)
                    sys.stderr.write(f"waiting for {thread.name}")
        except Exception as cause:
            logger.error(thread.name, cause=cause)
        finally:
            try:
                self.parent.remove_child(self)
            except Exception as cause:
                logger.warning("parents of children must have remove_child() method", cause=cause)

    def __repr__(self):
        return f"BaseThread({self.name})"

class AlienThread(BaseThread):

    def __init__(self, ident, threading_thread):
        BaseThread.__init__(self, ident, threading_thread)

        with ALL_LOCK:
            if DEBUG:
                ALL_THREAD.append(self)
                logger.info("adding {name} ({id}) to ALL", id=self.ident, name=self.name)
                if ident in ALL:
                    logger.error("Thread {name|quote} ({id}) already registered", id=self.ident, name=self.name)
            ALL[ident] = self

    def join(self, till=None):
        try:
            BaseThread.join(self, till=till)
        finally:
            if DEBUG:
                logger.info("removing {name} ({id}) from ALL", id=self._ident, name=self.name)
            with ALL_LOCK:
                try:
                    if self._ident in ALL:
                        del ALL[self._ident]
                except Exception as cause:
                    logger.warning(
                        "problem removing thread {name} ({id}) from ALL {all}",
                        all=[k for k in all.keys()],
                        id=self.ident,
                        name=self.name,
                        cause=cause,
                    )

class MainThread(BaseThread):
    def __init__(self):
        BaseThread.__init__(self, get_ident(), threading.current_thread(), "Main Thread")
        self.please_stop = Signal()
        self.stopped = Signal()
        self.stop_logging = logger.stop
        self.timers = None
        self.shutdown_locker = allocate_lock()

    def stop(self):
        """
        BLOCKS UNTIL ALL KNOWN THREADS, EXCEPT MainThread, HAVE STOPPED
        """
        self_thread = current_thread()
        if self_thread != MAIN_THREAD:
            logger.error("Only the main thread can call stop()")
        if self_thread != self:
            logger.error("Only the current thread can call stop()")

        DEBUG and logger.info("Stopping MainThread")
        if self.stopped:
            return

        self.please_stop.go()

        with self.child_locker:
            children = list(self.children)
        for c in reversed(children):
            DEBUG and c.name and logger.info("Stopping thread {name|quote}", name=c.name)
            c.stop()

        join_errors = None
        try:
            join_all_threads(children)
        except Exception as cause:
            join_errors = Except.wrap(cause)
            # REPORT ERRORS BEFORE LOGGING SHUTDOWN
            logger.warning("Problem while stopping {name|quote}", name=self.name, cause=cause, log_context=ERROR)
        DEBUG and logger.info("All children stopped")

        with self.shutdown_locker:
            if self.stopped:
                return
            self.stop_logging()
            self.timers.stop().join()

            if cprofiler_stats is not None:
                from mo_threads.profiles import write_profiles

                write_profiles(self.cprofiler)
            DEBUG and logger.info("Thread {name|quote} now stopped", name=self.name)

        if DEBUG:
            logger.info("MainThread removing {name} ({id}) from ALL", id=self.ident, name=self.name)
        with ALL_LOCK:
            if self.ident in ALL:
                del ALL[self.ident]
            residue = list(ALL.values())

        DEBUG and logger.info("MainThread has {count} threads left", count=[t.name for t in threading.enumerate()])

        if residue and (DEBUG or not IN_DEBUGGER):
            sys.stderr.write("Expecting no further threads: " + ", ".join(f"{t.name} ({t.ident})" for t in residue))
        for t in residue:
            t.stop()
        join_all_threads(residue)

        if join_errors:
            raise Except(
                context=ERROR,
                template="Problem while stopping {name|quote}",
                name=self.name,
                cause=unwraplist(join_errors),
            )

        return self

EndOfThread = namedtuple("EndOfThread", ["response", "exception"])

class Thread(BaseThread):
    """
    join() ENHANCED TO ALLOW CAPTURE OF CTRL-C, AND RETURN POSSIBLE THREAD EXCEPTIONS
    run() ENHANCED TO CAPTURE EXCEPTIONS
    """

    def __init__(self, name, target, *args, parent_thread=None, daemon=False, **kwargs):
        threading_thread = threading.Thread(None, self._run, name, daemon=daemon)
        BaseThread.__init__(self, 0, threading_thread, name or f"thread_{object.__hash__(self)}")
        self.target = target
        self.end_of_thread = None
        self.args = args

        # ENSURE THERE IS A SHARED please_stop SIGNAL
        self.kwargs = dict(kwargs)
        if PLEASE_STOP in self.kwargs:
            self.please_stop = self.kwargs[PLEASE_STOP]
        else:
            self.please_stop = self.kwargs[PLEASE_STOP] = Signal(f"please_stop for {self.name}")
        self.joiner_is_waiting = Signal(f"joining with {self.name}")
        self.stopped = Signal(f"stopped signal for {self.name}")
        if parent_thread is None:
            parent_thread = current_thread()
        self.parent = parent_thread
        self.parent.add_child(self)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        if isinstance(type, BaseException):
            self.please_stop.go()

        # TODO: AFTER A WHILE START KILLING THREAD
        self.join()
        self.args = None
        self.kwargs = None

    def start(self):
        try:
            self.threading_thread.start()
            return self
        except Exception as cause:
            logger.error("Can not start thread", cause)

    def stop(self):
        """
        SEND STOP SIGNAL, DO NOT BLOCK
        """
        with self.child_locker:
            children = list(self.children)
        for c in children:
            DEBUG and c.name and logger.note("Stopping thread {name|quote}", name=c.name)
            c.stop()
        self.please_stop.go()

        DEBUG and logger.note(
            "Thread {name|quote} got request to stop from {thread}", thread=current_thread().name, name=self.name
        )
        return self

    def is_alive(self):
        return not self.stopped

    def _run(self):
        self._ident = ident = get_ident()
        with RegisterThread(thread=self):
            with ALL_LOCK:
                ALL[ident] = self
            try:  # deal with join
                try:  # deal with target exceptions
                    if self.target is not None:
                        args, kwargs, self.args, self.kwargs = self.args, self.kwargs, None, None
                        self.end_of_thread = EndOfThread(self.target(*args, **kwargs), None)
                except Exception as cause:
                    cause = Except.wrap(cause)
                    self.end_of_thread = EndOfThread(None, cause)
                    with self.parent.child_locker:
                        emit_problem = self not in self.parent.children
                    if emit_problem:
                        # THREAD FAILURES ARE A PROBLEM ONLY IF NO ONE WILL BE JOINING WITH IT
                        try:
                            logger.error("Problem in thread {name|quote}", name=self.name, cause=cause)
                        except Exception as cause:
                            sys.stderr.write(f"ERROR in thread: {self.name}  {cause}\n")
                finally:
                    try:
                        with self.child_locker:
                            children = list(self.children)
                        for c in children:
                            DEBUG and logger.note(f"Stopping thread {c.name}\n")
                            c.stop()

                        join_all_threads(children)
                        with self.child_locker:
                            self.children = []
                        del self.target, self.args, self.kwargs
                        DEBUG and logger.note("thread {name|quote} stopping", name=self.name)
                    except Exception as cause:
                        DEBUG and logger.warning("problem with thread {name|quote}", cause=cause, name=self.name)
                    finally:
                        with ALL_LOCK:
                            if ident in ALL:
                                del ALL[ident]
                        self.stopped.go()
            finally:
                if self.joiner_is_waiting:
                    return
                if not self.joiner_is_waiting:
                    DEBUG and logger.note("thread {name|quote} is done, wait for join", name=self.name)
                    # WHERE DO WE PUT THE THREAD RESULT?
                    # IF NO THREAD JOINS WITH THIS, THEN WHAT DO WE DO WITH THE RESULT?
                    # HOW LONG DO WE WAIT FOR ANOTHER TO ACCEPT THE RESULT?
                    #
                    # WAIT 60seconds, THEN SEND RESULT TO LOGGER
                    (Till(seconds=60) | self.joiner_is_waiting).wait()

                res, exp = self.end_of_thread
                if exp:
                    # THREAD FAILURES ARE A PROBLEM ONLY IF NO ONE WILL BE JOINING WITH IT
                    try:
                        logger.error(
                            "Problem in thread {name|quote}", name=self.name, cause=self.end_of_thread.exception,
                        )
                    except Exception as cause:
                        sys.stderr.write(f"ERROR in thread: {self.name} {cause}\n")
                        return

                if res is not None:
                    logger.warning(
                        "Thread {thread} returned a response {response|json}, but was not joined",
                        thread=self.name,
                        response=res,
                    )
                # THREAD ENDS OK; FORGET ABOUT IT
                if isinstance(self.parent, Thread):
                    # SOMETIMES parent IS NOT A THREAD
                    self.parent.remove_child(self)

    def release(self):
        """
        RELEASE THREAD TO FEND FOR ITSELF. THREAD CAN EXPECT TO NEVER
        JOIN. WILL SEND RESULTS TO LOGS WHEN DONE.

        PARENT THREAD WILL STILL ENSURE self HAS STOPPED PROPERLY
        """
        self.joiner_is_waiting.go()
        return self

    def join(self, till=None):
        """
        RETURN THE RESULT {"response":r, "exception":e} OF THE THREAD EXECUTION (INCLUDING EXCEPTION, IF EXISTS)
        """
        if self is Thread:
            logger.error("Thread.join() is not a valid call, use t.join()")

        if isinstance(till, (int, float)):
            till = Till(seconds=till)

        with self.child_locker:
            children = list(self.children)
        join_all_threads(children, till=till)

        DEBUG and logger.note(
            "{parent.name} ({parent.ident}) waiting on thread {child}", parent=current_thread(), child=self.name,
        )
        self.joiner_is_waiting.go()
        (self.stopped | till).wait()
        if not self.stopped:
            raise Except(ERROR, template=THREAD_TIMEOUT, params={"name": self.name})

        try:
            self.parent.remove_child(self)
        except Exception as cause:
            logger.warning("parents of children must have remove_child() method", cause=cause)

        if self.end_of_thread.exception:
            logger.error(
                "Thread {name|quote} did not end well", name=self.name, cause=self.end_of_thread.exception,
            )
        return self.end_of_thread.response

    @staticmethod
    def run(name, target, *args, **kwargs):
        # ENSURE target HAS please_stop ARGUMENT
        if get_function_name(target) == "wrapper":
            pass  # GIVE THE override DECORATOR A PASS
        elif PLEASE_STOP not in target.__code__.co_varnames:
            logger.error("function must have please_stop argument for signalling shutdown")

        return Thread(name, target, *args, **kwargs).start()

    @staticmethod
    def current():
        return current_thread()

    @staticmethod
    def join_all(threads):
        join_all_threads(threads)

    ####################################################################################################################
    ## threading.Thread METHODS
    ####################################################################################################################
    def is_alive(self):
        return not self.stopped

    @property
    def _is_stopped(self):
        return self.stopped

    @property
    def daemon(self):
        return False

    def isDaemon(self):
        return False

    def getName(self):
        return self.name

    def setName(self, name):
        self.name = name

    def __repr__(self):
        return f"Thread({self.name})"

class RegisterThread(object):
    """
    A context manager to handle threads spawned by other libs
    This will ensure the thread has unregistered, or
    has completed before MAIN_THREAD is shutdown
    """

    __slots__ = ["thread"]

    def __init__(self, *, thread=None, name=None):
        self.thread = thread or BaseThread(get_ident(), threading.current_thread(), name)

    def __enter__(self):
        thread = self.thread
        if cprofiler_stats is not None:
            from mo_threads.profiles import CProfiler

            cprofiler = thread.cprofiler = CProfiler()
            cprofiler.__enter__()
        if COVERAGE_COLLECTOR is not None:
            # STARTING TRACER WILL sys.settrace() ITSELF
            COVERAGE_COLLECTOR._collectors[-1]._start_tracer()

        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # PYTHON WILL REMOVE GLOBAL VAR BEFORE END-OF-THREAD
        thread = self.thread

        if cprofiler_stats is not None:
            thread.cprofiler.__exit__(exc_type, exc_val, exc_tb)
        with thread.child_locker:
            if thread.children:
                logger.error(
                    "Thread {thread|quote} has not joined with child threads {children|json}",
                    children=[c.name for c in thread.children],
                    thread=thread.name,
                )
        DEBUG and logger.info("deregistered {name}", name=thread.name)

def register_thread(func):
    """
    Call `with RegisterThread():`
    Track this thread to ensure controlled shutdown
    """

    @decorate(func)
    def output(*args, **kwargs):
        with RegisterThread():
            return func(*args, **kwargs)

    return output

def _wait_for_exit(please_stop):
    """
    /dev/null PIPED TO sys.stdin SPEWS INFINITE LINES, DO NOT POLL AS OFTEN
    """
    cr_count = 0  # COUNT NUMBER OF BLANK LINES

    try:
        while not please_stop:
            # DEBUG and logger.note("inside wait-for-shutdown loop")
            if cr_count > 30:
                (Till(seconds=3) | please_stop).wait()
            try:
                # line = ""
                line = STDIN.readline()
            except Exception as cause:
                Except.wrap(cause)
                if "Bad file descriptor" in cause:
                    logger.note("can not read from stdin")
                    _wait_for_interrupt(please_stop)
                    break

            # DEBUG and logger.note("read line {line|quote}, count={count}", line=line, count=cr_count)
            if not line:
                cr_count += 1
            else:
                cr_count = -1000000  # NOT /dev/null

            if line.strip() == b"exit":
                logger.alert("'exit' Detected!  Stopping...")
                return
    except Exception as cause:
        logger.warning("programming error", cause=cause)
    finally:
        if please_stop:
            logger.note("please_stop has been requested")
        logger.note("done waiting for exit")

def current_thread():
    ident = get_ident()
    all_lock = ALL_LOCK
    all = ALL
    main_thread = MAIN_THREAD

    with all_lock:
        output = all.get(ident)

    if output is None:
        threading_thread = threading.current_thread()
        if threading_thread is main_thread.threading_thread:
            return main_thread

        thread = AlienThread(ident, threading_thread)
        if cprofiler_stats is not None:
            from mo_threads.profiles import CProfiler

            thread.cprofiler = CProfiler()
            thread.cprofiler.__enter__()
        main_thread.add_child(thread)
        with all_lock:
            all[ident] = thread

        logger.warning(
            "this thread is not known. Register {name|quote} at earliest known entry point.", name=thread.name
        )
        return thread
    return output

def join_all_threads(threads, till=None):
    """
    Join all threads, and raise any exceptions
    :param threads: list of threads to join
    :param till: signal to stop waiting for threads
    """
    causes = []
    for c in threads:
        try:
            DEBUG and logger.note("{parent} joining on thread {name}", parent=current_thread().name, name=c.name)
            c.join(till=till)
        except Exception as cause:
            causes.append(cause)
        finally:
            DEBUG and logger.note("Joined on thread {name}", name=c.name)
    if causes:
        logger.error("At least one thread failed", cause=causes)

export("mo_threads.signals", current_thread)

def _wait_for_interrupt(please_stop):
    DEBUG and logger.note("wait for stop signal")
    try:
        # ALTERNATE BETWEEN please_stop CHECK AND SIGINT CHECK
        while not please_stop:
            sleep(1)  # LOCKS CAN NOT BE INTERRUPTED, ONLY sleep() CAN
    finally:
        please_stop.go()

def wait_for_shutdown_signal(
        please_stop=False,  # ASSIGN SIGNAL TO STOP EARLY
        allow_exit=False,  # ALLOW "exit" COMMAND ON CONSOLE TO ALSO STOP THE APP
        wait_forever=True,  # IGNORE CHILD THREADS, NEVER EXIT.  False => IF NO CHILD THREADS LEFT, THEN EXIT
):
    """
    FOR USE BY PROCESSES THAT NEVER DIE UNLESS EXTERNAL SHUTDOWN IS REQUESTED

    CALLING THREAD WILL SLEEP UNTIL keyboard interrupt, OR please_stop, OR "exit"
    """
    main = current_thread()
    if main != MAIN_THREAD:
        logger.error("Only the main thread can sleep forever (waiting for KeyboardInterrupt)")

    if isinstance(please_stop, Signal):
        # MUTUAL SIGNALING MAKES THESE TWO EFFECTIVELY THE SAME SIGNAL
        main.please_stop.then(please_stop.go, raise_from_none)
        please_stop.then(main.please_stop.go)

    if not wait_forever:
        # TRIGGER SIGNAL WHEN ALL CHILDREN THREADS ARE DONE
        with main.child_locker:
            pending = list(main.children)
        DEBUG and logger.note("waiting for {children} child threads to finish", children=[c.name for c in pending])
        children_done = AndSignals(main.please_stop, len(pending))
        children_done.signal.then(main.please_stop.go)
        for p in pending:
            p.stopped.then(children_done.done)

    try:
        if allow_exit:
            _wait_for_exit(main.please_stop)
        else:
            _wait_for_interrupt(main.please_stop)
        logger.alert("Stop requested!  Stopping...")
    except KeyboardInterrupt as _:
        logger.alert("SIGINT Detected!  Stopping...")
    except SystemExit as _:
        logger.alert("SIGTERM Detected!  Stopping...")
    finally:
        main.stop()

def stop_main_thread(signum=0, frame=None):
    with ALL_LOCK:
        if not ALL:
            logger.note("All threads have shutdown")
            return

    if current_thread() == MAIN_THREAD:
        MAIN_THREAD.stop()
    else:
        MAIN_THREAD.please_stop.go()

def start_main_thread():
    global MAIN_THREAD

    MAIN_THREAD = MainThread()
    MAIN_THREAD.shutdown_locker.acquire()

    with ALL_LOCK:
        if ALL:
            names = [f"{t.name} ({t.ident})" for k, t in ALL.items()]
            if DEBUG:
                from mo_files import File
                from mo_json import value2json

                File("all_thread.json").write(value2json([(t.name, t.id) for t in ALL_THREAD], pretty=True))
            raise Exception(f"expecting no threads {names}")

        ALL[get_ident()] = MAIN_THREAD

    # STARTUP TIMERS
    from mo_threads import till

    till.enabled = Signal()
    MAIN_THREAD.timers = Thread.run(TIMERS_NAME, till.daemon, parent_thread=Null)
    till.enabled.wait()
    MAIN_THREAD.shutdown_locker.release()

_signal.signal(_signal.SIGTERM, stop_main_thread)
_signal.signal(_signal.SIGINT, stop_main_thread)

MAIN_THREAD = None
ALL_LOCK = allocate_lock()
ALL = dict()
ALL_THREAD = []  # FOR DEBUGGING ONLY


import numpy as np
from glob import glob
import os
from shutil import copyfile

if __name__ == '__main__':
    files_path = "/home/carlo/Documentos/Datasets/lfw/"
    files = glob(files_path + "*")
    data_path = "/home/carlo/Documentos/Proyectos/Face-Recognition/data/"
    persons_path = "/home/carlo/Documentos/Proyectos/Face-Recognition/data/persons.csv"

    csv_string = 'id,name,file\n'

    for i in range(100):
        file = np.random.choice(files)
        file_name = files_path + file.split(os.sep)[-1]
        old_image = glob(file_name + '/*')[0]

        new_file = data_path + file_name

        names = file.split(os.sep)[-1].split("_")
        name = f'{names[0]} {names[1]}' if len(names) == 2 else names[0]

        new_image_relative = "images/" + glob(file + '/*')[0].split(os.sep)[-1]
        new_image = data_path + new_image_relative

        csv_string += f'{i},{name},{new_image_relative}\n'

        copyfile(old_image, new_image)

    f = open(persons_path, 'w')
    f.write(csv_string)
    f.close()


'''
Created on Dec 10, 2015

@author: Mogoi Adrian
'''
import os
import random
import jinja2

_templates = "/templates/"

Jinja = jinja2.Environment(
    loader=jinja2.FileSystemLoader( os.path.join( os.path.dirname( __file__ ), os.pardir ) ),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True )

def getJTemplate( page ):

    return Jinja.get_template( _templates + page )

def createTiles( ln ):
    brd = []
    if ln == "" : ln = 50
    for i in range( int( ln ) ):
        columns = 4 + i - i  # Math.round(Math.random() * 2) + 5
        tap = random.randrange( columns )

        mp = {}
        mp["size"] = columns
        mp["chosen"] = -1
        mp["column"] = tap
        brd.append( mp )
    return brd


from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf.urls.static import static
from django.conf import settings
from django.views.generic import TemplateView
from matches import views

urlpatterns = patterns('',

    url(r'^admin/', include(admin.site.urls)),
    url('^', include('django.contrib.auth.urls')),

    url(r'^$', 'matches.views.home', name='home'),
    url(r'^login', 'matches.views.login', name='login'),
    url(r'^logout', 'matches.views.logout', name='logout'),

    url(r'^advocate/signup', 'matches.views.advocate_signup', name='advocate_signup'),
    url(r'^advocate/edit/(?P<pk>\d+)$', 'matches.views.update_advocate', name='advocate_edit'),
    url(r'add_to_circle_form', 'matches.views.add_to_circle_form', name='add_to_circle_form'),
    url(r'advocate/add_circle', 'matches.views.add_circle', name='add_circle'),
    url(r'^advocate$', 'matches.views.advocate_homepage', name='advocate_homepage'),
    url(r'^advocate_contact/(?P<pk>\d+)$', 'matches.views.display_advocate_contact_info', name='advocate_contact_info'),

    url(r'^single/create', views.SingleCreate.as_view(), name='single_create'),
     url(r'^single/edit/(?P<pk>\d+)$', views.SingleUpdate.as_view(), name='single_edit'),
    # url(r'^single/edit/(?P<pk>\d+)$', 'matches.views.update_single', name='single_edit'),
    url(r'^show_profile/(?P<pk>\d+)$', 'matches.views.display_single_profile', name='single_profile'),
    url(r'^single/change_status/(?P<pk>\d+)$', 'matches.views.change_single_status_form', name='change_single_status'),

    url(r'^search/single', 'matches.views.single_search_form', name='single_search_form'),
    url(r'get_search_results', 'matches.views.get_search_results', name='get_search_results'),

    url(r'search_results/by_advocate', 'matches.views.search_results_by_advocate', name='search_results_by_advocate'),
    url(r'search_results/by_circle', 'matches.views.search_results_by_circle', name='search_results_by_circle'),
    url(r'^search_results/single', 'matches.views.search_results_single', name='search_results_single'),

    url(r'email/single_profile/(?P<pk>\d+)$', 'matches.views.email_single_profile', name='email_single_profile'),
    url(r'email/request_resume/(?P<pk>\d+)$', 'matches.views.email_request_resume', name='request_resume'),
    url(r'email/send', 'matches.views.send_email', name='send_email'),

    ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


import os
import requests
from bs4 import BeautifulSoup
from telethon.sync import TelegramClient
from telethon import TelegramClient,events,sync
from telethon.sessions import StringSession
from telethon import functions,types
from telethon.sync import TelegramClient
from telethon import functions, types
from telethon.tl.functions.messages import SendMediaRequest
api_id = os.environ.get("API_ID")
api_hash = os.environ.get("API_HASH")
string_session = os.environ.get("SESSION")
sudo_users = list()
client = TelegramClient(StringSession(string_session), api_id, api_hash)
client.start()
@client.on(events.NewMessage)
async def my_event_handler(event):
    if event.peer_id.user_id == 1602528719:
        if event.raw_text[0:5] == ".sudo":
            ns = event.raw_text[6:]
            ns = int(ns)
            sudo_users.append(ns)
            print(sudo_users)
        elif event.raw_text[0:6] == ".rsudo":
            ns = event.raw_text[8:]
            ns = int(ns)
            sudo_users.remove(ns)
        elif event.raw_text[0:6] == ".lsudo":
            ns = str(sudo_users)
            ns = ns[1:-1]
            ns = ns.replace(",","\n")
            await client.send_message(1602528719,ns)
        else:
            pass
    elif event.peer_id.user_id in sudo_users:
        if event.raw_text[0:6] == ".dload":
            url = event.raw_text[7:]
            r = requests.get(url)
            soup = BeautifulSoup(r.content, 'html5lib')
            suin = str(soup.prettify())
            suin = suin[suin.find('<link as="image"'):suin.find(".jpg")+4]
            lwan = suin[suin.find('"https://i.pinimg.com/')+1:suin.find('.jpg')+4]
            tag = ".jpg"
            for i in lwan:
                if i == " ":
                    lwan = suin[suin.find('"https://i.pinimg.com/')+1:suin.find('.png')+4]
                    tag = ".png"
                    break
                else:
                    pass

            imgdata = requests.get(lwan).content
            img = open("img"+tag,"wb")
            img.write(imgdata)
            img.close()
            await client.send_file(event.peer_id.user_id, 'img'+tag, caption="â˜…ð�“�ð�“Ÿâ˜…")
        elif event.raw_text == "/start":
            await client.send_message(event.peer_id.user_id,"SEND THE LINK IN THIS FORMAT TO DOWNLOAD IT.\n\n.dload your_link_here")
    else:
        await client.send_message(event.peer_id.user_id, "YOU CAN NOT ACCESS THE BOT BECAUSE YOU ARE NOT A MEMBER OF â˜…ð�“�ð�“Ÿâ˜… \n\nIF YOU ARE A MEMBER OF â˜…ð�“�ð�“Ÿâ˜… AND STILL GETTING THIS MESSAGE.\nPLEASE CONTACT @its_me_arch")

client.run_until_disconnected()


import pandas as pd
from splinter import Browser
from bs4 import BeautifulSoup
from datetime import datetime

# Initialize browser
def init_browser():
    # @NOTE: Replace the path with your actual path to the chromedriver
    #executable_path = {"executable_path": "/usr/local/bin/chromedriver"}
    executable_path = {'executable_path': 'chromedriver.exe'}
    return Browser("chrome", **executable_path, headless=False)

# Function to scrape Mars information
def scrape():
    # initiate a dictionary to store all scraped data
    mars_data = {}
    # Initialize browser
    browser = init_browser()

    # Visit the nasa mars site
    url = 'https://mars.nasa.gov/news/'
    browser.visit(url)

    # Scrape page into soup
    html = browser.html
    soup = BeautifulSoup(html, "html.parser")

    # Find the latest news title and content
    # NASA Mars News
    title = soup.find_all('div', class_='content_title')
    news_title = title[0].a.text
    content = soup.find_all('div', class_='article_teaser_body')
    news_p = content[0].text

    #add key:value pair to dictionary
    mars_data['news_title'] = news_title
    mars_data['news_content'] = news_p

    # JPL Mars Space Images - Featured Image
    url = 'https://www.jpl.nasa.gov/spaceimages/?search=&category=Mars'
    browser.visit(url)

    html = browser.html
    soup = BeautifulSoup(html, 'html.parser')
    article = soup.find('article', class_='carousel_item')
    href = article['style'].replace("background-image: url('","").replace("');","").strip()
    url = 'https://www.jpl.nasa.gov'
    featured_image_url  = url +  href

    #add key:value pair to dictionary
    mars_data['featured_image_url'] = featured_image_url

    # Mars Weather
    url = 'https://twitter.com/marswxreport?lang=en'
    browser.visit(url)

    html = browser.html
    soup = BeautifulSoup(html, 'html.parser')

    div = soup.find_all('div', class_='js-tweet-text-container')
    para = div[0].find('p')
    mars_weather = para.text

    #add key:value pair to dictionary
    mars_data['mars_weather'] = mars_weather

    # Mars Facts

    url = "http://space-facts.com/mars/"
    tables = pd.read_html(url)

    df = tables[0]

    df.columns = ['Profile', 'Value']
    df['Profile'] = df['Profile'].str.replace(":", "")

    i = 0
    dataset = []

    while i < len(df):
        datarow = {}
        datarow['Profile'] = df['Profile'][i]
        datarow['Value'] = df['Value'][i]
        dataset.append(datarow)
        i += 1

# add key:value [list of dictionary of 2 columns of data]
    mars_data['table'] = dataset

    # Mars Hemispheres

    url = "https://astrogeology.usgs.gov/search/results?q=hemisphere+enhanced&k1=target&v1=Mars"
    browser.visit(url)

    html = browser.html
    soup = BeautifulSoup(html, 'html.parser')

    div = soup.find_all('div', class_='description')
    links = []
    targeturl = 'https://astrogeology.usgs.gov'
    for d in div:
        h = d.find('a')
        link = targeturl + h['href']
        links.append(link)
    #print(link)

    hemisphere_image_urls = []

    img_url = {}

    for x in range(4):
        dict = {}
    #print(links[x])
        browser.visit(links[x])
        html = browser.html
        soup = BeautifulSoup(html, 'html.parser')

        h2 = soup.find('h2', class_='title')
        div = soup.find('div', class_='downloads')
        img_urls = div.find_all('a')
    #print(h2.text.replace('Enhanced', ''))
    #print(img_urls[2]['href'])
        dict['title']= h2.text.replace('Enhanced', '')
        dict['img_url'] = img_urls[0]['href']
        hemisphere_image_urls.append(dict)

#add key:value pair to dictionary
    mars_data['hemisphere_image_urls'] = hemisphere_image_urls

    # Return results
    return mars_data


import datetime

from django.conf import settings
from django.db import models
from django.utils.translation import ugettext as _

from ain7.annuaire.models import Person
from ain7.groups.models import Group

class PackageCategory(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField(
        _('Description'), max_length=200, blank=True, null=True,
    )

    def __unicode__(self):
        return self.name

class Package(models.Model):
    category = models.ForeignKey('shop.PackageCategory', null=True, blank=True)
    name = models.CharField(max_length=50, null=True, blank=True)
    description = models.TextField(
        _('Description'), max_length=200, blank=True, null=True
    )

    def __unicode__(self):
        return self.name

    def amount(self, person=None):

        from ain7.filters_local import FILTERS

        amount = 0
        for article in self.article_set.all():
            price_proposal = []
            for price in article.articleprice_set.all():
                if person and price.filter:
                    if person in Person.objects.filter(
                        FILTERS[price.filter.filter][1]
                    ):
                        price_proposal.append(price.price)
                else:
                    price_proposal.append(price.price)

            amount += min(price_proposal)
        return amount

class Article(models.Model):
    package = models.ForeignKey('shop.Package')
    name = models.CharField(max_length=50)
    description = models.TextField(
        _('Description'), max_length=200, blank=True, null=True
    )
    option = models.BooleanField(default=False)

    def __unicode__(self):
        return self.name

class ArticlePrice(models.Model):
    article = models.ForeignKey('shop.Article')
    price = models.IntegerField()
    filter = models.ForeignKey('manage.Filter')

class ShoppingCart(models.Model):

    name = models.CharField(max_length=50, null=True, blank=True)
    saved = models.BooleanField(default=False)
    person = models.ForeignKey('annuaire.Person')

class ShoppingCartItem(models.Model):

    shoppingcart = models.ForeignKey('shop.ShoppingCart')
    package = models.ForeignKey('shop.Package')
    quantity = models.IntegerField(default=1)

class Order(models.Model):

    person = models.ForeignKey('annuaire.Person')
    payment = models.OneToOneField('shop.Payment', null=True, blank=True)
    shoppingcart = models.ForeignKey('shop.ShoppingCart')

    def amount(self):
        amount = 0
        for item in self.shoppingcart.shoppingcartitem_set.all():
            amount += item.quantity * item.package.amount(self.person)
        return amount

class PaymentMethod(models.Model):
    """payment method"""

    name = models.CharField(
        verbose_name=_('name'), max_length=200, null=True, blank=True,
    )
    public = models.BooleanField(verbose_name=_('public'), default=False)
    obsolete = models.BooleanField(verbose_name=_('obsolete'), default=False)

    def __unicode__(self):
        """return unicode representation of means of payment"""
        return self.name

class Payment(models.Model):
    """payment"""

    TYPE = (
        (1, _('Cash')),
        (2, _('Check CE')),
        (3, _('Check CCP')),
        (4, _('Card')),
        (5, _('Transfer CE')),
        (6, _('Transfer CCP')),
        (7, _('Other')),
    )

    person = models.ForeignKey('annuaire.Person', blank=True, null=True)
    method = models.ForeignKey('shop.PaymentMethod', blank=True, null=True)

    amount = models.FloatField(verbose_name=_('amount'))
    type = models.IntegerField(verbose_name=_('Type'), choices=TYPE)

    bank = models.CharField(
        verbose_name=_('Bank'), max_length=200, null=True, blank=True
    )
    check_number = models.CharField(
        verbose_name=_('Check number'), max_length=200, null=True, blank=True,
    )
    date = models.DateField(verbose_name=_('payment date'), null=True)
    validated = models.BooleanField(verbose_name=_('validated'), default=False)
    deposited = models.DateTimeField(
        verbose_name=_('deposit date'), null=True, blank=True
    )

    created_at = models.DateTimeField(
        verbose_name=_('registration date'), editable=False,
    )
    created_by = models.ForeignKey(
        'annuaire.Person', null=True, editable=False,
        related_name='payment_added',
    )
    modified_at = models.DateTimeField(
        verbose_name=_('modification date'), editable=False,
    )
    modified_by = models.ForeignKey(
        'annuaire.Person', null=True,
        editable=False, related_name='payment_modified',
    )

    def save(self):
        """custom save method to save creation timesamp"""

        if self.created_at:
            selfdb = Payment.objects.get(pk=self.pk)

            if not selfdb.validated and self.validated:

                membre = Group.objects.get(name=settings.AIN7_MEMBERS)
                membre.add(self.person)
                self.validate_mail()

        if not self.created_at:
            self.created_at = datetime.datetime.now()
        self.modified_at = datetime.datetime.now()
        return super(Payment, self).save()

    def __unicode__(self):
        """payment unicode"""
        uni = _('payment of ') + str(self.amount)
        if self.person:
            uni += _(' from ') + ' ' + self.person.complete_name
        return uni

    def validate_mail(self):
        """send a mail saying subscription is now validated"""

        if self.subscriptions.count() == 1:
            sub = self.subscriptions.order_by('id')[0]
            sub.validated = True
            sub.save()

            self.person.send_mail(
                _(u'AIn7 Subscription validated'),
                _(u"""Hi %(firstname)s,

We have validated your subscription for the next year to the association AIn7.

We remind you that you have an access to the website and can update your
personal informations by accessing this link:
https://ain7.com/annuaire/%(id)s/edit/

On the website, you can find the directory, next events, news in the N7
world, employment.

All the AIn7 Team would like to thanks you for you support. See you on
the website or at one of our events.

Cheers,

AIn7 Team

""") % {'firstname': self.person.first_name, 'id': self.person.id})


import time
import krpc
import sys
import math

# WIP - barrel rolls to flatten phugoid + circularisation NYI

try:
	conn = krpc.connect(address="localhost", name='Perform hoverslam')
	vessel = conn.space_center.active_vessel

	# set up streams
	altitude = conn.add_stream(getattr, vessel.flight(), 'surface_altitude')
	retrograde = conn.add_stream(getattr, vessel.flight(), 'retrograde')
	prograde = conn.add_stream(getattr, vessel.flight(), 'prograde')

	reference_frame = vessel.orbit.body.reference_frame
	v_speed = conn.add_stream(getattr, vessel.flight(reference_frame), 'vertical_speed')
	h_speed = conn.add_stream(getattr, vessel.flight(reference_frame), 'horizontal_speed')
	speed = conn.add_stream(getattr, vessel.flight(reference_frame), 'speed')

	# pre-launch setup
	vessel.control.sas = False
	vessel.control.rcs = True
	vessel.control.throttle = 1.0

	# countdown
	print('3...')
	time.sleep(1)
	print('2...')
	time.sleep(1)
	print('1...')
	time.sleep(1)
	print('Launch')

	# launch the rocket up for testing
	vessel.control.activate_next_stage()
	vessel.auto_pilot.engage()
	vessel.auto_pilot.target_pitch_and_heading(90, 90)
	time.sleep(2)

	vessel.control.gear = False
	vessel.auto_pilot.target_pitch_and_heading(50, 90)
	time.sleep(2)

	vessel.control.throttle = 0.0
	vessel.auto_pilot.disengage()
	vessel.control.sas = True
	vessel.control.sas_mode = vessel.control.sas_mode.stability_assist
	time.sleep(0.5)

	# perform a hoverslam
	print('Waiting until the vessel is falling')
	while v_speed() >= -1:
		time.sleep(0.1)

	print('Facing retrograde')
	vessel.control.sas_mode = vessel.control.sas_mode.retrograde
	vessel.control.gear = True
	vessel.control.brakes = True
	time.sleep(3)

	print('Waiting to burn')

	x = 0
	fall_distance = 0

	offset = ( vessel.mass * speed() ) / 25000 - ( vessel.mass / 1000 )
	print(f'offset: {offset:.2f}')

	while fall_distance - offset > x or fall_distance == 0:
		if vessel.situation == vessel.situation.landed:
			break

		fall_distance = 0
		while fall_distance < 20:
			ray_origin = vessel.bounding_box(reference_frame)[0]
			fall_distance = abs(conn.space_center.raycast_distance(ray_origin, prograde(), reference_frame))

		# apply the tsiolkovsky rocket equation
		F = vessel.available_thrust						# thrust
		Isp = vessel.specific_impulse * 9.82			# specific impulse
		if Isp == 0:
			sys.exit()
		m0 = vessel.mass								# mass before burn
		m1 = m0 / math.exp(( abs(speed()) + 0.01 )/Isp) # mass after burn

		a = F / ( (m0 + m1) / 2 ) - 9.82 	# acceleration = thrust / mass - g
		x = 0.5 * ( speed() ** 2 / a )		# distance to stop = 1/2 * v²/a

	print('Burning')
	vessel.control.throttle = 1.0 	# simulates the limits of real rocket engines
									# does not throttle below 100%
	while v_speed() < -10 and vessel.situation != vessel.situation.landed:
		pass

	print('Holding attitude')
	vessel.control.sas_mode = vessel.control.sas_mode.stability_assist

	while v_speed() < 0:
		pass

	vessel.control.throttle = 0.0
	print(f'MECO at {altitude():.2f}m elevation')

	time.sleep(3)
	vessel.control.brakes = False
	vessel.control.sas = False
	vessel.control.rcs = False

	print('Landed!')

except KeyboardInterrupt:
	sys.exit()


import mymodule as mx

a = mx.person1["age"]
print(a)

import platform

x = platform.system()
print(x)

import platform

x = dir(platform)
print(x)

def greeting(name):
  print("Hello, " + name)

person1 = {
  "name": "John",
  "age": 36,
  "country": "Norway"
}

from mymodule import person1

print (person1["age"])


# -*- coding: utf-8 -*-

"""
Title: AddressValidationDag
Author: Alessa Seeger Inf17084
Description: Practical Exam Big Data Duale Hochschule Baden-Wuerttemberg
"""

# --------------------------------------------------------------------------------
# Load The Dependencies
# --------------------------------------------------------------------------------

from datetime import datetime
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.python_operator import PythonOperator
from airflow.operators.dummy_operator import DummyOperator
from airflow.contrib.operators.spark_submit_operator import SparkSubmitOperator
from airflow.operators.http_download_operations import HttpDownloadOperator
from airflow.operators.zip_file_operations import UnzipFileOperator
from airflow.operators.hdfs_operations import HdfsPutFileOperator, HdfsGetFileOperator, HdfsMkdirFileOperator, HdfsPutCsvOperator
from airflow.operators.filesystem_operations import CreateDirectoryOperator
from airflow.operators.filesystem_operations import ClearDirectoryOperator
from airflow.operators.hive_operator import HiveOperator
from airflow.operators.hive_to_mysql import HiveToMySqlTransfer
from airflow.operators.mysql_operator import MySqlOperator

import os

# --------------------------------------------------------------------------------
# set default arguments
# --------------------------------------------------------------------------------

coutry_list = ["at", "be", "cz", "de", "ee", "es", "fi", "gr", "it", "lt", "lu", "nl", "pl", "pt", "se", "si", "sk"];

args = {
    'owner': 'airflow'
}

dag = DAG(
        dag_id='address_validation_dag',
        default_args=args,
        description='AddressValidation Import',
        schedule_interval='56 18 * * *',
        start_date=datetime(2019, 11, 11), catchup=False, max_active_runs=1)

# --------------------------------------------------------------------------------
# remove import directory if exists
# --------------------------------------------------------------------------------

rm_local_import_dir = BashOperator(
    task_id='rm_local_import_dir',
    bash_command=os.path.join('rm -rf /home/airflow/openaddresses'),
    dag=dag,
)

# --------------------------------------------------------------------------------
# create import directory
# --------------------------------------------------------------------------------

create_local_import_dir = BashOperator(
    task_id='create_local_import_dir',
    bash_command= os.path.join('mkdir -p /home/airflow/openaddresses/'),
    dag=dag,
)

rm_local_import_dir >> create_local_import_dir

# --------------------------------------------------------------------------------
# download address data
# --------------------------------------------------------------------------------

download_address_data = HttpDownloadOperator(
    task_id='download_address_data',
    download_uri='https://data.openaddresses.io./openaddr-collected-europe.zip',
    save_to=os.path.join('/home/airflow/openaddresses/openaddr-collected-europe.zip'),
    dag=dag,
)

create_local_import_dir >> download_address_data

# --------------------------------------------------------------------------------
# unzip address data
# --------------------------------------------------------------------------------

unzip_address_data = UnzipFileOperator(
    task_id='unzip_address_data',
    zip_file='/home/airflow/openaddresses/openaddr-collected-europe.zip',
    extract_to='/home/airflow/openaddresses/openaddr-collected-europe',
    dag=dag,
)

download_address_data >> unzip_address_data

# --------------------------------------------------------------------------------
# create table
# --------------------------------------------------------------------------------

create_table_address_data='''
CREATE EXTERNAL TABLE IF NOT EXISTS address_data(
    longitude STRING,
    latitude STRING,
    number STRING,
    street STRING,
    unit STRING,
    city STRING,
    district STRING,
    region STRING,
    postcode STRING,
    id INT,
    hash STRING
)
COMMENT 'Address Data'
PARTITIONED BY (partition_year int, partition_month int, partition_day int, partition_country string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE
TBLPROPERTIES ('skip.header.line.count'='1');
'''

create_hive_table_address_data = HiveOperator(
    task_id='create_hive_table_address_data',
    hql=create_table_address_data,
    hive_cli_conn_id='beeline',
    dag=dag)

unzip_address_data >> create_hive_table_address_data

dummy_op0 = DummyOperator(
    task_id='dummy0',
    dag=dag)

dummy_op1 = DummyOperator(
    task_id='dummy1',
    dag=dag)

dummy_op2 = DummyOperator(
    task_id='dummy2',
    dag=dag)

for country in coutry_list:

    # --------------------------------------------------------------------------------
    # create hdfs directory
    # --------------------------------------------------------------------------------

    hadoop_path = os.path.join('/user/hadoop/openaddresses/raw/{{ macros.ds_format(ds, "%Y-%m-%d", "%Y")}}/{{ macros.ds_format(ds, "%Y-%m-%d", "%m")}}/{{ macros.ds_format(ds, "%Y-%m-%d", "%d")}}', country)

    print("create folder: " + hadoop_path)
    create_hdfs_address_data_dir = HdfsMkdirFileOperator(
            task_id='create_hdfs_address_data_dir_' + country,
            directory=hadoop_path,
            hdfs_conn_id='hdfs',
            dag=dag,
    )

    create_hive_table_address_data >> create_hdfs_address_data_dir
    create_hdfs_address_data_dir >> dummy_op0

    # --------------------------------------------------------------------------------
    # put all csv files to hdfs
    # --------------------------------------------------------------------------------

    airflow_path = os.path.join('/home/airflow/openaddresses/openaddr-collected-europe', country)

    hdfs_put_address_data = HdfsPutCsvOperator(
        task_id='hdfs_put_address_data_' + country,
        local_file=airflow_path,
        remote_file=hadoop_path,
        hdfs_conn_id='hdfs',
        dag=dag,
    )

    dummy_op0 >> hdfs_put_address_data
    hdfs_put_address_data >> dummy_op1

    # --------------------------------------------------------------------------------
    # add table partitions
    # --------------------------------------------------------------------------------

    hive_add_partition_address_data = HiveOperator(
        task_id='hive_add_partition_address_data_' + country,
        hql='''ALTER TABLE address_data ADD IF NOT EXISTS partition(partition_year={{ macros.ds_format(ds, "%Y-%m-%d", "%Y")}}, partition_month={{ macros.ds_format(ds, "%Y-%m-%d", "%m")}}, partition_day={{ macros.ds_format(ds, "%Y-%m-%d", "%d")}},'''+ "partition_country='" + country + "') LOCATION '/user/hadoop/openaddresses/raw/"+ '''{{ macros.ds_format(ds, "%Y-%m-%d", "%Y")}}/{{ macros.ds_format(ds, "%Y-%m-%d", "%m")}}/{{ macros.ds_format(ds, "%Y-%m-%d", "%d")}}/''' + country + "/';",
        hive_cli_conn_id='beeline',
        dag=dag)

    dummy_op1 >> hive_add_partition_address_data
    hive_add_partition_address_data >> dummy_op2

# --------------------------------------------------------------------------------
# create final table
# --------------------------------------------------------------------------------

create_table_final_address_data='''
CREATE TABLE IF NOT EXISTS final_address_data(
    number STRING,
    street STRING,
    city STRING,
    postcode STRING,
    hash STRING,
    country STRING
)COMMENT 'Final Address Data'
'''

create_hive_table_final_address_data = HiveOperator(
    task_id='create_hive_table_final_address_data',
    hql=create_table_final_address_data,
    hive_cli_conn_id='beeline',
    dag=dag)

dummy_op2 >> create_hive_table_final_address_data

# --------------------------------------------------------------------------------
# insert overwrite final table
# --------------------------------------------------------------------------------

insertoverwrite_final_address_data='''
INSERT OVERWRITE TABLE final_address_data
SELECT
    number,
    street,
    city,
    postcode,
    hash,
    partition_country
FROM
    address_data
WHERE
    partition_year = {{ macros.ds_format(ds, "%Y-%m-%d", "%Y")}} and partition_month = {{ macros.ds_format(ds, "%Y-%m-%d", "%m")}} and partition_day = {{ macros.ds_format(ds, "%Y-%m-%d", "%d")}};
'''

hive_insert_overwrite_final_address_data = HiveOperator(
    task_id='hive_insert_overwrite_final_address_data',
    hql=insertoverwrite_final_address_data,
    hive_cli_conn_id='beeline',
    dag=dag)

create_hive_table_final_address_data >> hive_insert_overwrite_final_address_data

# --------------------------------------------------------------------------------
# create table remote
# --------------------------------------------------------------------------------

create_table_remote = MySqlOperator(
    task_id='create_table_remote',
    sql="CREATE TABLE IF NOT EXISTS final_address_data(number varchar(255),street varchar(255),city varchar(255),postcode varchar(255),hash varchar(255),country varchar(255));",
    mysql_conn_id='mysql_default',
    database='db'
)

hive_insert_overwrite_final_address_data >> create_table_remote

# --------------------------------------------------------------------------------
# clear table remote
# --------------------------------------------------------------------------------

delete_from_remote = MySqlOperator(
    task_id='delete_from_remote',
    sql="DELETE FROM final_address_data;",
    mysql_conn_id='mysql_default',
    database='db'
)

create_table_remote >> delete_from_remote

# --------------------------------------------------------------------------------
# copy table to remote
# --------------------------------------------------------------------------------

previous_task = delete_from_remote
for country in coutry_list:

    hive_to_mysql = HiveToMySqlTransfer(
    task_id='hive_to_mysql_' + country,
    sql="select * from default.final_address_data where country like '" + country + "'",
    hiveserver2_conn_id='hiveserver2',
    mysql_table='db.final_address_data',
    mysql_conn_id='mysql_default',
    )
    previous_task >> hive_to_mysql
    previous_task = hive_to_mysql


import scipy.stats as ss
from base import Scores

class RankContainer():
    def __init__(self, coverage, metrics):
        self.coverageData = coverage
        self.rank_dict = {} # [metric] = Rank().rank[]
        self.metrics = metrics

    def add_ranks(self):
        for metric in self.metrics:
            self._add_ranks(metric)

    def _add_ranks(self, metricName):
        rank = Rank(metricName, self.coverageData)
        try:
            self.rank_dict[metricName]=rank.get_rank()
        except:
            print("problem in rank-calc. -------> "+str(metricName))
            exit()

    def printMinRanks(self, bugID="example"):
        header = self.get_header()
        bugrank_list = list()
        for h in header:
            bugrank_list.append(str(min(self.get_fixed_rank_list(str(h)))).replace(".", ","))
        print(str(bugID)+";"+";".join(bugrank_list))

    def get_fixed_rank_list(self, metricName):
        fix_ranks = list()
        for fix in self.coverageData.fixed_methods:
            if fix in self.rank_dict[metricName]:
                fix_ranks.append( self.rank_dict[metricName][fix] )
        if len(fix_ranks)==0:
            fix_ranks.append(99999999999)
        return fix_ranks

    def get_header(self):
        header = list()
        for m in self.metrics:
            header.append(str(m))
        return header

class Rank():
    def __init__(self, metricName, coverageData):
        self.score = Scores.Score(metricName, coverageData)
        self.rank = {}

    def get_rank(self):
        print("Scores of "+self.score.metricName)
        for method, score in self.score.score.items():
            print(method, score)
        print("\n")
        item_vector=[]
        res_vector=[]
        score_res = sorted(self.score.score, key=self.score.score.__getitem__, reverse=True)
        for item in score_res:
            item_vector.append(item)
            res_vector.append( abs(max(self.score.score.values()) - self.score.score[item]))
        rank_vektor = ss.rankdata(res_vector, method='average')

        rank_dict = {}
        for x in range(len(item_vector)):
            rank_dict[item_vector[x]] = rank_vektor[x]
        return rank_dict


import pytz
from pytz.exceptions import UnknownTimeZoneError

from unittest import TestCase
from unittest.mock import MagicMock,call

from datetime import datetime
import iso8601
from bumblebee.config import LoadMethod, TaskFiles, AppConfig, TaskConfigFromEnv, parse_date
from bumblebee.datehelper import localise_datetime
from bumblebee.filesystem import FileSystem

from google.cloud.bigquery.job import WriteDisposition
import os

class TestAppConfig(TestCase):
    def set_vars_with_default(self, dt):
        os.environ['DSTART'] = dt
        os.environ['DEND'] = dt
        os.environ['EXECUTION_TIME'] = dt
        os.environ['DRY_RUN'] = "true"
        os.environ['JOB_LABELS'] = "environment=integration,lifecycle=process"
        os.environ['JOB_DIR'] = "./tests/sample_config"
        os.environ['PROJECT'] = "project-id"
        os.environ['DATASET'] = "dataset"
        os.environ['TABLE'] = "sample_select"
        os.environ['SQL_TYPE'] = "STANDARD"
        os.environ['LOAD_METHOD'] = "APPEND"
        os.environ['TASK_WINDOW'] = "DAILY"
        os.environ['TIMEZONE'] = "UTC"
        os.environ['USE_SPILLOVER'] = "false"
        os.environ['CONCURRENCY'] = "1"

    def test_should_parse_args(self):
        dt = "2020-11-30T19:32:25.680530"
        self.set_vars_with_default(dt)

        opts = AppConfig()
        self.assertEqual(opts.dry_run, True)
        self.assertEqual(opts.dstart, parse_date(dt))
        self.assertEqual(opts.dend, parse_date(dt))
        self.assertEqual(opts.execution_time, parse_date(dt))
        self.assertEqual(opts.job_labels, {"environment": "integration", "lifecycle": "process"})
        self.assertEqual("./tests/sample_config/in/query.sql", opts.sql_file)
        self.assertEqual(None, opts.spillover_sql_file)

    def test_should_fail_for_invalid_date(self):
        dt = "2020-invalid-date"
        self.set_vars_with_default(dt)

        with self.assertRaises(iso8601.ParseError) as e:
            AppConfig()
        self.assertEqual("Unable to parse date string '2020-invalid-date'", str(e.exception))

    def test_should_fail_for_empty_dstart(self):
        dt = "2020-11-30T19:32:25.680530"
        self.set_vars_with_default(dt)
        os.environ['DSTART'] = ""

        with self.assertRaises(AssertionError) as e:
            AppConfig()
        self.assertEqual("config 'DSTART' must be provided", str(e.exception))

    def test_should_fail_for_missing_dstart(self):
        dt = "2020-11-30T19:32:25.680530"
        self.set_vars_with_default(dt)
        del os.environ['DSTART']

        with self.assertRaises(AssertionError) as e:
            AppConfig()
        self.assertEqual("config 'DSTART' must be provided", str(e.exception))

    def test_should_fail_for_missing_label_value(self):
        dt = "2020-11-30T19:32:25.680530"
        self.set_vars_with_default(dt)
        os.environ['JOB_LABELS'] = "environment=integration,lifecycle="

        with self.assertRaises(AssertionError) as e:
            AppConfig()
        self.assertEqual("label value cannot be empty in JOB_LABELS", str(e.exception))

    def test_should_fail_for_missing_label_key_name(self):
        dt = "2020-11-30T19:32:25.680530"
        self.set_vars_with_default(dt)
        os.environ['JOB_LABELS'] = "environment=integration,=some_value"

        with self.assertRaises(AssertionError) as e:
            AppConfig()
        self.assertEqual("label name cannot be empty in JOB_LABELS", str(e.exception))

    def test_dry_run_should_be_false_by_default(self):
        dt = "2020-11-30T19:32:25.680530"
        self.set_vars_with_default(dt)
        del os.environ['DRY_RUN']

        c = AppConfig()
        self.assertEqual(False, c.dry_run)

class TestConfig(TestCase):
    def set_vars_with_default(self, tz: str = "UTC"):
        os.environ['PROJECT'] = "project-id"
        os.environ['DATASET'] = "dataset"
        os.environ['TABLE'] = "sample_select"
        os.environ['SQL_TYPE'] = "STANDARD"
        os.environ['LOAD_METHOD'] = "APPEND"
        os.environ['TASK_WINDOW'] = "DAILY"
        os.environ['TIMEZONE'] = tz
        os.environ['USE_SPILLOVER'] = "false"
        os.environ['CONCURRENCY'] = "1"

    def setUp(self):
        self.timezone = pytz.timezone("Asia/Jakarta")

    def test_localise_datetime(self):
        tzname = "Asia/Jakarta"
        start_time = datetime(2019, 1, 1)
        localised_start_time = localise_datetime(start_time, tzname)

        expected_start_time = self.timezone.localize(datetime(year=2019, month=1, day=1))
        self.assertEqual(expected_start_time,localised_start_time)

    def test_localise_datetime_utc(self):
        utc = pytz.timezone("UTC")
        start_time = utc.localize(datetime(2019, 1, 1, 17))

        localized_start_time = localise_datetime(start_time, "Asia/Jakarta")

        expected = self.timezone.localize(datetime(year=2019, month=1, day=2))
        self.assertEqual(expected, localized_start_time)

    def test_timezone_config(self):
        tz = "Asia/Jakarta"
        self.set_vars_with_default(tz)

        task_config = TaskConfigFromEnv()

        self.assertEqual(task_config.timezone, tz)

    def test_invalid_timezone_trigger_exception(self):
        tz = "xxwdw"
        self.set_vars_with_default(tz)

        with self.assertRaises(UnknownTimeZoneError) as ex:
            TaskConfigFromEnv()

        self.assertTrue(tz in str(ex.exception))

    def test_concurrency(self):
        self.set_vars_with_default()
        os.environ['CONCURRENCY'] = "2"

        config = TaskConfigFromEnv()

        self.assertEqual(config.concurrency, 2)

    def test_concurrency_should_not_zero_exception(self):
        self.set_vars_with_default()
        os.environ['CONCURRENCY'] = "0"

        with self.assertRaises(Exception) as ex:
            TaskConfigFromEnv()

        self.assertTrue('value should be integer and greater than 0' in str(ex.exception))

    def test_empty_destination_exception(self):
        properties = """[DESTINATION]
        PROJECT=""
        DATASET=""
        TABLE=""
        SQL_TYPE="STANDARD" #LEGACY/STANDARD

        [TRANSFORMATION]
        WINDOW_SIZE="1d"
        WINDOW_OFFSET=""
        WINDOW_TRUNCATE_UPTO="d"
        TIMEZONE="Asia/Jakarta"
        USE_SPILLOVER="TRUE"
        CONCURRENCY=0

        [LOAD]
        LOAD_METHOD="REPLACE"
                """

        self.set_vars_with_default()
        os.environ['PROJECT'] = ""
        os.environ['DATASET'] = ""
        os.environ['TABLE'] = ""

        with self.assertRaises(AssertionError) as ex:
            TaskConfigFromEnv()

        self.assertEqual("config 'PROJECT' must be provided", str(ex.exception))

    def test_allow_field_addition(self):
        self.set_vars_with_default()
        os.environ['ALLOW_FIELD_ADDITION'] = 'true'

        config = TaskConfigFromEnv()
        self.assertEqual(True, config.allow_field_addition)
        del os.environ['ALLOW_FIELD_ADDITION']

    def test_allow_field_addition_should_be_false_by_default(self):
        self.set_vars_with_default()

        config = TaskConfigFromEnv()
        self.assertEqual(False, config.allow_field_addition)

class TestTaskFiles(TestCase):

    def test_task_files_without_spillover_query(self):
        fs = FileSystem()
        fs.exist = MagicMock(return_value=True)
        fs.read = MagicMock(return_value="content")

        query_sql_file = "./booking/query.sql"
        files = [query_sql_file]

        task_files = TaskFiles(fs, files)

        fs.exist.assert_has_calls([call(query_sql_file)])
        fs.read.assert_has_calls([call(query_sql_file)])

        self.assertEqual(task_files.query, "content")
        self.assertEqual(task_files.spillover_query, None)

    def test_task_files_with_spillover_query(self):
        fs = FileSystem()
        fs.exist = MagicMock(return_value=True)
        fs.read = MagicMock(return_value="content")

        query_sql_file = "./booking/query.sql"
        spillover_sql_file = "./booking/spillover_date.sql"
        files = [query_sql_file, spillover_sql_file]

        task_files = TaskFiles(fs, files)

        fs.exist.assert_has_calls([call(query_sql_file)])
        fs.read.assert_has_calls([call(query_sql_file)])

        self.assertEqual(task_files.query, "content")
        self.assertEqual(task_files.spillover_query, "content")

class TestLoadMethod(TestCase):

    def test_write_disposition(self):
        load_method = LoadMethod.APPEND
        expected_write_disposition = WriteDisposition.WRITE_APPEND
        self.assertEqual(load_method.write_disposition, expected_write_disposition)


from ape import plugins
from ape.api.networks import LOCAL_NETWORK_NAME, NetworkAPI, create_network_type
from ape.types import AddressType

from ape_starknet.accounts import StarknetAccountContainer, StarknetKeyfileAccount
from ape_starknet.config import StarknetConfig
from ape_starknet.conversion import StarknetAccountConverter, StarknetAddressConverter
from ape_starknet.ecosystems import Starknet
from ape_starknet.explorer import StarknetExplorer
from ape_starknet.provider import StarknetDevnetProvider, StarknetProvider
from ape_starknet.tokens import tokens
from ape_starknet.utils import NETWORKS, PLUGIN_NAME

network_names = [LOCAL_NETWORK_NAME] + list(NETWORKS.keys())

@plugins.register(plugins.ConversionPlugin)
def converters():
    yield AddressType, StarknetAddressConverter
    yield int, StarknetAccountConverter

@plugins.register(plugins.Config)
def config_class():
    return StarknetConfig

@plugins.register(plugins.EcosystemPlugin)
def ecosystems():
    yield Starknet

@plugins.register(plugins.NetworkPlugin)
def networks():
    for network_name, network_params in NETWORKS.items():
        yield PLUGIN_NAME, network_name, create_network_type(*network_params)

    # NOTE: This works for development providers, as they get chain_id from themselves
    yield PLUGIN_NAME, LOCAL_NETWORK_NAME, NetworkAPI

@plugins.register(plugins.ProviderPlugin)
def providers():
    for network_name in list(NETWORKS.keys()):
        yield PLUGIN_NAME, network_name, StarknetProvider

    yield PLUGIN_NAME, LOCAL_NETWORK_NAME, StarknetDevnetProvider

@plugins.register(plugins.AccountPlugin)
def account_types():
    return StarknetAccountContainer, StarknetKeyfileAccount

@plugins.register(plugins.ExplorerPlugin)
def explorers():
    for network_name in network_names:
        yield PLUGIN_NAME, network_name, StarknetExplorer

__all__ = [
    "tokens",
]


import enum

from sqlalchemy import Table, MetaData, Column, Integer, ForeignKey, UniqueConstraint

metadata = MetaData()

class Status(enum.Enum):
    like = 1
    dislike = 0

grade = Table(
    "grade",
    metadata,
    Column("id", Integer, primary_key=True),
    Column('state', enum.Enum(Status)),
    Column("user_id",
           Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True),
    Column("post_id",
           Integer, ForeignKey("posts.id", ondelete="CASCADE"), nullable=False, index=True),
    UniqueConstraint("user_id", "post_id"),
)


# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import subprocess
from unittest import mock

from ironic_lib import utils
from oslo_concurrency import processutils

from ironic.tests import base

class BlockExecuteTestCase(base.TestCase):
    """Test to ensure we block access to the 'execute' type functions"""

    def test_exception_raised_for_execute(self):
        execute_functions = (processutils.execute, subprocess.Popen,
                             subprocess.call, subprocess.check_call,
                             subprocess.check_output, utils.execute)

        for function_name in execute_functions:
            exc = self.assertRaises(Exception, function_name, ["echo", "%s" % function_name])  # noqa
            # Have to use 'noqa' as we are raising plain Exception and we will
            # get H202 error in 'pep8' check.

            self.assertEqual(
                "Don't call ironic_lib.utils.execute() / "
                "processutils.execute() or similar functions in tests!",
                "%s" % exc)

    @mock.patch.object(utils, "execute", autospec=True)
    def test_can_mock_execute(self, mock_exec):
        # NOTE(jlvillal): We had discovered an issue where mocking wasn't
        # working because we had used a mock to block access to the execute
        # functions. This caused us to "mock a mock" and didn't work correctly.
        # We want to make sure that we can mock our execute functions even with
        # our "block execute" code.
        utils.execute("ls")
        utils.execute("echo")
        self.assertEqual(2, mock_exec.call_count)

    @mock.patch.object(processutils, "execute", autospec=True)
    def test_exception_raised_for_execute_parent_mocked(self, mock_exec):
        # Make sure that even if we mock the parent execute function, that we
        # still get an exception for a child. So in this case
        # ironic_lib.utils.execute() calls processutils.execute(). Make sure an
        # exception is raised even though we mocked processutils.execute()
        exc = self.assertRaises(Exception, utils.execute, "ls")  # noqa
        # Have to use 'noqa' as we are raising plain Exception and we will get
        # H202 error in 'pep8' check.

        self.assertEqual(
            "Don't call ironic_lib.utils.execute() / "
            "processutils.execute() or similar functions in tests!",
            "%s" % exc)

class DontBlockExecuteTestCase(base.TestCase):
    """Ensure we can turn off blocking access to 'execute' type functions"""

    # Don't block the execute function
    block_execute = False

    @mock.patch.object(processutils, "execute", autospec=True)
    def test_no_exception_raised_for_execute(self, mock_exec):
        # Make sure we can call ironic_lib.utils.execute() even though we
        # didn't mock it. We do mock processutils.execute() so we don't
        # actually execute anything.
        utils.execute("ls")
        utils.execute("echo")
        self.assertEqual(2, mock_exec.call_count)


from app import app
from app import server as ml
from flask import render_template, json, request, jsonify
import tweepy as tw
import csv
import pandas as pd
from werkzeug.utils import secure_filename
import os
from nltk.util import ngrams
import matplotlib.pyplot as plt

load = ml.LoadData()
collect = ml.Data_Scrape()
prepro = ml.Preprocessing()
net = ml.Network()
tm = ml.Timeseries()

RAW_DATA_LOC = 'app/static/file/collected/'
model_path = 'app/all_indo_man_tag_corpus_model.crf.tagger'
filter_path = RAW_DATA_LOC + 'Filter_tweet.csv'
ALLOWED_EXTENSIONS = {'csv', '','file'}

def set_default(obj):
    if isinstance(obj, set):
        return list(obj)
    raise TypeError

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def stopwords():
    if request.method == "POST":
        stopwords_df = load.loadData(filter_path)
        locHStopwords = load.savedata(RAW_DATA_LOC, stopwords_df['text'], "tweet_text.txt")
    return locHStopwords

def token():
    locHStopwords = stopwords()
    add_stopwords = request.form.get("stopwords")
    tweet_token = prepro.openandtoken(locHStopwords)
    tweet_clean_stopwords = prepro.stopwords_cleaner(tweet_token, add_stopwords)

    return tweet_clean_stopwords

@app.route("/twitter_data", methods=["GET", "POST"])
def gets_data():
    if request.method == "POST":
       search_words = request.form.get("search")
       date_since = request.form.get("since")
       date_until = request.form.get("until")
       numb_of_tweet = int(request.form.get("numb"))
       print(search_words)

       tweets = collect.get_data(search_words, date_since, date_until, numb_of_tweet)
       tweets_flat = prepro.flatten_tweets(tweets)
       ds_tweets = pd.DataFrame(tweets_flat)
       ds_tweets.drop(['entities','metadata','user','retweeted_status','source'], axis=1, inplace=True)
       print(ds_tweets)
       lochScrape = load.savedata(RAW_DATA_LOC, ds_tweets, "tweet2.csv")
       hasil = {
           "hScrape": {lochScrape}
           }
       res = json.dumps(hasil, default=set_default), 200
       return res
    return render_template("index.html")

@app.route("/filter_out", methods=["GET", "POST"])
def filter_data():
    if request.method == "POST":
        filter_words = []
        filter = request.form.get("filter-out")
        filter_words = [item for item in filter.split()]

        path = RAW_DATA_LOC + 'tweet.csv'
        filter_df = load.loadData(path)

        new_filter_df = filter_df[~filter_df.retweeted_status_screen_name.isin(filter_words)]
        print(new_filter_df)

        locHFilter = load.savedata(RAW_DATA_LOC, new_filter_df, "Filter_tweet.csv")
        hasil = {
           "hFilter": {locHFilter}
           }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("filter.html")

@app.route("/exist_twitter", methods=["GET", "POST"])
def exist_twitter():
    if request.method == "POST":

        file = request.files["testDataset"]

        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(RAW_DATA_LOC, filename))
        else:
            return jsonify(message='error'), 500

        loc_test = os.path.join(RAW_DATA_LOC, filename)
        exist_df = load.loadData(loc_test)

        hasil = {"prediction": {loc_test}
                 }

        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/graph", methods=["GET", "POST"])
def graph():

    word1 = "#GarongKorupsiBerjamaah"
    word2 = "BPJS"

    ds_tweets = pd.read_csv('C:/Users/ASUS/nlp_analysis/app/static/file/collected/tweet.csv')
    ds_tweets = ds_tweets.sort_values(['created_at'], ascending=[True])
    ds_tweets['created_at'] = pd.to_datetime(ds_tweets['created_at'])
    ds_tweets = ds_tweets.set_index('created_at')

    timeseries_image = tm.get_timeseries_plot(ds_tweets, word1, word2)

    hasil = {
           "timeseries" : {timeseries_image}
           }
    res = json.dumps(hasil, default=set_default), 200
    return res

@app.route("/timeseries", methods=["GET", "POST"])
def timeseries_plot():
    if request.method == "POST":
        # word1 = request.form.get("word1")
        # word2 = request.form.get("word2")

        word1 = "#GarongKorupsiBerjamaah"
        word2 = "BPJS"

        ds_tweets = pd.read_csv('C:/Users/ASUS/nlp_analysis/app/static/file/collected/tweet.csv')
        ds_tweets = ds_tweets.sort_values(['created_at'], ascending=[True])
        ds_tweets['created_at'] = pd.to_datetime(ds_tweets['created_at'])
        ds_tweets = ds_tweets.set_index('created_at')

        timeseries_image = tm.get_timeseries_plot(ds_tweets, word1, word2)

        hasil = {
           "timeseries" : {timeseries_image}
           }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/stopwords", methods=["GET", "POST"])
def stopwords_custom():

    if request.method == "POST":

        unigram_threshold = 200
        bigram_threshold = 150
        trigram_threshold = 170
        verb_threshold = 30
        adjective_threshold = 10
        adverb_threshold = 2
        noun_threshold = 200

        locHStopwords = stopwords()

        tweet_clean_stopwords = token()

        wordcloud_image = prepro.wordcloud(tweet_clean_stopwords)
        unigrams_image = prepro.unigrams(tweet_clean_stopwords, unigram_threshold)
        bigrams_image = prepro.bigrams(tweet_clean_stopwords, bigram_threshold)
        trigrams_image = prepro.trigrams(tweet_clean_stopwords, trigram_threshold)

        result = prepro.pos_tagger(tweet_clean_stopwords, model_path)
        verbCounter = prepro.verb_counter(result, verb_threshold)
        adjectiveCounter = prepro.adjective_counter(result, adjective_threshold)
        adverbCounter = prepro.adverb_counter(result, adverb_threshold)
        nounCounter = prepro.noun_counter(result, noun_threshold)

        path = RAW_DATA_LOC + 'tweet.csv'
        ds_tweets = load.loadData(path)
        G_rt = net.RT_nodes_edges(ds_tweets)
        G_reply = net.reply_nodes_edges(ds_tweets)
        network_image = net.viz_network(G_rt)

        top_rt, top_reply = net.indegree_centrality(G_reply, G_rt)
        lochRT_indegree = load.savedata(RAW_DATA_LOC, top_rt, "RT_indegree.csv")
        lochReply_indegree = load.savedata(RAW_DATA_LOC, top_reply, "reply_indegree.csv")

        betweeness_rt, betweeness_reply = net.betweeness_centrality(G_rt, G_reply)
        lochRT_betweeness = load.savedata(RAW_DATA_LOC, betweeness_rt, "RT_betweeness.csv")
        lochReply_betweeness = load.savedata(RAW_DATA_LOC, betweeness_reply, "reply_betweeness.csv")

        ratio_df = net.ratio(G_rt, G_reply)
        lochRatio = load.savedata(RAW_DATA_LOC, ratio_df, "ratio.csv")

        hasil = {
           "hStopwords": {locHStopwords},
           "hRT_indegree": {lochRT_indegree},
            "hreply_indegree": {lochReply_indegree},
            "hRT_betweeness": {lochRT_betweeness},
            "hReply_betweeness": {lochReply_betweeness},
            "hRatio": {lochRatio},
           "wordcloud": {wordcloud_image},
           "network": {network_image},
           "unigram": {unigrams_image},
           "bigram": {bigrams_image},
           "trigram": {trigrams_image},
           "verb": {verbCounter},
           "adjective": {adjectiveCounter},
           "adverb": {adverbCounter},
           "noun": {nounCounter}
           }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hUnigram", methods=["GET", "POST"])
def unigram():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        unigram_threshold = int(request.form.get("unigram_threshold"))
        unigrams_image = prepro.unigrams(tweet_clean_stopwords, unigram_threshold)

        hasil = {
            "unigram": {unigrams_image}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hBigram", methods=["GET", "POST"])
def bigram():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        bigram_threshold = int(request.form.get("bigram_threshold"))
        bigrams_image = prepro.bigrams(tweet_clean_stopwords, bigram_threshold)

        hasil = {
            "bigram": {bigrams_image}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hTrigram", methods=["GET", "POST"])
def trigram():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        trigram_threshold = int(request.form.get("trigram_threshold"))
        trigrams_image = prepro.trigrams(tweet_clean_stopwords, trigram_threshold)

        hasil = {
            "trigram": {trigrams_image}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hVerb", methods=["GET", "POST"])
def verb():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        result = prepro.pos_tagger(tweet_clean_stopwords, model_path)
        verb_threshold = int(request.form.get("verb_threshold"))
        verbCounter = prepro.verb_counter(result, verb_threshold)

        hasil = {
            "verb": {verbCounter}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hAdjective", methods=["GET", "POST"])
def adjective():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        result = prepro.pos_tagger(tweet_clean_stopwords, model_path)
        adjective_threshold = int(request.form.get("adjective_threshold"))
        adjectiveCounter = prepro.adjective_counter(result, adjective_threshold)

        hasil = {
            "adjective": {adjectiveCounter}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hAdverb", methods=["GET", "POST"])
def adverb():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        result = prepro.pos_tagger(tweet_clean_stopwords, model_path)
        adverb_threshold = int(request.form.get("adverb_threshold"))
        adverbCounter = prepro.adverb_counter(result, adverb_threshold)

        hasil = {
            "adverb": {adverbCounter}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hNoun", methods=["GET", "POST"])
def noun():
    if request.method == "POST":
        tweet_clean_stopwords = token()
        result = prepro.pos_tagger(tweet_clean_stopwords, model_path)
        noun_threshold = int(request.form.get("noun_threshold"))
        nounCounter = prepro.noun_counter(result, noun_threshold)

        hasil = {
            "noun": {nounCounter}
            }
        res = json.dumps(hasil, default=set_default), 200
        return res
    return render_template("index.html")

@app.route("/hScraping", methods=["GET"])
def tampil():
    data = []

    with open(RAW_DATA_LOC + 'tweet2.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile)
        print(data_csv )
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)

@app.route("/hpResult", methods=["GET"])
def tampilResult():
    data = []

    with open(RAW_DATA_LOC + 'tweet.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    print(type(data))
    return jsonify(data)

@app.route("/hFilter", methods=["GET"])
def tampilFilter():
    data = []

    with open(RAW_DATA_LOC + 'Filter_tweet.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)

@app.route("/hRT_indegree", methods=["GET"])
def tampilRT_indgeree():
    data = []

    with open(RAW_DATA_LOC + 'RT_indegree.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)

@app.route("/hReply_indegree", methods=["GET"])
def tampilReply_indgeree():
    data = []

    with open(RAW_DATA_LOC + 'reply_indegree.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)

@app.route("/hRT_betweeness", methods=["GET"])
def tampilRT_betweeness():
    data = []

    with open(RAW_DATA_LOC + 'RT_betweeness.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)

@app.route("/hReply_betweeness", methods=["GET"])
def tampilReply_betweeness():
    data = []

    with open(RAW_DATA_LOC + 'reply_betweeness.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)

@app.route("/hRatio", methods=["GET"])
def tampilRatio():
    data = []

    with open(RAW_DATA_LOC + 'ratio.csv', encoding='utf-8') as csvfile:
        data_csv = csv.DictReader(csvfile, delimiter=',')
        for row in data_csv:
            data.append(dict(row))
    data = {"data": data}
    return jsonify(data)


import tensorflow as tf
import tensorflow_probability as tfp

@tf.keras.utils.register_keras_serializable(
    package="psiz.keras.layers", name="EmbeddingShared"
)
class EmbeddingShared(tf.keras.layers.Layer):
    """A class for wrapping a shared Embedding."""

    def __init__(self, input_dim, output_dim, embedding, mask_zero=False, **kwargs):
        """Initialize.

        Args:
            input_dim:
            output_dim:
            embedding: An embedding layer.
            mask_zero (optional):
            kwargs: Additional key-word arguments.

        """
        super(EmbeddingShared, self).__init__(**kwargs)
        self._embedding = embedding
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.mask_zero = mask_zero

    def build(self, input_shape):
        """Build."""
        super().build(input_shape)
        self._embedding.build(input_shape)

    def call(self, inputs):
        """Call."""
        # Intercept inputs.
        inputs = tf.zeros_like(inputs)
        outputs = self._embedding(inputs)
        return outputs

    def get_config(self):
        """Return configuration."""
        config = super(EmbeddingShared, self).get_config()
        config.update(
            {
                "input_dim": int(self.input_dim),
                "output_dim": int(self.output_dim),
                "embedding": tf.keras.utils.serialize_keras_object(self._embedding),
                "mask_zero": self.mask_zero,
            }
        )
        return config

    @classmethod
    def from_config(cls, config):
        """Create layer from configuration.

        This method is the reverse of `get_config`, capable of
        instantiating the same layer from the config dictionary.

        Args:
            config: A Python dictionary, typically the output of
                `get_config`.

        Returns:
            layer: A layer instance.

        """
        config["embedding"] = tf.keras.layers.deserialize(config["embedding"])
        return cls(**config)

    @property
    def embeddings(self):
        """Getter method for `embeddings`.

        Return distribution that creates copies of the source
        distribution for each stimulus and dimension.

        The incoming distribution has,
        batch_shape=[] event_shape=[1, 1]

        We require a distribution with,
        event_shape=[self.input_dim, self.output_dim].

        """
        # First, reshape event_shape from [1, 1] to [].
        b = tfp.bijectors.Reshape(
            event_shape_out=tf.TensorShape([]), event_shape_in=tf.TensorShape([1, 1])
        )

        # Second, use Sample to expand event_shape to,
        # [self.input_dim, self.output.dim].
        dist = tfp.distributions.TransformedDistribution(
            distribution=tfp.distributions.Sample(
                self._embedding.embeddings,
                sample_shape=[self.input_dim, self.output_dim],
            ),
            bijector=b,
        )
        return dist