"""Table metadata-related classes."""
import itertools
import logging
import threading
from contextlib import contextmanager
from math import ceil
from typing import (
    TYPE_CHECKING,
    Any,
    Callable,
    Dict,
    Generator,
    Iterator,
    List,
    Optional,
    Sequence,
    Tuple,
    cast,
)

from psycopg2.sql import SQL, Composable, Identifier
from tqdm import tqdm

from splitgraph.config import (
    SG_CMD_ASCII,
    SPLITGRAPH_API_SCHEMA,
    SPLITGRAPH_META_SCHEMA,
)
from splitgraph.core.common import Tracer, get_temporary_table_id
from splitgraph.core.fragment_manager import ExtraIndexInfo, get_chunk_groups
from splitgraph.core.indexing.range import quals_to_sql
from splitgraph.core.output import pluralise, truncate_list
from splitgraph.core.sql.queries import select
from splitgraph.core.types import Quals, TableSchema
from splitgraph.engine import ResultShape
from splitgraph.engine.postgres.engine import get_change_key
from splitgraph.exceptions import ObjectIndexingError

if TYPE_CHECKING:
    from splitgraph.core.image import Image
    from splitgraph.core.repository import Repository
    from splitgraph.engine.postgres.engine import PostgresEngine

# Output checkout progress every 5MB to trade off between the latency
# of initializing a batch of object applications and not reporting anything at all
_PROGRESS_EVERY = 5 * 1024 * 1024

# Rough ratio between the size of a PG table and a CStore table (picked empirically)
_CSTORE_COMPRESSION = 2.5

def _generate_select_query(
    engine: "PostgresEngine",
    table: bytes,
    columns: Sequence[str],
    qual_sql: Optional[Composable] = None,
    qual_args: Optional[Tuple] = None,
) -> bytes:
    cur = engine.connection.cursor()

    query = (
        SQL("SELECT ")
        + SQL(",").join(Identifier(c) for c in columns)
        + SQL(" FROM " + table.decode("utf-8"))
        + (SQL(" WHERE ") + qual_sql if qual_args else SQL(""))
    )
    query = cur.mogrify(query, qual_args)

    cur.close()
    return cast(bytes, query)

def _generate_table_names(engine: "PostgresEngine", schema: str, tables: List[str]) -> List[bytes]:
    result = []
    cur = engine.connection.cursor()
    for table in tables:
        result.append(cur.mogrify(SQL("{}.{}").format(Identifier(schema), Identifier(table))))
    cur.close()
    logging.debug("Returning tables %r", tables)
    return result

def _delete_temporary_table(engine: "PostgresEngine", schema: str, table: str) -> None:
    """
    Workaround for Multicorn deadlocks at end_scan time, supposed to be run in a separate thread.
    """
    # Delete the temporary table in an autocommitting connection with a small lock
    # timeout: if we fail to delete it because Multicorn is still holding a lock on it etc,
    # we'd rather leave the temporary table in splitgraph_meta than lock up.
    conn = engine.connection
    conn.autocommit = True
    try:
        with conn.cursor() as cur:
            cur.execute("SET lock_timeout TO '5s';")
            cur.execute(
                SQL("DROP TABLE IF EXISTS {}.{}").format(Identifier(schema), Identifier(table))
            )
        logging.info("Dropped temporary table %s", table)
    finally:
        conn.autocommit = False
        conn.close()

def _empty_callback(**kwargs) -> None:
    pass

class QueryPlan:
    """
    Represents the initial query plan (fragments to query) for given columns and
    qualifiers.
    """

    def __init__(self, table: "Table", quals: Optional[Quals], columns: Sequence[str]) -> None:
        self.table = table
        self.quals = quals
        self.columns = columns
        self.tracer = Tracer()

        self.object_manager = table.repository.objects

        # Make sure objects don't repeat (the second copy of the same object does nothing).
        # Some process makes certain datasets have duplicate objects, disabling the singleton
        # "fast path" and requiring materialization.
        self.required_objects = list(dict.fromkeys(table.objects))
        self.tracer.log("resolve_objects")
        self.filtered_objects = self.object_manager.filter_fragments(
            self.required_objects, table, quals
        )
        # Estimate the number of rows in the filtered objects
        object_meta = self.object_manager.get_object_meta(self.filtered_objects)
        self.estimated_rows = sum([o.rows_inserted - o.rows_deleted for o in object_meta.values()])

        # Estimate the row size in bytes by looking at the total object size
        # This can sometimes be important if we're querying wide tables with JSON data where
        # a single cell can be a few KB -- in some cases, this can make PG think it's going to get
        # less data than there actually be and pick suboptimal plans.
        total_rows_inserted = sum(o.rows_inserted for o in object_meta.values())

        self.size_per_row = (
            (
                sum(o.size for o in object_meta.values())
                / sum(o.rows_inserted for o in object_meta.values())
                * _CSTORE_COMPRESSION
            )
            if total_rows_inserted
            else 0
        )

        self.tracer.log("filter_objects")

        # Prepare a list of objects to query

        # Special fast case: single-chunk groups can all be batched together
        # and queried directly without having to copy them to a staging table.
        # We also grab all fragments from multiple-fragment groups and batch them together
        # for future application.
        #
        # Technically, we could do multiple batches of application for these groups
        # (apply first batch to the staging table, extract the result, clean the table,
        # apply next batch etc): in the middle of it we could also talk back to the object
        # manager and release the objects that we don't need so that they can be garbage
        # collected. The tradeoff is that we perform more calls to apply_fragments (hence
        # more roundtrips).
        self.non_singletons, self.singletons = self._extract_singleton_fragments()

        logging.info(
            "Fragment grouping: %d singletons, %d non-singletons",
            len(self.singletons),
            len(self.non_singletons),
        )
        self.tracer.log("group_fragments")

        self.sql_quals, self.sql_qual_vals = quals_to_sql(
            quals, column_types={c.name: c.pg_type for c in self.table.table_schema}
        )

        if self.singletons:
            self.singleton_queries = _generate_table_names(
                self.object_manager.object_engine, SPLITGRAPH_META_SCHEMA, self.singletons
            )
        else:
            self.singleton_queries = []
        self.tracer.log("generate_singleton_queries")

    def _extract_singleton_fragments(self) -> Tuple[List[str], List[str]]:
        # Get fragment boundaries (min-max PKs of every fragment).
        table_pk = get_change_key(self.table.table_schema)
        object_pks = self.object_manager.get_min_max_pks(self.filtered_objects, table_pk)

        surrogate_pk = not any(t.is_pk for t in self.table.table_schema)
        if surrogate_pk:
            object_pks = self.table.repository.objects.generate_surrogate_pk(self.table, object_pks)

        # Group fragments into non-overlapping groups: those can be applied independently of each other.
        object_groups = get_chunk_groups(
            [
                (object_id, min_max[0], min_max[1])
                for object_id, min_max in zip(self.filtered_objects, object_pks)
            ]
        )
        singletons: List[str] = []
        non_singletons: List[str] = []
        for group in object_groups:
            if len(group) == 1:
                singletons.append(group[0][0])
            else:
                non_singletons.extend(object_id for object_id, _, _ in group)
        return non_singletons, singletons

QueryPlanCacheKey = Tuple[Optional[Tuple[Tuple[Tuple[str, str, Any]]]], Tuple[str]]

def _get_plan_cache_key(quals: Optional[Quals], columns: Sequence[str]) -> QueryPlanCacheKey:
    quals = (
        cast(
            Tuple[Tuple[Tuple[str, str, Any]]],
            tuple(tuple(tuple(q) for q in qual) for qual in quals),
        )
        if quals
        else None
    )
    columns = cast(Tuple[str], tuple(columns))
    return quals, columns

def merge_index_data(current_index: Dict[str, Any], new_index: Dict[str, Any]):
    for index_type, index_data in new_index.items():
        for col_name, col_index_data in index_data.items():
            if index_type not in current_index:
                current_index[index_type] = {}
            if col_name not in current_index[index_type]:
                current_index[index_type][col_name] = {}

            current_index[index_type][col_name] = col_index_data

class Table:
    """Represents a Splitgraph table in a given image. Shouldn't be created directly, use Table-loading
    methods in the :class:`splitgraph.core.image.Image` class instead."""

    def __init__(
        self,
        repository: "Repository",
        image: "Image",
        table_name: str,
        table_schema: TableSchema,
        objects: List[str],
    ) -> None:
        self.repository = repository
        self.image = image
        self.table_name = table_name
        self.table_schema = table_schema

        # List of fragments this table is composed of
        self.objects = objects

        self._query_plans: Dict[Tuple[Optional[Quals], Tuple[str]], QueryPlan] = {}

    def __repr__(self) -> str:
        return "Table %s in %s" % (self.table_name, str(self.image))

    def get_query_plan(
        self, quals: Optional[Quals], columns: Sequence[str], use_cache: bool = True
    ) -> QueryPlan:
        """
        Start planning a query (preliminary steps before object downloading,
        like qualifier filtering).

        :param quals: Qualifiers in CNF form
        :param columns: List of columns
        :param use_cache: If True, will fetch the plan from the cache for the same qualifiers and columns.
        :return: QueryPlan
        """
        key = _get_plan_cache_key(quals, columns)

        if use_cache and key in self._query_plans:
            plan = self._query_plans[key]
            # Reset the tracer in the plan: if this instance
            # persisted, the resolve/filter times in it will be
            # way in the past.
            plan.tracer = Tracer()
            plan.tracer.log("resolve_objects")
            plan.tracer.log("filter_objects")
            plan.tracer.log("group_fragments")
            plan.tracer.log("generate_singleton_queries")
            return plan

        plan = QueryPlan(self, quals, columns)
        self._query_plans[key] = plan
        return plan

    def materialize(
        self,
        destination: str,
        destination_schema: Optional[str] = None,
        lq_server: Optional[str] = None,
        temporary: bool = False,
    ) -> None:
        """
        Materializes a Splitgraph table in the target schema as a normal Postgres table, potentially downloading all
        required objects and using them to reconstruct the table.

        :param destination: Name of the destination table.
        :param destination_schema: Name of the destination schema.
        :param lq_server: If set, sets up a layered querying FDW for the table instead using this foreign server.
        """
        # Circular import
        from splitgraph.hooks.data_source.fdw import create_foreign_table

        destination_schema = destination_schema or self.repository.to_schema()
        engine = self.repository.object_engine
        object_manager = self.repository.objects
        engine.delete_table(destination_schema, destination)

        if not lq_server:
            # Materialize by applying fragments to one another in their dependency order.
            with object_manager.ensure_objects(
                table=self, objects=self.objects
            ) as required_objects:
                engine.create_table(
                    schema=destination_schema,
                    table=destination,
                    schema_spec=self.table_schema,
                    include_comments=True,
                    unlogged=True,
                    temporary=temporary,
                )
                if required_objects:
                    logging.debug("Applying %s...", pluralise("fragment", len(required_objects)))

                    table_size = self.get_size()

                    progress_every: Optional[int]
                    if table_size > _PROGRESS_EVERY:
                        progress_every = int(
                            ceil(len(required_objects) * _PROGRESS_EVERY / float(table_size))
                        )
                    else:
                        progress_every = None

                    engine.apply_fragments(
                        [(SPLITGRAPH_META_SCHEMA, d) for d in cast(List[str], required_objects)],
                        destination_schema,
                        destination,
                        progress_every=progress_every,
                    )
        else:
            query, args = create_foreign_table(
                destination_schema,
                lq_server,
                destination,
                self.table_schema,
                extra_options={"table": self.table_name},
            )

            engine.run_sql(query, args)

    def query_indirect(
        self, columns: List[str], quals: Optional[Quals]
    ) -> Tuple[Iterator[bytes], Callable, QueryPlan]:
        """
        Run a read-only query against this table without materializing it. Instead of
        actual results, this returns a generator of SQL queries that the caller can use
        to get the results as well as a callback that the caller has to run after they're
        done consuming the results.

        In particular, the query generator will prefer returning direct queries to
        Splitgraph objects and only when those are exhausted will it start materializing
        delta-compressed fragments.

        This is an advanced method: you probably want to call table.query().

        :param columns: List of columns from this table to fetch
        :param quals: List of qualifiers in conjunctive normal form. See the documentation for
            FragmentManager.filter_fragments for the actual format.
        :return: Generator of queries (bytes), a callback and a query plan object (containing stats
            that are fully populated after the callback has been called to end the query).
        """
        plan = self.get_query_plan(quals, columns)
        required_objects = plan.filtered_objects
        logging.info(
            "Using %d fragments (%s) to satisfy the query",
            len(required_objects),
            truncate_list(required_objects),
        )
        if not required_objects:
            return cast(Iterator[bytes], []), cast(Callable, _empty_callback), plan

        object_manager = self.repository.objects
        if not plan.non_singletons:
            with object_manager.ensure_objects(
                self, objects=required_objects, defer_release=True, tracer=plan.tracer
            ) as eo_result:
                _, release_callback = cast(Tuple, eo_result)
                return iter(plan.singleton_queries), cast(Callable, release_callback), plan

        def _generate_nonsingleton_query() -> Generator[bytes, None, None]:
            # If we have fragments that need applying to a staging area, we don't want to
            # do it immediately: the caller might be satisfied with the data they got from
            # the queries to singleton fragments. So here we have a callback that, when called,
            # actually materializes the chunks into a temporary table and then changes
            # the table's release callback to also delete that temporary table.

            # There's a slight issue: we can't use temporary tables if we're returning
            # pointers to tables since the caller might be in a different session.
            staging_table = self._create_staging_table()
            engine = self.repository.object_engine

            def _f(from_fdw=False):
                # This is very horrible but the way we share responsibilities between ourselves
                # and Multicorn leaves us no other choice. In LQ, this is supposed to be called
                # during EndForeignScan (at which point we are done with this staging table).
                # However, EndForeignScan doesn't actually release locks on tables that Multicorn
                # was reading (that are acquired outside of our control if the foreign scan happened in a
                # transaction). In that case we can't delete this table until the transaction actually finishes
                # -- which can't happen until we've deleted this table.

                # Other options are: generating the materialization query and running it on
                # Multicorn side (issues with Portals not being able to perform DDL and us having
                # to rework our interface), adding a DROP table to the end of the query (then
                # it doesn't return results, Portals still can't do DDL and the query is no longer
                # idempotent).

                # Instead, we pretend that we've successfully cleaned up but actually spawn
                # a thread whose single job will be running DROP table and waiting until it actually
                # returns.

                if from_fdw:
                    thread = threading.Thread(
                        target=_delete_temporary_table,
                        args=(engine, SPLITGRAPH_META_SCHEMA, staging_table),
                    )
                    thread.start()
                else:
                    engine.delete_table(SPLITGRAPH_META_SCHEMA, staging_table)

            nonlocal release_callback
            release_callback.append(_f)

            # Apply the fragments (just the parts that match the qualifiers) to the staging area
            if quals:
                engine.apply_fragments(
                    [(SPLITGRAPH_META_SCHEMA, o) for o in plan.non_singletons],
                    SPLITGRAPH_META_SCHEMA,
                    staging_table,
                    extra_quals=plan.sql_quals,
                    extra_qual_args=plan.sql_qual_vals,
                    schema_spec=self.table_schema,
                )
            else:
                engine.apply_fragments(
                    [(SPLITGRAPH_META_SCHEMA, o) for o in plan.non_singletons],
                    SPLITGRAPH_META_SCHEMA,
                    staging_table,
                    schema_spec=self.table_schema,
                )
            engine.commit()
            table_name = _generate_table_names(engine, SPLITGRAPH_META_SCHEMA, [staging_table])[0]
            yield table_name

        with object_manager.ensure_objects(
            self, objects=required_objects, defer_release=True, tracer=plan.tracer
        ) as eo_result:
            _, release_callback = cast(Tuple, eo_result)
            return (
                itertools.chain(plan.singleton_queries, _generate_nonsingleton_query()),
                cast(Callable, release_callback),
                plan,
            )

    @contextmanager
    def query_lazy(self, columns: List[str], quals: Quals) -> Iterator[Iterator[Dict[str, Any]]]:
        """
        Run a read-only query against this table without materializing it.

        :param columns: List of columns from this table to fetch
        :param quals: List of qualifiers in conjunctive normal form. See the documentation for
            FragmentManager.filter_fragments for the actual format.
        :return: Generator of dictionaries of results.
        """

        table_gen, release_callback, plan = self.query_indirect(columns, quals)
        engine = self.repository.object_engine

        def _generate_results():
            for table in table_gen:
                result = engine.run_sql(
                    _generate_select_query(
                        engine, table, plan.columns, plan.sql_quals, plan.sql_qual_vals
                    )
                )
                for row in result:
                    yield dict(zip(columns, row))

        try:
            yield _generate_results()
        finally:
            release_callback()

    def query(self, columns: List[str], quals: Quals):
        """
        Run a read-only query against this table without materializing it.

        This is a wrapper around query_lazy() that force evaluates the results which
        might mean more fragments being materialized that aren't needed.

        :param columns: List of columns from this table to fetch
        :param quals: List of qualifiers in conjunctive normal form. See the documentation for
            FragmentManager.filter_fragments for the actual format.
        :return: List of dictionaries of results
        """
        with self.query_lazy(columns, quals) as result:
            return list(result)

    def get_size(self) -> int:
        """
        Get the physical size used by the table's objects (including those shared with other tables).

        This is calculated from the metadata, the on-disk footprint might be smaller if not all of table's
        objects have been downloaded.

        :return: Size of the table in bytes.
        """
        return cast(
            int,
            self.repository.engine.run_sql(
                select("get_table_size", table_args="(%s,%s,%s,%s)", schema=SPLITGRAPH_API_SCHEMA),
                (
                    self.repository.namespace,
                    self.repository.repository,
                    self.image.image_hash,
                    self.table_name,
                ),
                return_shape=ResultShape.ONE_ONE,
            )
            or 0,
        )

    def get_length(self) -> int:
        """
        Get the number of rows in this table.

        This might be smaller than the total number of rows in all objects belonging to this
        table as some objects might overwrite each other.

        :return: Number of rows in table
        """
        return cast(
            int,
            self.repository.engine.run_sql(
                select(
                    "get_table_length", table_args="(%s,%s,%s,%s)", schema=SPLITGRAPH_API_SCHEMA
                ),
                (
                    self.repository.namespace,
                    self.repository.repository,
                    self.image.image_hash,
                    self.table_name,
                ),
                return_shape=ResultShape.ONE_ONE,
            )
            or 0,
        )

    def reindex(self, extra_indexes: ExtraIndexInfo, raise_on_patch_objects=True) -> List[str]:
        """
        Run extra indexes on all objects in this table and update their metadata.
        This only works on objects that don't have any deletions or upserts (have a deletion hash of 000000...).

        :param extra_indexes: Dictionary of {index_type: column: index_specific_kwargs}.
        :param raise_on_patch_objects: If True, will raise an exception if any objects in the table
            overwrite any other objects. If False, will log a warning but will reindex all non-patch objects.

        :returns List of objects that were reindexed.
        """
        object_manager = self.repository.objects

        object_meta = object_manager.get_object_meta(self.objects)

        # Because the index includes both inserted and deleted entries (so that we know
        # to grab the object if it deletes something we're interested in), we can't easily
        # reindex objects that include deletions since we'd have to find the object with
        # the old value for whatever we're deleting and also download it.

        valid_objects = {o: om for o, om in object_meta.items() if om.deletion_hash == "0" * 64}
        if len(valid_objects) < len(object_meta):
            message = "%d object(s) in %s have deletions or upserts, reindexing unsupported" % (
                len(object_meta) - len(valid_objects),
                self,
            )
            if raise_on_patch_objects:
                raise ObjectIndexingError(message)
            else:
                logging.warning(message)

        # Download the objects to reindex them
        with object_manager.ensure_objects(self, objects=list(valid_objects)):
            for object_id in tqdm(valid_objects, unit="objs", ascii=SG_CMD_ASCII):
                current_index = valid_objects[object_id].object_index

                index_struct = object_manager.generate_object_index(
                    object_id, self.table_schema, changeset=None, extra_indexes=extra_indexes
                )

                # Update the index in-place and overwrite it
                merge_index_data(current_index, index_struct)

        object_manager.register_objects(list(valid_objects.values()))
        return list(valid_objects)

    def _create_staging_table(self) -> str:
        staging_table = get_temporary_table_id()

        logging.debug("Using staging table %s", staging_table)
        self.repository.object_engine.create_table(
            schema=SPLITGRAPH_META_SCHEMA,
            table=staging_table,
            schema_spec=self.table_schema,
            unlogged=True,
        )
        return staging_table


from entities.board import board
from logic.spaceCreator import spaceCreator
import os
import time
from pynput import keyboard

class gameLogic:
    def __init__(self):
        self.board = None
        self.availableDificulties = [
            "easy",
            "medium",
            "hard"
        ]

        self.boardSizes = {
            "easy": (8,8,10),
            "medium": (10,10,20),
            "hard": (20,20,100)
        }

        self.neighbour_map = [(0,-1),(0,1),(-1,-1),(-1,0),(-1,1),(1,-1),(1,0),(1,1)]

        self.gameover = False
        self.won = False
        self.flaggedMines = []
        self.uncovered_spaces = 0
        self.x = 0
        self.y = 0
        self.clear = lambda: os.system('cls' if os.name=='nt' else 'clear')

    def startGame(self):
        print("Minesweeper")
        print("Choose game difficulty:")
        for i in range(len(self.availableDificulties)):
            print(str(i+1)+"."+self.availableDificulties[i])
        if self.selectedDifficulty(input())==False:
            self.startGame()
        else:
            listener = keyboard.Listener(on_press=self.__keyboard_listener,suppress=True)
            listener.start()
            while(self.gameover==False):
                self.clear()
                self.__print_board(self.board.fakeArray)
                self.__print_controls()
                time.sleep(.500)
                self.clear()
                self.__print_board(self.board.fakeArray,True)
                self.__print_controls()
                time.sleep(.500)
            listener.stop()
            if(self.gameover and self.won == False):
                self.clear()
                self.__print_board(self.board.fakeArray)
                print("Game over")
            elif(self.gameover and self.won):
                self.clear()
                self.__print_board(self.board.fakeArray)
                print("You won")
            input()

    def selectedDifficulty(self,selectedOption)->bool:
        self.clear()
        selectedOption = int(selectedOption)-1
        if selectedOption  not in range(len(self.availableDificulties)):
            return False
        else:
            selecteDificulty = self.availableDificulties[selectedOption]
            (width,height,mines)=self.boardSizes[selecteDificulty]
            print("You choosed: "+self.availableDificulties[selectedOption])
            print("This option, will create a board of {0} by {1} , with {2} mines".format(width,height,mines))
            print("Are you sure?")
            confirm = input("Yes/No:\n")
            if confirm.lower() == "yes":
                self.board = board(width,height,mines)
                space = spaceCreator(self.board)
            else:
                return False

    def __print_board(self,board, cursorBlink = False):
        for i in range(len(board)):
            row = ""
            for j in range(len(board)):
                if self.y == i and self.x == j and cursorBlink:
                    row += "\u2588"+","
                elif board[i][j] == None:
                    row += "?,"
                else:
                    row += board[i][j]+","
            print(row[0:len(row)-1])

    def __print_controls(self):
        print("Mines: "+str(self.board.mines)+"  Flags: "+str(len(self.flaggedMines)))
        print("Move with arrow keys")
        print("Press F to flag mines")
        print("Press SPACE key to uncover square")
        print("Press ESC to close game")

    def __keyboard_listener(self,key):
        if key == keyboard.Key.esc:
            self.gameover = True
        elif key == keyboard.Key.down and self.y < len(self.board.boardArray)-1:
            self.y += 1
        elif key == keyboard.Key.up and self.y > 0:
            self.y -= 1
        elif key == keyboard.Key.left and self.x > 0:
            self.x -= 1
        elif key == keyboard.Key.right and self.x < len(self.board.boardArray[self.y])-1:
            self.x += 1
        elif key == keyboard.Key.space:
            self.__uncover_spaces()
        else:
            try:
                if key.char == 'F' or key.char == 'f':
                    self.__flag_space()
                print(key)
            except AttributeError:
                print("special key {0} ".format(key))

    def __uncover_spaces(self):
        if(self.board.boardArray[self.y][self.x]=="*" and self.board.fakeArray[self.y][self.x]=="?"):
            self.board.fakeArray[self.y][self.x] = "*"
            self.gameover = True
        elif(self.board.boardArray[self.y][self.x]==" "):
            self.board.fakeArray[self.y][self.x] = self.board.boardArray[self.y][self.x]
            self.uncovered_spaces += 1
            self.__run_uncover_task()
        elif(self.board.boardArray[self.y][self.x] in ['1','2','3','4','5','6','7','8']):
            self.board.fakeArray[self.y][self.x] = self.board.boardArray[self.y][self.x]
            self.uncovered_spaces += 1
        self.__is_winner()

    def __run_uncover_task(self,space=None):
        for x,y in self.neighbour_map:
            new_x = (self.x if space == None else space["x"])+x
            new_y = (self.y if space == None else space["y"])+y
            if(new_x<0 or new_y<0 or new_x>self.board.width-1 or new_y>self.board.height-1):
                continue
            if(self.board.fakeArray[new_y][new_x]=="?" and self.board.boardArray[new_y][new_x]=="*"):
                continue
            elif(self.board.fakeArray[new_y][new_x]=="?" and self.board.boardArray[new_y][new_x]==" "):
                self.board.fakeArray[new_y][new_x]=" "
                self.uncovered_spaces+=1
                self.__run_uncover_task({"x":new_x,"y":new_y})
            elif(self.board.fakeArray[new_y][new_x]=="?" and self.board.boardArray[new_y][new_x] in ['1','2','3','4','5','6','7','8']):
                self.board.fakeArray[new_y][new_x]=self.board.boardArray[new_y][new_x]
                self.uncovered_spaces+=1

    def __flag_space(self):
        if(self.board.fakeArray[self.y][self.x]=="?") and len(self.flaggedMines)<self.board.mines:
            self.board.fakeArray[self.y][self.x] = "F"
            self.flaggedMines.append((self.y,self.x))
        elif(self.board.fakeArray[self.y][self.x]=="F"):
            self.board.fakeArray[self.y][self.x] = "?"
            self.flaggedMines.remove((self.y,self.x))
        if(self.uncovered_spaces+len(self.flaggedMines) == self.board.width*self.board.height):
            self.won = True
            self.gameover = True
        self.__is_winner()

    def __is_winner(self):
        if(self.uncovered_spaces+len(self.flaggedMines) == self.board.width*self.board.height):
            self.won = True
            self.gameover = True


import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import ode
import time as time
from multiprocessing import Pool
from scipy.integrate import trapz
import functools
from multiprocessing import cpu_count
from scipy.interpolate import interp1d
from numba import jit, prange
from decimal import Decimal
import math as mt
import scipy.interpolate
import _pickle as cPickle
import matplotlib.animation as Animation
import pylab as pylab
import scipy.fftpack as fft
import os as os
from shutil import copyfile
import matplotlib.cm as cm
from matplotlib import gridspec
import scipy.integrate as integrate

# from numdifftools import Derivative
flatten = np.ndarray.flatten
# from scipy.interpolate import UnivariateSpline
# from scipy import interpolate
from statsmodels.nonparametric.smoothers_lowess import lowess

colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple'
    , 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan']

plt.rcParams['axes.labelsize'] = 25
plt.rcParams['legend.fontsize'] = 20
plt.rcParams['xtick.labelsize'] = 15
plt.rcParams['ytick.labelsize'] = 15

pi = np.pi;
sin = np.sin;
cos = np.cos;
exp = np.exp;
log = np.log;
abs = np.abs;
absolute = np.absolute;
sqrt = np.sqrt
acos = mt.acos
asin = mt.sin
sinh = np.sinh
cosh = np.cosh

def timer(note, start):
    t = time.time()
    print(note, ':', t-start)
    return

def make_dir(Master_path):
    if os.path.exists(Master_path):
        print('Data Directory exists')
    else:
        os.mkdir(Master_path)
        print('Data directory does not exist')

def save(data, name, directory, Master_path):
    path = '%s/%s/%s.npy' % (Master_path, directory, name)

    file = open(path, 'wb')
    np.save(file, data)
    file.close()
    return

def load(name, directory, Master_path):
    path = '%s/%s/%s.npy' % (Master_path, directory, name)
    file = open(path, 'rb')
    stack = np.load(file)
    file.close()
    return stack

def load_or_exec(filename, directory, function, Master_path, execute_arguments):
    command = input('Rewrite %s in %s (T/F):'%(filename, directory))

    sub_path = '%s/%s' % (Master_path, directory)
    file_path = '%s/%s/%s.npy' % (Master_path, directory, filename)

    if os.path.exists(sub_path):
        print('Sub Directory exists')
    else:
        os.mkdir(sub_path)
        print('Sub directory does not exist')
        print('Builing new Subdirectory %s'%directory)

    if os.path.exists(file_path) and command == 'F':

        print('File exists')
        file = load(filename, directory, Master_path)

    else:

        print('File does not exist or computing fresh set')
        file = function(*execute_arguments)
        save(file, filename, directory, Master_path)

    return np.array(file)

def V_PN(phi,p):

    V = (1-1/(1+((phi)**2))**p)
    V_norm = 0.5*(1 - 1 / (1 + ((phi) ** 2) / p) ** p)

    V_mon = phi**p + 0.1*cos(phi)

    return V_norm

def load_or_exec_multi_file(Master_path, directory, function, execute_arguments):

    path_data = '%s/%s' % (Master_path, directory)

    Rewrite_command = input('Overwrite existing data in %s?(T or F):'%directory)

    if os.path.exists(path_data) == True and Rewrite_command == 'F':

        print('Using Existing Data')

    else:
        if os.path.exists(path_data):
            print('Sub Directory exists')
            print('Overwriting data in %s'%(directory))
            function(*execute_arguments)
        else:
            os.mkdir(path_data)
            print('Sub directory does not exist')
            print('Builing new Subdirectory %s' % directory)
            print('Computing new data')
            function(*execute_arguments)

    return

H_inf = 1e-8
T_R = (90 / (100 * pi ** 2)) ** (1 / 2) * (H_inf) ** (1 / 2)
T_0 = 23.5 * 1e-14
Mpl = 2.435 * 1e18  ##Mpl in GeV
GeV2 = 6.8 * 1e20  ##Gev^2 in Gauss
a_R = T_0 / (T_R * Mpl)

def mapper(var, var_arr , target_arr):

    diff_arr = abs(var_arr-var)
    min_idx = np.argmin(diff_arr)

    out = target_arr[min_idx]

    return out

def Lambda_0(Lambda_k_f, B_k_f):
    Lambda_0 = 3.3e5 * a_R * (Lambda_k_f) ** (1 / 3) * (B_k_f) ** (2 / 3);
    return Lambda_0

def B_0(Lambda_0):
    B_0 = 1e-8 * Lambda_0
    return B_0

def rho_plot(p, alpha, k, x_len, a_stack, Master_path, f, trigger_matrix, kill_matrix, Phi_Stack, asymp_stack):
    h = [-1, 1]

    targ_f = [0.01, 0.005]
    f_idxs = [np.argmin(abs(targ - f)) for targ in targ_f]

    p_idxs = [0]

    targ_alpha = [0.5, 0.6, 0.7, 0.8]
    alpha_idxs = [np.argmin(abs(targ - alpha)) for targ in targ_alpha]

    for cnt_f, idx_f in enumerate(f_idxs):
        item_f = f[idx_f]
        for cnt_p, idx_p, in enumerate(p_idxs):
            item_p = p[idx_p]
            sol = Phi_Stack[idx_f][idx_p]
            t = sol[0];
            phi_a = np.array([mapper(x, a_stack[idx_f][idx_p][0], a_stack[idx_f][idx_p][1]) for x in t]) \
                    / mapper(t[0],a_stack[idx_f][idx_p][0],a_stack[idx_f][idx_p][1])
            phi = sol[1]
            dphi = sol[2]

            for cnt_alpha, idx_alpha in enumerate(alpha_idxs):
                item_alpha = alpha[idx_alpha]

                name_1 = 'alpha:%.5f_h:%s_p:%.3f_f_%.5f' % (item_alpha, -1, item_p, item_f)
                name_2 = 'alpha:%.5f_h:%s_p:%.3f_f_%.5f' % (item_alpha, 1, item_p, item_f)
                name_0_1 = 'alpha:%.5f_h:%s_p:%.3f_f_%.5f' % (0., -1, item_p, item_f)
                name_0_2 = 'alpha:%.5f_h:%s_p:%.3f_f_%.5f' % (0., 1, item_p, item_f)

                stack_B_1, stack_B_2 = np.array(load(name_1, 'Rho_B', Master_path)), np.array(
                    load(name_2, 'Rho_B', Master_path))
                stack_B_0_1, stack_B_0_2 = np.array(load(name_0_1, 'Rho_B', Master_path)), np.array(
                    load(name_0_2, 'Rho_B', Master_path))

                x_B = stack_B_1[:, 0]

                x_B_0_1, rho_B_0_1 = stack_B_0_1[:, 0], stack_B_0_1[:, 1]
                x_B_0_2, rho_B_0_2 = stack_B_0_2[:, 0], stack_B_0_2[:, 1]
                rho_B = stack_B_1[:, 1] / rho_B_0_1 + stack_B_2[:, 1] / rho_B_0_2  # *m**2/H_map**2/(a_i**4)

                stack_E_1 = np.array(load(name_1, 'Rho_E', Master_path));
                stack_E_0_1 = np.array(load(name_0_1, 'Rho_E', Master_path))
                stack_E_2 = np.array(load(name_2, 'Rho_E', Master_path));
                stack_E_0_2 = np.array(load(name_0_2, 'Rho_E', Master_path))
                x_E_0_1, rho_E_0_1 = stack_E_0_1[:, 0], stack_E_0_1[:, 1]
                x_E_0_2, rho_E_0_2 = stack_E_0_2[:, 0], stack_E_0_2[:, 1]
                rho_E = stack_E_1[:, 1] / rho_E_0_1 + stack_E_2[:, 1] / rho_E_0_2  # *m**2/H_map**2/(a_i**2)

                m = H_inf / item_f * (3 * (0.5 * absolute(dphi[0]) ** 2 + V_PN(phi[0], item_p)) ** (-1)) ** (1 / 2)

                H_map = sqrt(item_f ** 2 * (0.5 * dphi ** 2 + np.array([V_PN(z, item_p) for z in phi]))) / sqrt(
                    (0.5 * dphi[0] ** 2 + V_PN(phi[0], item_p)));
                H_map = np.array([mapper(x, t, H_map) for x in x_B])
                t_i = trigger_matrix[idx_f][idx_p]
                a_i = mapper(t_i, a_stack[idx_f][idx_p][0], a_stack[idx_f][idx_p][1])
                a_map = np.array([mapper(x, a_stack[idx_f][idx_p][0], a_stack[idx_f][idx_p][1]) for x in x_B]) / a_i;
                a_map = 1. / a_i  # print(np.shape(rho_B),np.shape(rho_E),np.shape(H_map))#a_map = 1/a_i
                cross_idx = np.argwhere(
                    np.diff(np.sign(np.absolute(rho_E + rho_B) - 3 * H_map ** 2 / m ** 2))).flatten()

                t_i = trigger_matrix[idx_f][idx_p]
                t_f = kill_matrix[idx_f][idx_p];
                a_f = mapper(t_f, a_stack[idx_f][idx_p][0], a_stack[idx_f][idx_p][1])

                A_0 = [absolute(asymp_stack[idx_f, idx_h, idx_p, 0, :, 1]) for idx_h in [0, 1]]
                A = [absolute(asymp_stack[idx_f, idx_h, idx_p, idx_alpha, :, 1]) - absolute(A_0[idx_h]) for idx_h in
                     [0, 1]]

                max_idx = np.argmax(A[0])
                max_k, max_A = [k[idx_f][idx_p][max_idx],
                                sqrt(absolute(A[0][max_idx]) ** 2 + absolute(A[1][max_idx]) ** 2)]

                max_A0 = sqrt(absolute(A_0[0][max_idx]) ** 2 + absolute(A_0[1][max_idx]) ** 2)

                rho_B_1 = (absolute(stack_B_1[:, 1]) - absolute(rho_B_0_1)) * m ** 4 * Mpl ** 4;
                rho_E_1 = (absolute(stack_E_1[:, 1]) - absolute(rho_E_0_1)) * m ** 4 * Mpl ** 4  # *m**2/H_map**2
                rho_B_2 = (absolute(stack_B_2[:, 1]) - absolute(rho_B_0_2)) * m ** 4 * Mpl ** 4;
                rho_E_2 = (absolute(stack_E_2[:, 1]) - absolute(rho_E_0_2)) * m ** 4 * Mpl ** 4  # *m**2/H_map**2
                ratio = \
                (((rho_B_1 + rho_B_2) / a_map ** 4 + (rho_E_1 + rho_E_2) / a_map ** 2) * m ** 2 / (3 * H_map ** 2))[-1]
                print(r'$\alpha:$', item_alpha, 'f:', item_f, 'Ratio:%.5f' % ratio)

                Lambda_f = 2 / (m * Mpl);
                Lambda_f = (a_f / (max_k * m * Mpl))

                if ratio < 2:
                    print(r'$B_{gen}:%.4e$' % (sqrt(rho_B_1 + rho_B_2) * m ** 2 * Mpl ** 2 * a_map ** -2)[-1])
                    print(r'$\Lambda_{gen}:%.4e \quad \Lambda_{gen, peak}:%.4e$' % (
                    2 / (m * Mpl), (a_f / (max_k * m * Mpl))))
                    B_k_f = (m ** 2 * (max_k / (a_f / a_i)) ** 2 * (max_A / max_A0)) * Mpl ** 2;
                    print(r'$B_{gen, peak}:%.4e$' % (B_k_f));

                    Lambda_0 = Lambda_0(Lambda_f, B_k_f);
                    B_0 = B_0(Lambda_0)
                    print(r'$\Lambda_{m,0}:%.4e$' % (Lambda_0))

                    print(r'$B_{0, peak}:%.4e$' % (B_0))
                    # a_R = 1e-29 ##Subhramanian entropy conservation
                    cross_idx_1 = np.argwhere(np.diff(np.sign(np.absolute(
                        rho_E_1 / a_map ** 2 + rho_B_1 / a_map ** 4) - 3 * H_map ** 2 * m ** 2 * Mpl ** 4))).flatten()
                    cross_idx_2 = np.argwhere(np.diff(np.sign(np.absolute(
                        rho_E_2 / a_map ** 2 + rho_B_2 / a_map ** 4) - 3 * H_map ** 2 * m ** 2 * Mpl ** 4))).flatten()

                    B_k_f_1 = sqrt((rho_B_1 / a_map ** 4)[cross_idx_1]) * (m * Mpl) ** 2

    return


"""Write a stream of close approaches to CSV or to JSON.

This module exports two functions: `write_to_csv` and `write_to_json`, each of
which accept an `results` stream of close approaches and a path to which to
write the data.

These functions are invoked by the main module with the output of the `limit`
function and the filename supplied by the user at the command line. The file's
extension determines which of these functions is used.

You'll edit this file in Part 4.
"""
import csv
import json
from helpers import transform_to_str, datetime_to_str

def transform_result_for_csv_writing(results):
    """
    Transform approach objects to list of lists (only including necessary fields for csv).

    :param results: An iterrator of queried approaches
    :return: A list of approach data for csv writing
    """
    fieldkeys = [
        "time",
        "distance",
        "velocity",
        "_designation",
        "name",
        "diameter",
        "hazardous",
    ]
    outlist = list()
    for approach in list(results):
        unpacked_dict = unpack_approach(approach)
        outlist.append([transform_to_str(unpacked_dict[fkey]) for fkey in fieldkeys])

    return outlist

def write_to_csv(results, filename):
    """Write an iterable of `CloseApproach` objects to a CSV file.

    The precise output specification is in `README.md`. Roughly, each output row
    corresponds to the information in a single close approach from the `results`
    stream and its associated near-Earth object.

    :param results: An iterable of `CloseApproach` objects.
    :param filename: A Path-like object pointing to where the data should be saved.
    """
    fieldnames = (
        "datetime_utc",
        "distance_au",
        "velocity_km_s",
        "designation",
        "name",
        "diameter_km",
        "potentially_hazardous",
    )

    outlist = transform_result_for_csv_writing(results)

    with open(filename, "w") as f:
        write = csv.writer(f)
        write.writerow(fieldnames)
        write.writerows(outlist)

    return

def unpack_approach(approach):
    """Unpack approach object into dictionary.

    :param approach:Approach object.
    :return: Dictionary with approach keys and values.
    """
    return {**approach.__dict__, **approach.__dict__["neo"].__dict__}

def get_dict_for_json_mapping():
    """Return required fields for json output and corresponding key in approach and neo object.

    :return: Dictionary for lookup of required json fields.
    """
    return {
        "datetime_utc": "time",
        "distance_au": "distance",
        "velocity_km_s": "velocity",
        "designation": "designation",
        "name": "name",
        "diameter_km": "diameter",
        "potentially_hazardous": "hazardous",
    }

def approach_vars():
    """Return variables that are part of approach object (and not neo) and needed for json output.

    :return: List of json output coming from approach object.
    """
    return ["datetime_utc", "distance_au", "velocity_km_s"]

def transform_approaches_to_list_of_dicts(approaches, keymap_dict, approach_vars):
    """Transform approaches collection to list of dictionaries to be dumped into json.

    :param approaches: Collection of approach objects
    :param keymap_dict: Function that returns how to lookup required fields
    :param approach_vars: List of elements indicating which fields belong to approach object
    :return: List of results that should be written to json file
    """
    resultlist = list()
    for approach in approaches:
        unpacked_approach = unpack_approach(approach)
        approachdict = {"neo": {}}
        for key, lookup_val in keymap_dict.items():
            if key in ["datetime_utc"]:
                value = datetime_to_str(unpacked_approach[lookup_val])
            elif key in ["designation", "name"]:
                value = transform_to_str(unpacked_approach[lookup_val])
            elif key in ["distance_au", "velocity_km_s", "diameter_km"]:
                value = float(unpacked_approach[lookup_val])
            elif key in ["potentially_hazardous"]:
                value = bool(unpacked_approach[lookup_val])
            else:
                raise RuntimeError("unexpected_key")
            if key in approach_vars:
                approachdict[key] = value
            else:
                approachdict["neo"][key] = value
        resultlist.append(approachdict)
    return resultlist

def write_to_json(results, filename):
    """Write an iterable of `CloseApproach` objects to a JSON file.

    The precise output specification is in `README.md`. Roughly, the output is a
    list containing dictionaries, each mapping `CloseApproach` attributes to
    their values and the 'neo' key mapping to a dictionary of the associated
    NEO's attributes.

    :param results: An iterable of `CloseApproach` objects.
    :param filename: A Path-like object pointing to where the data should be saved.
    """
    resultlist = transform_approaches_to_list_of_dicts(
        results, get_dict_for_json_mapping(), approach_vars()
    )
    with open(filename, "w") as file:
        json.dump(resultlist, file)
    return


from direct.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedObjectAI import DistributedObjectAI

from toontown.hood import ZoneUtil
from toontown.hood.GSHoodDataAI import GSHoodDataAI
from toontown.hood.TTHoodDataAI import TTHoodDataAI
from toontown.toonbase import ToontownGlobals

class WelcomeValleyManagerAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('WelcomeValleyManagerAI')

    def requestZoneIdMessage(self, zoneId, context):
        avId = self.air.getAvatarIdFromSender()
        if zoneId == 0:
            zoneId = ToontownGlobals.WelcomeValleyBegin

        self.toonSetZone(avId, zoneId)
        self.sendUpdateToAvatarId(avId, 'requestZoneIdResponse', [zoneId, context])

    def toonSetZone(self, doId, zoneId):
        event = self.staticGetLogicalZoneChangeEvent(doId)
        inWelcomeValley = self.isAccepting(event)
        if not ZoneUtil.isDynamicZone(zoneId):
            if ZoneUtil.isWelcomeValley(zoneId) and not inWelcomeValley:
                self.air.districtStats.b_setNewAvatarCount(self.air.districtStats.getNewAvatarCount() + 1)
                self.accept(event, lambda newZoneId, _: self.toonSetZone(doId, newZoneId))
                self.accept(self.air.getAvatarExitEvent(doId), self.toonSetZone,
                            extraArgs=[doId, ToontownGlobals.ToontownCentral])
            elif (not ZoneUtil.isWelcomeValley(zoneId)) and inWelcomeValley:
                self.air.districtStats.b_setNewAvatarCount(self.air.districtStats.getNewAvatarCount() - 1)
                self.ignore(event)
                self.ignore(self.air.getAvatarExitEvent(doId))

    def createWelcomeValleyZones(self):
        self.notify.info('Creating Welcome Valley zones...')

        # Toontown Central
        self.air.generateHood(TTHoodDataAI, 22000)

        # Goofy Speedway
        self.air.generateHood(GSHoodDataAI, 23000)


"""
Author : Helia Ghorbani
Student ID : 9824353
"""
import pygame

pygame.init()

# declare window size parameters : height, width
winSize = 100
height = winSize * 6
width = height + winSize * 2
# ---------------------------------------------------------
board = []
btnOffset = (winSize * 2) // 3
run = True
pressed = False
number = ''
N = 0
page = 0
isSolved = False
# ---------------------------------------------------------
# colors
BLACK  = (0,0,0)
LIGHTGRAY = (211,211,211)
RED = (255, 0, 0)
TURQUOISE = (64,224,208)
LIGHTCORAL = (240,128,128)
# ---------------------------------------------------------
# set display window size : height, width
window = pygame.display.set_mode((width,height))
pygame.display.set_caption('N-Queens Problem')
# ---------------------------------------------------------
# set display font
titleFont = pygame.font.SysFont('Helvetica', 30, bold=True)
textFont = pygame.font.SysFont('Helvetica', 20, bold=True)
# ---------------------------------------------------------
# set solve button
solveBtn = pygame.Rect(0,0, 100, 50)
solveBtn.center = (width // 2, height // 2 + height // 6)
# ---------------------------------------------------------
# Set previous, next and clear button
prvBtn = pygame.Rect(0, 0, 75, 50)
nxtBtn = pygame.Rect(0, 0, 75, 50)
prvBtn.center = (height + btnOffset - 10, 100)
nxtBtn.center = (height + btnOffset * 2 + 10 ,100)
clrBtn = pygame.Rect(0, 0, 75, 50)
clrBtn.center = (height + (width - height) // 2, height // 2)
# ---------------------------------------------------------
# check left diagonal
def checkLeftDiagonal(arr, row, col):
    x = y = 0
    if row > col:
        x = row - col
        y = 0
    elif col > row:
        x = 0
        y = col - row
    while ((x != len(arr)) and (y != len(arr[0]))):
        if arr[x][y] == 1:
            return False
        x = x + 1
        y = y + 1
    return True
# ---------------------------------------------------------
# check right digonal
def checkRightDiagonal(arr, row, col):
    x = row
    y = col
    while x != 0 and y != len(arr) - 1:
        x = x - 1
        y = y + 1
    while x != len(arr) and y >= 0:
        if arr[x][y] == 1:
            return False
        x = x + 1
        y = y - 1
    return True
# ---------------------------------------------------------
# check vlidation of movement
# check row, column, diagonal
# 1 means full -> False
def validMove(arr, row, col):
    # check row - no other 1 in row
    for i in range(len(arr[0])):
        if arr[row][i]:
            return False
    # check column - no other 1 in column
    for i in range(len(arr[col])):
        if arr[i][col]:
            return False
    # check right and left digonal
    if not (checkRightDiagonal(arr, row, col) and checkLeftDiagonal(arr, row, col)):
        return False
    return True
# ---------------------------------------------------------
# return a copy of input array
def copyArray(arr,N):
    array = initArray(N)
    for i in range(len(arr)):
        for j in range(len(arr[0])):
            array[i][j] = arr[i][j]
    return array
# ---------------------------------------------------------
# find suitable place
# solve recursuvely
def NQueensSolver(arr, col):
    global board
    result = False
    # return true if all queens placed
    if col >= len(arr[0]) :
        board.append(copyArray(arr, len(arr)))
        return True
    # consider this column and place this in all row
    for row in range(len(arr[0])):
        # check can be placed in arr[row][col]
        if validMove(arr, row, col):
            # placed in arr[row][col]
            arr[row][col] = 1
            # possible placement
            result = NQueensSolver(arr, col + 1) or result
            # placing in arr[row][col] doesn't lead to solution
            # remove from arr[row][col]
            # backtrack
            arr[row][col] = 0
    # if can't place in any row false
    return result
# ---------------------------------------------------------
# draw chessboard
def chessboard(N):
    cellSize = height // N
    # set black cells
    for i in range(N):
        for j in range(N):
            if i % 2 == 0 and j % 2 != 0:
                pygame.draw.rect(window, BLACK, (cellSize * i, cellSize * j, cellSize,cellSize ))
            elif i % 2 != 0 and j % 2 == 0:
                pygame.draw.rect(window, BLACK, (cellSize * i, cellSize * j , cellSize, cellSize))
    # draw lines around the board
    pygame.draw.line(window, BLACK, (0, 0), (cellSize * N, 0))
    pygame.draw.line(window,BLACK,(cellSize * N, 0),(cellSize * N, cellSize * N))
# ---------------------------------------------------------
# number of solution
def numOfSol(page, arr):
    # display page number
    string = '{} / {}'
    pageNum = textFont.render(string.format(str(page + 1), str(len(arr))), 1, BLACK)
    # set position of page number
    pagenumRect = pageNum.get_rect()
    pagenumRect.center = (height + (width - height) // 2, 50)
    window.blit(pageNum, pagenumRect)
    # draw pervious, next and clear button on the board
    pygame.draw.rect(window, TURQUOISE, prvBtn)
    pygame.draw.rect(window, TURQUOISE, nxtBtn)
    pygame.draw.rect(window, LIGHTCORAL, clrBtn)
    # set text and position of pervious button
    prv = textFont.render('Previous', 1, BLACK)
    prvRect = prv.get_rect()
    prvRect.center = prvBtn.center
    window.blit(prv, prvRect)
    # set text and position of next button
    nxt = textFont.render('Next', 1, BLACK)
    nxtRect = nxt.get_rect()
    nxtRect.center = nxtBtn.center
    window.blit(nxt, nxtRect)
    # set text and position of clear button
    clear = textFont.render('Clear', 1, BLACK)
    clearRect = clear.get_rect()
    clearRect.center = clrBtn.center
    window.blit(clear, clearRect)
# ---------------------------------------------------------
# fill cell -> put red rect on selected cell
def fillCell(arr, N):
    cellSize = height // N
    queenSize = cellSize // 1.5
    queenOffset = (cellSize - queenSize) // 2
    for row in range(len(arr)):
        for col in range(len(arr[0])):
            if arr[row][col]:
                pygame.draw.rect(window, RED, (col * cellSize + queenOffset, row * cellSize + queenOffset, queenSize, queenSize))
# ---------------------------------------------------------
# make empty N x N matrix
def initArray(N):
    return [[0 for i in range(N)] for j in range(N)]
# ---------------------------------------------------------
# first page - text & button display
def menu():
    # first page - text, position
    text = titleFont.render("Enter number of Queens (at least 4)",1 ,BLACK)
    textRect = text.get_rect()
    textRect.center = (width //2 , height // 2 - height // 6)
    window.blit(text, textRect)
    # draw solve button
    pygame.draw.rect(window, TURQUOISE, solveBtn)
    # set text and position of solve button
    solve = titleFont.render('Solve', 1, BLACK)
    solveTextRect = solve.get_rect()
    solveTextRect.center = (width // 2, height // 2 + height // 6)
    window.blit(solve, solveTextRect)
# ---------------------------------------------------------
# display input number of queens
def num(number):
    # set text and position of number of queens
    inputNum = titleFont.render(number, 1, BLACK)
    inputNumRect = inputNum.get_rect()
    inputNumRect.center = (width //2 , height // 2)
    window.blit(inputNum, inputNumRect)
# ---------------------------------------------------------
# main func
def main():
    global run, pressed, number, isSolved, board, page
    while run:
        # set window background
        window.fill(LIGHTGRAY)
        # no answer for N = 2 & N = 3
        if not pressed or N == 2 or N == 3:
            # display first page
            menu()
            # display input number
            num(number)
            # input is accepted (not 2 or 3)
            pressed = False
        elif N > 3 or N == 1:
            # init N x N empty array
            array = initArray(N)
            # draw N x N chessboard
            chessboard(N)
            # check if solved
            # prevent solving everytime after changing page
            if isSolved:
                NQueensSolver(array, 0)
                isSolved = False
            # fill selected position
            fillCell(board[page], N)
            # display number of solution
            numOfSol(page, board)
        # events : press a key, click
        for event in pygame.event.get():
            # event - press key
            if event.type == pygame.KEYDOWN:
                # press a number
                if event.unicode.isdigit():
                    number += event.unicode
                # press backspace or del
                if event.key == pygame.K_BACKSPACE or event.key == pygame.K_DELETE:
                    number = number[:-1]
            # mouse click
            elif event.type == pygame.MOUSEBUTTONDOWN:
                pos = pygame.mouse.get_pos()
                x = pos[0]
                y = pos[1]
                # click on solve button
                if solveBtn.collidepoint(x, y) and not pressed:
                    if number != '':
                        N = int(number)
                        number = ''
                        pressed = True
                        isSolved  = True
                # click on prevoius button
                elif prvBtn.collidepoint(x, y) and page > 0:
                    page = page - 1
                # click on next button
                elif nxtBtn.collidepoint(x, y) and page < len(board) - 1:
                    page = page + 1
                # click on clear button - start again
                elif clrBtn.collidepoint(x, y):
                    pressed = False
                    isSolved = False
                    board = []
                    page = 0
            # terminate - close
            elif event.type == pygame.QUIT:
                run = False
        # upadate display
        pygame.display.update()
# ---------------------------------------------------------
# driver
if __name__ == '__main__':
    main()
    pygame.quit()


r"""This script calculates the numerical storage and retrieval of the
optimal input signal that the analytic theory suggests using feasible
parameters and getting high efficiency.
"""
from __future__ import print_function
from pickle import dump
import numpy as np
from matplotlib import pyplot as plt
from orca_memories.misc import (time_bandwith_product, num_integral)
from orca_memories.graphical import sketch_frame_transform
from orca_memories.orca import (set_parameters_ladder,
                                print_params,
                                build_mesh_fdm,
                                calculate_xi0, calculate_Gammap,
                                calculate_optimal_input_xi,
                                calculate_optimal_input_Z,
                                calculate_optimal_input_tau,
                                calculate_pulse_energy,
                                solve)
# from quantum_memories.orca import (calculate_pulse_energy, calculate_F,
#                                    calculate_optimal_input_xi, num_integral,
#                                    calculate_optimal_input_Z,
#                                    calculate_optimal_input_tau,
#                                    solve)
from scipy.constants import c

# We establish base parameters.
folder = "__01__high_efficiency/"
name = ""
plots = False; calculate = False
plots = True
calculate = True

# Set the memory parameters.
if True:
    # The cell to control pulse ratio:
    f = 2.0; l = 1.6*f
    # The cell to control pulse ratio at half light-speed.
    lp = 2*l
    tauw = 300e-12
    D = lp*tauw*c/2
    ########################################################################
    # The bandwidth of the control pulse is chosen so that it is a
    # Fourier-limited square pulse with intensity FWHM in time tauw.
    sigma_power2 = time_bandwith_product("oo")/tauw

    # The bandwidth of the signal pulse is chosen so that it is a
    # Fourier-limited Gaussian pulse with intensity FWHM in time tauw.
    sigma_power1 = time_bandwith_product(1)/tauw
    ########################################################################

    params = {"verbose": 1,
              "nshg": 0, "USE_HG_SIG": True,
              "sigma_power1": sigma_power1/f,
              "sigma_power2": sigma_power2,
              "Temperature": 273.15 + 115,
              "L": D/1.05,
              "w1": 131e-6,
              "w2": 131e-6,
              "delta1": 9.0*1e9*2*np.pi,
              "USE_SQUARE_CTRL": True, "nwsquare": "oo", "nrsquare": "oo",
              "element": "Rb", "isotope": 87}
    params = set_parameters_ladder(params)

    ########################################################################
    # We use the analytic theory to calculate the optimal pulse energy,
    # (that would allow unit efficiency for a narrowband signal and an
    # infinite cell.)
    Ecrit = calculate_pulse_energy(params)
    # We set the pulse energy to that value.
    params["energy_pulse2"] = Ecrit
    ########################################################################
    print_params(params)
    print("")
    params, Z, tau, tau1, tau2, tau3 = build_mesh_fdm(params)
    sketch_frame_transform(params, folder=folder, draw_readout=False)

# Calculate the optimal signal.
if True:
    ########################################################################
    # In xi-space.
    xi0 = calculate_xi0(params)
    Deltaxi = 2/c/tauw
    xi = np.linspace(xi0-4*Deltaxi/2, xi0+4*Deltaxi/2, 1001)

    Gammaxi = calculate_Gammap(params, xi)
    xi, S0xi = calculate_optimal_input_xi(params, xi)
    Sfxi = Gammaxi*S0xi

    # The initial normalization of the xi signal (instead of integrating).
    N0 = c/2
    Nf = num_integral(np.abs(Sfxi)**2, xi)
    eta_ana = Nf/N0

    print("Critical energy: {:.2f} nJ".format(Ecrit*1e9))
    print("Analytic-theory efficiency: {:.4f}".format(eta_ana))

    ########################################################################
    # In Z-space
    Z__, S0Z = calculate_optimal_input_Z(params)
    ########################################################################
    # In tau-space
    tau, S0tau = calculate_optimal_input_tau(params)

# # We calculate the write-in process.
if calculate:
    # NOTE: set analytic_storage to 2 for faster calculation.
    # kwargs = {"plots": True, "folder": folder, "name": "write", "verbose": 0,
    #           "analytic_storage": 1, "S0t": S0tau}
    # tau, Z, Bw, Sw = solve_fdm(params, **kwargs)

    # NOTE: set analytic_storage to 2 for faster calculation.
    kwargs = {"plots": True, "folder": folder, "name": "write", "verbose": 0,
              "analytic_storage": 1, "S0t": S0tau}
    tau, Z, Bw, Sw = solve(params, **kwargs)

# We calculate the read-out process.
if calculate:
    B0_stored = Bw[-1, :]
    # NOTE: set analytic_storage to 2 for faster calculation.
    kwargs = {"plots": True, "folder": folder, "name": "read", "verbose": 0,
              "analytic_storage": 1, "B0z": B0_stored}
    tau, Z, Br, Sr = solve(params, **kwargs)
# We calculate the Beam-splitter picture transmissivities and reflectivities.
if calculate:
    Nt1 = tau1.shape[0]
    S0Z_num = Sw[Nt1-1, :]

    NS = num_integral(np.abs(Sw[:, 0])**2, tau)
    NST = num_integral(np.abs(Sw[:, -1])**2, tau)
    NSR = num_integral(2/c*np.abs(Bw[-1, :])**2, Z)

    NB = num_integral(2/c*np.abs(Br[0, :])**2, Z)
    NBT = num_integral(2/c*np.abs(Br[-1, :])**2, Z)
    NBR = num_integral(np.abs(Sr[:, -1])**2, tau)

    TS = NST/NS
    RS = NSR/NS
    TB = NBT/NB
    RB = NBR/NB

    # RB_naive = 1 - TB
    # RS_naive = 1 - TS
    # print(RS, RS_naive)
    # print(RB, RB_naive)

    Nf = num_integral(np.abs(Sr[:, -1])**2, tau)
    eta_num = Nf/NS
    eta_teo = RS*RB
    assert np.allclose(eta_num, eta_teo)

    print("Numerical efficiency      : {:.4f}".format(eta_num))
    print("Theorical efficiency      : {:.4f}".format(eta_teo))
    print("")
    print("Beam-splitter picture transmissivities and reflectivities:")
    print("TB: {:.4f}, RS: {:.4f}".format(TB, RS))
    print("RB: {:.4f}, TS: {:.4f}".format(RB, TS))
# Save the results.
if calculate:
    dump(params, open(folder+"params.pickle", "wb"))
    dump([tau, Z, Bw, Sw], open(folder+"solution_write.pickle", "wb"))
    dump([tau, Z, Br, Sr], open(folder+"solution_read.pickle", "wb"))
if calculate and plots:
    fs = 15
    ######################################################################
    fig, ax = plt.subplots(2, 1, figsize=(8, 8))
    ax1 = ax[0]
    ax1.xaxis.set_tick_params(labelsize=fs-5)
    ax1.yaxis.set_tick_params(labelsize=fs-5)
    ax2 = ax1.twinx()
    ax2.yaxis.set_tick_params(labelsize=fs-5)

    delay = tau[-1] - tau[0]

    ax1.plot(tau*1e9, np.abs(Sw[:, 0])**2*1e-9, "b-", label="Input")
    ax1.plot(tau*1e9, np.abs(Sw[:, -1])**2*1e-9, "r-", label="Leaked")
    ax1.plot((tau+delay)*1e9, np.abs(Sr[:, -1])**2*1e-9, "g-", label="Output")

    angle1 = np.unwrap(np.angle(Sw[:, 0]))/2/np.pi
    angle2 = np.unwrap(np.angle(Sw[:, -1]))/2/np.pi
    angle3 = np.unwrap(np.angle(Sr[:, -1]))/2/np.pi
    ax2.plot(tau*1e9, angle1, "b:")
    ax2.plot(tau*1e9, angle2, "r:")
    ax2.plot((tau+delay)*1e9, angle3, "g:")

    ax1.set_xlabel(r"$\tau \ [ns]$", fontsize=fs)
    ax1.set_ylabel(r"$|S|^2$  [1/ns]", fontsize=fs)
    ax2.set_ylabel(r"Phase  [revolutions]", fontsize=fs)
    ax1.legend(loc=0, fontsize=fs-5)

    ax[1].plot(Z*100, np.abs(Bw[0, :])**2 * 2/c*1e-2, "b-", label="Input")
    ax[1].plot(Z*100, np.abs(Bw[-1, :])**2 * 2/c*1e-2, "g-", label="Storage")
    ax[1].plot(Z*100, np.abs(Br[-1, :])**2 * 2/c*1e-2, "r-", label="Leakage")
    ax[1].legend(loc=0, fontsize=fs-5)

    ax[1].set_xlabel(r"$Z \ [cm]$", fontsize=fs)
    ax[1].set_ylabel(r"$2|B|^2/c \ [1/cm]$", fontsize=fs)

    plt.savefig(folder+"high_efficiency.png", bbox_inches="tight")
    plt.close()

    ######################################################################

    fig, ax = plt.subplots(1, 1, figsize=(15, 8))
    ax.xaxis.set_tick_params(labelsize=fs-5)
    ax.yaxis.set_tick_params(labelsize=fs-5)
    ax2 = ax.twinx()
    ax2.yaxis.set_tick_params(labelsize=fs-5)

    ax.plot(xi, np.abs(Gammaxi), "k-", label=r"$\Gamma'(\xi)$")
    ax2.plot(xi, np.abs(S0xi), "b-", label=r"$S(\tau=0, \xi)$")
    ax2.plot(xi, np.abs(Sfxi), "g-", label=r"$S(\tau=\tau_f, \xi)$")

    ax.grid(True)
    ax.legend(fontsize=fs, loc=2)
    ax2.legend(fontsize=fs, loc=1)
    ax.set_xlabel(r"$\xi \ [1/m]$", fontsize=fs)
    ax.set_ylabel(r"$F(\xi)$", fontsize=fs)
    ax2.set_ylabel(r"$S(\xi) \ [m]$", fontsize=fs)

    ax.set_xlim(xi[0], xi[-1])

    plt.savefig(folder+"Gamma_xi.png", bbox_inches="tight")
    plt.close()


from collections import namedtuple
from smoke.util import enum

Type = enum(
    Int       = 0, Float  = 1, Vector = 2,
    VectorXY  = 3, String = 4, Array  = 5,
    DataTable = 6, Int64  = 7)

Flag = enum(
    Unsigned              = 1 <<  0, Coord                   = 1 <<  1,
    NoScale               = 1 <<  2, RoundDown               = 1 <<  3,
    RoundUp               = 1 <<  4, Normal                  = 1 <<  5,
    Exclude               = 1 <<  6, XYZE                    = 1 <<  7,
    InsideArray           = 1 <<  8, ProxyAlways             = 1 <<  9,
    VectorElem            = 1 << 10, Collapsible             = 1 << 11,
    CoordMP               = 1 << 12, CoordMPLowPrecision     = 1 << 13,
    CoordMPIntegral       = 1 << 14, CellCoord               = 1 << 15,
    CellCoordLowPrecision = 1 << 16, CellCoordIntegral       = 1 << 17,
    ChangesOften          = 1 << 18, EncodedAgainstTickcount = 1 << 19)

Prop = namedtuple('Prop',
    'src, name, type, flags, pri, len, bits, dt, low, high, array_prop')


from flask import Flask, request, render_template, make_response, url_for, redirect, Markup
import requests
import configparser

# Read the Cloudflare account information from the config file
config = configparser.ConfigParser()
config.read('credentials.cfg')
pi_hostname = config.get('piholeApi', 'pi_hostname')
pi_local_domain = config.get('piholeApi', 'pi_local_domain')
token = config.get('piholeApi', 'token')

app = Flask(__name__)
app.config["DEBUG"] = True

@app.route('/hook/block-enable', methods=['GET'])
def block_enable():

    url = f'http://{pi_hostname}.{pi_local_domain}/admin/api.php?enable&auth={token}'
    r = requests.request("GET", url)
    r.raise_for_status()

    if r.status_code == 200:
        jsn = {"is_active": "true"}
        return(jsn)

    else:
        jsn = {"Error": "Not possible to enable Adblocking"}
        return(jsn)

@app.route('/hook/block-disable', methods=['GET'])
def block_disable():

    url = f'http://{pi_hostname}.{pi_local_domain}/admin/api.php?disable&auth={token}'
    r = requests.request("GET", url)
    r.raise_for_status()

    if r.status_code == 200:
        jsn = {"is_active": "false"}
        return(jsn)

    else:
        jsn = {"Error": "Not possible to disable Adblocking"}
        return(jsn)

if __name__ == "__main__":
    app.run(debug=True)


__author__ = 'aditichaudhary'
import codecs
import math
from collections import defaultdict
import numpy as np
np.random.seed(1)
import os
from sklearn.metrics import pairwise_distances_argmin_min
from copy import deepcopy
import pickle

def getTokenIndexInfo(data_loader, gold_dict, model, output_dict, sentence_index, sentence_index_sent,
                      sentence_index_tokens, token_index):
    sent_index = model.token_index_sent_index_map[token_index]
    sentence_index.append(sent_index)
    sent = model.sent_index_sent_map[sent_index]
    sent = [data_loader.id_to_word[int(token)] for token in sent]
    gold_path = gold_dict[" ".join(sent)]
    sentence_index_sent[sent_index] = (sent, gold_path, output_dict[" ".join(sent)])
    sentence_index_tokens[sent_index].append(model.token_index_relative_idx_map[token_index])
    return sent, model.token_index_relative_idx_map[token_index]

def createAnnotationOutput_mimic_oracle(args, model, data_loader, gold_dict, output_dict):
    sentence_index = []
    sentence_index_sent = {}
    sentence_index_tokens = defaultdict(list)

    typeTag, typeTagIndex, tokenIndex_map, sentIndex_map, _ = readTrain(args.test_path)
    data = {}
    with codecs.open(args.to_annotate, "w", encoding='utf-8') as fout, codecs.open(args.debug, "w", encoding='utf-8') as fdebug:
        sorted_type = sorted(model.approxTypeErrors.items(), key=lambda kv: kv[1], reverse=True )[:args.k]
        fdebug.write("TOKEN\tTYPE\tGOLD\tPRED\tPREDPROB\tERRORS\n")
        for (type, error_percent) in sorted_type:
            token_pred_error = model.predTypeErrors[type]
            token_tag_error = model.approxTokenClassErrors[type]
            sorted_token_tag_error = sorted(token_tag_error.items(),key= lambda kv: kv[1], reverse=True)
            errors = []
            maxTag = sorted_token_tag_error[0][0]
            for (tagId, error) in sorted_token_tag_error:
                tag = data_loader.id2tags["POS"][tagId]
                errors.append(tag + "=" + str(error))

            predErrors = []
            sorted_tag_error = sorted(token_pred_error.items(),key= lambda kv: kv[1], reverse=True)
            for (tagId, error) in sorted_tag_error:
                tag = data_loader.id2tags["POS"][tagId]
                predErrors.append(tag + "=" + str(error))

            token_indices = list(model.type_tokenIndices[type])
            required_embeddings, gold_token_tags, pred_token_tags = [], [],[]
            for token_index in token_indices:
                embedding = model.token_embeddings[token_index]
                gammaVal= model.token_gamma_key[token_index][maxTag]
                prob = np.exp(gammaVal)
                required_embeddings.append(embedding * prob)
                (token_, tag_, sent_index_, relative_index_) = tokenIndex_map[token_index]
                one_sent_ = sentIndex_map[sent_index_]
                pred_path_ = output_dict[" ".join(one_sent_)]
                gold_path_ = gold_dict[" ".join(one_sent_)]
                pred_token_tags.append(pred_path_[relative_index_])
                gold_token_tags.append(gold_path_[relative_index_])

            cluster_center = centeroidnp(np.array(required_embeddings))
            closest, _ = pairwise_distances_argmin_min(np.array([cluster_center]), required_embeddings)
            centroid = token_indices[closest[0]]

            (token, tag, sent_index, relative_index) = tokenIndex_map[centroid]

            one_sent = sentIndex_map[sent_index]

            sentence_index.append(sent_index)
            pred_path = output_dict[" ".join(one_sent)]
            gold_path = gold_dict[" ".join(one_sent)]
            sentence_index_sent[sent_index] = (one_sent, gold_path, pred_path)
            sentence_index_tokens[sent_index].append(relative_index)
            data[token] = {"tokenindices":token_indices, "weighted":required_embeddings, "centroid_center":cluster_center, "pred":pred_token_tags,  "gold":gold_token_tags}
            fdebug.write( str(centroid) + "\t" + data_loader.id_to_word[type] + "\t" + gold_path[relative_index] + "\t" + pred_path[relative_index] + "\t" + "@".join(predErrors) +"\t" + "@".join(errors) + "\n")

        covered = set()
        count = 0

        with open("./" + args.model_name + "approx.pkl", "wb") as f:
            pickle.dump(data, f)

        with codecs.open(args.to_annotate, "w", encoding='utf-8') as fout:

            for sent_index in sentence_index:
                if sent_index not in covered:
                    covered.add(sent_index)
                    (sent, gold_path, pred_path) = sentence_index_sent[sent_index]
                    path = deepcopy(pred_path)
                    for token_index in sentence_index_tokens[sent_index]:
                        path[token_index] = "UNK"

                    for token, tag_label, gold_tag in zip(sent, path, gold_path):
                        fout.write(token + "\t" + tag_label + "\t" + gold_tag + "\n")
                        if tag_label == "UNK":
                            count += 1

                    fout.write("\n")

def centeroidnp(arr):
    length, dim = arr.shape
    return np.array([np.sum(arr[:, i])/length for i in range(dim)])

def readTrain(input):
    typeTag = {}
    typeTagIndex = {}
    tokenIndex_map = {}
    sentIndex_map = {}
    one_sent = []
    output_dict = {}
    gold_path = []
    with codecs.open(input, "r", encoding='utf-8') as fin:
        token_index = 0
        sent_index = 0
        relative_index = 0
        for line in fin:
            if line.startswith("#"):
                continue
            if line == "" or line == "\n":
                sentIndex_map[sent_index] = one_sent
                sent_index += 1
                relative_index = 0
                output_dict[" ".join(one_sent)] = gold_path
                gold_path = []
                one_sent = []

            else:
                line = line.strip().split("\t")
                token, tag = line[1], line[5]
                one_sent.append(token)
                gold_path.append(tag)
                if token not in typeTag:
                    typeTag[token] = defaultdict(lambda:0)
                    typeTagIndex[token] = defaultdict(list)
                typeTag[token][tag] += 1
                typeTagIndex[token][tag].append(token_index)
                tokenIndex_map[token_index] = (token, tag, sent_index, relative_index)
                relative_index += 1
                token_index += 1

        return typeTag, typeTagIndex, tokenIndex_map, sentIndex_map, output_dict

def createAnnotationOutput_SPAN_wise(args, model, data_loader, gold_dict, output_dict, score_sentence):
    sentence_index = []
    reverse = True

    # Order the sentences by entropy of the spans
    fout = codecs.open(args.to_annotate, "w", encoding='utf-8')
    sorted_spans = sorted(model.most_uncertain_entropy_spans, key=lambda k: model.most_uncertain_entropy_spans[k],
                          reverse=reverse)
    print("Total unique spans: {0}".format(len(sorted_spans)))
    count_span = args.k
    count_tokens = args.k

    # DEBUG Print Span Entropy
    fdebug = codecs.open(args.debug, "w", encoding='utf-8')

    # Accumulate tokens by sentence
    sentence_index_sent = {}
    sentence_index_tokens = defaultdict(list)
    spans_index = 0
    for sorted_span in sorted_spans:
        # Debug
        spans_index += 1
        span_words = []
        span_in_text = data_loader.id_to_word[int(sorted_span)]

        if count_tokens <= 0:
            break

        (span_entropy, sentence_key, start, end, best_path, instance_entropy, sent_index, token_index) = \
        model.most_uncertain_entropy_spans[sorted_span]
        sent = sentence_key.split()
        sent = [data_loader.id_to_word[int(token)] for token in sent]
        gold_path = gold_dict[" ".join(sent)]

        if args.normdata and span_in_text.lower() in data_loader.word_to_id:
            sorted_span = data_loader.word_to_id[span_in_text.lower()]

        tokenEntropy = model.typeHeap[str(sorted_span)]
        tokenInfo = model.heapInfo[str(sorted_span)]

        sorted_tokenEntropy, sorted_tokenInfo = zip(*(sorted(zip(tokenEntropy, tokenInfo), reverse=True)))
        (t_sentence_key, t_start, t_sent_index) = sorted_tokenInfo[0]
        t_sent = [data_loader.id_to_word[int(token)] for token in t_sentence_key.split()]
        t_gold_path = gold_dict[" ".join(t_sent)]
        sentence_index.append(t_sent_index)
        sentence_index_sent[t_sent_index] = (t_sent, t_gold_path, output_dict[" ".join(t_sent)])
        sentence_index_tokens[t_sent_index].append(t_start)
        span_words.append(t_sent[t_start])
        pred_path = output_dict[" ".join(t_sent)]
        fdebug.write(
            str(t_sent[t_start]) + "\t" + " ".join(span_words) + "\t" + str(span_entropy) + "\t" + pred_path[
                t_start] + "\t" + t_gold_path[t_start] + "\n")
        count_tokens -= 1

    # print remaining cluster stats
    remaining_spans = sorted_spans[spans_index:]
    for span in remaining_spans:

        (span_entropy, sentence_key, start, end, best_path, instance_entropy, sent_index, token_index) = \
        model.most_uncertain_entropy_spans[span]
        sent = sentence_key.split()
        sent = [data_loader.id_to_word[int(token)] for token in sent]
        gold_path = gold_dict[" ".join(sent)]
        span_words = []
        span_in_text = data_loader.id_to_word[int(span)]
        sentence_index_sent[sent_index] = (sent, gold_path, output_dict[" ".join(sent)])
        fdebug.write(str(token_index) + "\t" + " ".join([sent[start]]) + "\t" + str(span_entropy) + "\n")

    covered = set()
    count = 0
    for sent_index in sentence_index:
        if sent_index not in covered:
            covered.add(sent_index)
            (sent, gold_path, path) = sentence_index_sent[sent_index]
            for token_index in sentence_index_tokens[sent_index]:
                path[token_index] = "UNK"

            for token, tag_label, gold_tag in zip(sent, path, gold_path):
                fout.write(token + "\t" + tag_label + "\t" + gold_tag + "\n")
                if tag_label == "UNK":
                    count += 1

            fout.write("\n")

    print("Total unique spans for exercise: {0}".format(args.k))
    print("Total spans for exercise: {0}".format(count))


import os
import time

import jetson.inference
import jetson.utils

import cv2
import requests
import threading
import numpy as np
from imutils.video import FPS

from utils import gstreamer_pipeline, check_thread_alive, send_picture, calculate_vote
from alpr import detect_plate,accum_vote

delay=10

arr=[]
detection=0

cap_width=1920
cap_height=1080

net = jetson.inference.detectNet("ssd-mobilenet-v2", threshold=0.5)

def detect(img):
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA).astype(np.float32)
    img = jetson.utils.cudaFromNumpy(img)
    detections = net.Detect(img, 1280, 720)
    img = jetson.utils.cudaToNumpy(img, 1280, 720, 4)
    img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR).astype(np.uint8)
    return img, detections

def clear_arr():
    global arr
    global detection
    time.sleep(8)
    detection=0
    arr=[]

def get_bbox(detection):
    num=detection.ClassID
    x1,y1,x2,y2=[int(i) for i in detection.ROI]
    return  num,x1,y1,x2,y2

def main():
    global arr
    global detection
    cap = cv2.VideoCapture(gstreamer_pipeline(capture_width=cap_width,capture_height=cap_height,flip_method=2), cv2.CAP_GSTREAMER)
    #cap = cv2.VideoCapture('../video-test2.mp4')
    if cap.isOpened():
        window_handle = cv2.namedWindow("frame", cv2.WINDOW_AUTOSIZE)

        fps_i=None
        empty_frame=0

        th = threading.Thread(target=send_picture, args=(None,None,delay))
        th.start()

        while cv2.getWindowProperty("frame", 0) >= 0:
            fps=FPS().start()

            ret_val, img = cap.read()

            frame = img.copy()
            img,detections=detect(img)

            #print("# detected : ",len(detections))

            for i in range(len(detections)):
                num,x1,y1,x2,y2=get_bbox(detections[i])

                if num in [3,4,6,8]:
                    detection=detection+1
                    crop = frame[y1:y2,x1:x2]
                    results=detect_plate(crop)
                    #print(results)

                    if results['results']:
                        arr=accum_vote(results['results'],arr)

                cv2.rectangle(frame,(x1,y1),(x2,y2),(255,0,0),4)

            if detection>=10:
                detection=0
                if not check_thread_alive(th):
                    results,arr=calculate_vote(arr)
                    th = threading.Thread(target=send_picture, args=(frame,results,delay))
                    cl = threading.Thread(target=clear_arr)
                    th.start()
                    cl.start()
                else:
                    pass

            cv2.imshow("frame", img)

            if fps_i is None:
                fps_i=0

            fps.update()
            fps.stop()
            fps_i=fps.fps()

            #print("FPS: {:.2f}".format(fps.fps()))

            keyCode = cv2.waitKey(30) & 0xFF
            if keyCode == 27:
                break

        cap.release()
        cv2.destroyAllWindows()
    else:
        print("Unable to open camera")

if __name__ == "__main__":
    main()


from rest_framework.decorators import api_view
from rest_framework.response import Response
from CRUD import models
from . import serializer
from django.core.exceptions import ObjectDoesNotExist

# GET , POST , DELETE , PUT

@api_view(['GET', 'POST'])
def With_NOID(request):

    if request.method == 'GET':
        accounts = models.Accounts.objects.all()
        serializeData = serializer.AccountSerializer(accounts, many=True)

        response = Response()

        data = {
            'isError': False,
            'Message': serializeData.data
        }

        response.data = data

    elif request.method == 'POST':

        # Check email address
        try:
            user = models.Accounts.objects.get(Email=request.POST.get('Email'))

            response = Response()

            data = {
                'isError': True,
                'Message': "Email is already in use"
            }

            response.data = data

        except ObjectDoesNotExist:
            try:
                user = models.Accounts.objects.get(
                    Username=request.POST.get('Username'))

                response = Response()

                data = {
                    'isError': True,
                    'Message': "Username is already in use"
                }

                response.data = data
            except ObjectDoesNotExist:
                serializeData = serializer.AccountSerializer(data=request.data)

                if serializeData.is_valid():
                    serializeData.save()

                    response = Response()

                    data = {
                        'isError': False,
                        'Message': "New Account Has Been Created"
                    }

                    response.data = data

    return response

@api_view(['GET', 'PUT', 'DELETE'])
def With_ID(request, pk):

    if request.method == 'GET':
        try:
            account = models.Accounts.objects.get(id=pk)
            serializeData = serializer.AccountSerializer(account)

            response = Response()

            data = {
                'isError': False,
                'Message': serializeData.data
            }

            response.data = data
        except ObjectDoesNotExist:
            response = Response()

            data = {
                'isError': True,
                'Message': "Account Was Not Created"
            }

            response.data = data

    elif request.method == 'DELETE':
        try:
            account = models.Accounts.objects.get(id=pk)
            account.delete()

            response = Response()

            data = {
                'isError': False,
                'Message': "Account Has been Deleted"
            }

            response.data = data

        except ObjectDoesNotExist:
            response = Response()

            data = {
                'isError': True,
                'Message': "Account Was Not Created"
            }

            response.data = data

    elif request.method == 'PUT':
        try:
            account = models.Accounts.objects.get(id=pk)

            serializeData = serializer.AccountSerializer(account, request.data)

            if serializeData.is_valid():
                serializeData.save()

                response = Response()

                data = {
                    'isError': False,
                    'Message': "New Account Has Been Updated"
                }

                response.data = data

        except ObjectDoesNotExist:
            response = Response()

            data = {
                'isError': True,
                'Message': "Account Was Not Created"
            }

            response.data = data

    return response


#!c:/python26/python.exe
#
# need PIL
# see
# http://www.pythonware.com/products/pil/
# http://www.pythonware.com/library/pil/handbook/introduction.htm
# http://www.pythonware.com/library/pil/handbook/image.htm
# http://www.riaidea.com/blog/archives/279.html
#
from PIL import Image

def decomposejpg(inputName, jpgName, horizontal):
	im = Image.open(inputName)
	im.load()
	if horizontal:
		outim = Image.new("RGB", (im.size[0] * 2, im.size[1]))
	else:
		outim = Image.new("RGB", (im.size[0], im.size[1] * 2))
	outim.paste(im, (0, 0))
	source = im.split()
	source[0].paste(source[0].point(lambda i: 0xff), None)
	im = Image.merge(im.mode, (source[3], source[3], source[3], source[0]))
	if horizontal:
		outim.paste(im, (im.size[0], 0))
	else:
		outim.paste(im, (0, im.size[1]))
	outim.save(jpgName)

def composejpg(jpgName, pngName, horizontal):
	jpgIm = Image.open(jpgName)
	jpgIm.load()
	if horizontal:
		outim = Image.new("RGBA", (jpgIm.size[0] / 2, jpgIm.size[1]))
		img1 = jpgIm.crop((0, 0, jpgIm.size[0] / 2, jpgIm.size[1])).split()
		img2 = jpgIm.crop((jpgIm.size[0] / 2, 0, jpgIm.size[0], jpgIm.size[1])).split()
	else:
		outim = Image.new("RGBA", (jpgIm.size[0], jpgIm.size[1] / 2))
		img1 = jpgIm.crop((0, 0, jpgIm.size[0], jpgIm.size[1] / 2)).split()
		img2 = jpgIm.crop((0, jpgIm.size[1] / 2, jpgIm.size[0], jpgIm.size[1])).split()
	im = Image.merge("RGBA", (img1[0], img1[1], img1[2], img2[0]))
	im.save(pngName)

horizontal = 1
decomposejpg("preview.png", "out.jpg", horizontal)
composejpg("out.jpg", "out.png", horizontal)


import json, string, pickle
from gensim.scripts.glove2word2vec import glove2word2vec
from gensim.models.keyedvectors import KeyedVectors
# from nltk.tokenize import WordPunctTokenizer
from nltk.tokenize import word_tokenize
import numpy as np

WORD_DIM = 300

# glove2word2vec(glove_input_file='/Users/Weini/Dev/GloVe/glove.6B/glove.6B.300d.txt', word2vec_output_file='/Users/Weini/Dev/GloVe/glove.6B/word2vec_glove.6B.300d.txt')
# glove_model = KeyedVectors.load_word2vec_format("/Users/Weini/Dev/GloVe/glove.6B/word2vec_glove.6B.300d.txt", binary=False)
# with open('/Users/Weini/Dev/GloVe/glove.6B/word2vec_glove.6B.300d.pkl', 'wb') as f:
#     pickle.dump(glove_model, f)

def build_vocab(json_filename, glove_p_filename, save_vocab='./data/vqa_glove_vocab2ind.pkl', save_embeddings='./data/vqa_glove_embeddings.pkl'):
	vocab = {'NULL': 0}
	vecs = np.zeros(WORD_DIM)

	with open(glove_p_filename,'rb') as f:
		glove_embed = pickle.load(f)

	with open(json_filename) as file:
		json_data = json.load(file)
		for img in json_data['images']:
			for qapair in img['qa_pairs']:
				# qa_id, image_id
				li = []
				li.extend(word_tokenize(qapair['question'].strip(string.punctuation).lower()))
				# q = word_tokenize(qapair['question'].strip(string.punctuation).lower())
				li.extend(word_tokenize(qapair['answer'].strip(string.punctuation).lower()))
				# answers = [word_tokenize(qapair['answer'].strip(string.punctuation).lower())]
				for choice in qapair['multiple_choices']:
					# answers.append(word_tokenize(choice.strip(string.punctuation).lower()))
					li.extend(word_tokenize(choice.strip(string.punctuation).lower()))

				for t in li:
					if t not in vocab:
						if t in glove_embed:
							# vecs.append(glove_embed[t])
							vecs = np.vstack((vecs, glove_embed[t]))
							vocab[t] = vecs.shape[0]-1

	with open(save_vocab, 'wb') as handle:
		pickle.dump(vocab, handle)
	with open(save_embeddings, 'wb') as handle:
		pickle.dump(vecs, handle)

def process_qas_embeds(json_filename, vocab_p_filename, save_file=''):
	with open(vocab_p_filename,'rb') as f:
		vocab = pickle.load(f)

	qa_map = []
	with open(json_filename) as file:
		json_data = json.load(file)
		for img in json_data['images']:
			for qapair in img['qa_pairs']:
				# qa_id, image_id
				q = word_tokenize(qapair['question'].strip(string.punctuation).lower())
				answers = [word_tokenize(qapair['answer'].strip(string.punctuation).lower())]
				for choice in qapair['multiple_choices']:
					answers.append(word_tokenize(choice.strip(string.punctuation).lower()))

				q_ids = []
				as_ids = []
				for t in q:
					id = vocab[t] if t in vocab else 0
					q_ids.append(id)
				q_ids = np.asarray(q_ids, dtype=np.int32)
				for a in answers:
					a_ids = []
					for t in a:
						id = vocab[t] if t in vocab else 0
						a_ids.append(id)
					as_ids.append(np.asarray(a_ids, dtype=np.int32))

				qa = {'qa_id': qapair['qa_id'],
					  'img_id': img["image_id"],
					  'q_embed': q_ids, # nparray of indices
					  'a_embeds': as_ids} # list of 4 nparray of indices
				qa_map.append(qa)
				# print()
		if save_file:
			with open(save_file, 'wb') as handle:
				pickle.dump(qa_map, handle)
		return qa_map

def sent2vec(glove_embed, sentence, word_dim):
	v = np.array([]).reshape(0, word_dim)
	for w in sentence:
		if w in glove_embed:
			v = np.vstack((v, glove_embed[w]))
	if v.shape[0] == 0:
		v = np.vstack((v, np.zeros_like(glove_embed['this'])))
	return v

def process_qas(json_filename, glove_p_filename, save=''):
	with open(glove_p_filename,'rb') as f:
		glove_embed = pickle.load(f)

	qa_map = []
	with open(json_filename) as file:
		json_data = json.load(file)
		for img in json_data['images']:
			for qapair in img['qa_pairs']:
				# qa_id, image_id
				# qa_id_list.append(qapair['qa_id'])
				q = word_tokenize(qapair['question'].strip(string.punctuation).lower())
				answers = [word_tokenize(qapair['answer'].strip(string.punctuation).lower())]
				for choice in qapair['multiple_choices']:
					answers.append(word_tokenize(choice.strip(string.punctuation).lower()))

				# qv = np.array([]).reshape(WORD_DIM,)
				qv = sent2vec(glove_embed, q, WORD_DIM)
				# print("qv", qv.shape)
				# qa_m = np.array([]).reshape(0, WORD_DIM)
				av_list = []
				for ans in answers:
					av = sent2vec(glove_embed, ans, WORD_DIM)
					av_list.append(av)
				qa = {'qa_id': qapair['qa_id'],
						'img_id': img["image_id"],
						'q_embed': qv,
						'a_embeds': av_list}
				qa_map.append(qa)
	if save:
		with open(save, 'wb') as handle:
			pickle.dump(qa_map, handle)
	return qa_map

if __name__ == '__main__':
	json_filename = './data/visual7w-telling.json'
	glove_p_filename = './data/word2vec_glove.6B.300d.pkl'
	# print(process_qas(json_filename, glove_p_filename)[0])

	build_vocab(json_filename, glove_p_filename)

	process_qas_embeds('./data/visual7w-telling_train.json', './data/vqa_glove_vocab2ind.pkl', './data/qa_embeds_train.pkl')
	process_qas_embeds('./data/visual7w-telling_val.json', './data/vqa_glove_vocab2ind.pkl', './data/qa_embeds_val.pkl')
	process_qas_embeds('./data/visual7w-telling_test.json', './data/vqa_glove_vocab2ind.pkl', './data/qa_embeds_test.pkl')

	# print('image_id_list len', len(image_id_list))
	# print('image_id_list min', min(image_id_list))
	# print('image_id_list max', max(image_id_list))
	# print('qa_id_list len', len(qa_id_list))
	# print('qa_id_list min', min(qa_id_list))
	# print('qa_id_list max', max(qa_id_list))