import sys
import contextlib
import time
import threading

from PySide6.QtWidgets import QApplication, QWidget, QToolButton, QSizePolicy
from PySide6.QtWidgets import QUndoView, QHBoxLayout, QVBoxLayout, QListView
from PySide6.QtWidgets import QMainWindow
from PySide6.QtGui import QPainter, QColor, QPixmap, QPen, QTabletEvent
from PySide6.QtGui import QPainterPath, QCursor, QBitmap, QIcon, QAction
from PySide6.QtGui import QUndoStack, QUndoCommand, QStandardItemModel
from PySide6.QtGui import QStandardItem, QUndoGroup, QPointingDevice
from PySide6.QtGui import QKeyEvent
from PySide6.QtCore import Qt, QEvent, QRect, QTimer, QFile, QObject, QSize
from PySide6.QtCore import Signal, QPointF, QRectF, QSizeF, QItemSelectionModel
from PySide6.QtUiTools import QUiLoader

import global_shortcuts

MAX_RADIUS = 100

COLORS = {
    'Red': (1, 0, 0),
    'Green': (0, 1, 0),
    'Blue': (0, 0, 1),
    'Yellow': (1, 1, 0),
    'Purple': (1, 0, 1),
    'Cyan': (0, 1, 1),
}

class Overlay():
    composition_mode = QPainter.CompositionMode_SourceOver
    opacity = 0.5
    _final = None
    def __init__(self, topleft=None, pixmap=None, prev=None):
        self.pixmap = pixmap
        self.prev = prev
        if topleft and pixmap:
            self.rect = QRect(
                topleft.x(), topleft.y(),
                pixmap.width(), pixmap.height()
            )
        else:
            self.rect = None

    def _opaque_copy(self):
        result = Overlay(self.rect.topLeft(), self.pixmap.copy())
        result.opacity = 1
        return result

    def __repr__(self):
        return f'<Overlay {self.rect}>'

    def paint(self, painter):
        if self.rect:
            painter.setOpacity(self.opacity)
            painter.setCompositionMode(self.composition_mode)
            painter.drawPixmap(self.rect.topLeft(), self.pixmap)

    def reserve(self, rect):
        if self.rect:
            new_rect = self.rect.united(rect)
        else:
            new_rect = rect
        new_pixmap = QPixmap(new_rect.width(), new_rect.height())
        new_pixmap.fill(QColor(0, 0, 0, 0))
        if self.pixmap:
            painter = QPainter(new_pixmap)
            painter.drawPixmap(
                self.rect.left() - new_rect.left(),
                self.rect.top() - new_rect.top(),
                self.pixmap
            )
            painter.end()
        self.pixmap = new_pixmap
        self.rect = new_rect

    def add(self, other_overlay):
        if self.rect:
            self.reserve(other_overlay.rect)
            painter = QPainter(self.pixmap)
            painter.drawPixmap(
                other_overlay.rect.left() - self.rect.left(),
                other_overlay.rect.top() - self.rect.top(),
                other_overlay.pixmap
            )
            painter.end()
        else:
            self.pixmap = other_overlay.pixmap.copy()
            self.rect = other_overlay.rect

    @contextlib.contextmanager
    def painter_context(self):
        self._final = None
        if self.pixmap:
            painter = QPainter(self.pixmap)
            painter.translate(-self.rect.topLeft())
            try:
                yield painter
            finally:
                painter.end()
        else:
            yield None

    @property
    def final(self):
        if self._final:
            return self._final
        if self.prev and self.prev.final.pixmap:
            self._final = self.prev.final._opaque_copy()
        else:
            self._final = Overlay()
            self._final.opacity = 1
        if self.pixmap:
            self._final.reserve(self.rect)
            with self._final.painter_context() as painter:
                self.paint(painter)
        return self._final

class DrawCommand(QUndoCommand):
    def __init__(self, widget, tool):
        super().__init__(f"Draw with {tool.name}")
        self.widget = widget
        self.scribbles = widget.scribbles
        if self.scribbles:
            self.scribble = Overlay(prev=self.scribbles[-1])
        else:
            self.scribble = Overlay()
        self.tool = tool

    def undo(self):
        popped = self.scribbles.pop()
        self.widget.current_wet = Overlay()
        if popped.rect:
            self.widget.update(popped.rect)
            assert popped == self.scribble

    def redo(self):
        self.scribbles.append(self.scribble)
        if self.scribble.rect:
            self.widget.update(self.scribble.rect)

class PictureItem(QStandardItem):
    def __init__(self, widget):
        super().__init__("Drawing")
        self.scribbles = []
        self.undo_stack = QUndoStack()
        self.undo_stack.indexChanged.connect(self.reset_props)
        self.widget = widget
        widget.undo_group.addStack(self.undo_stack)

    def start_scribble(self):
        cmd = DrawCommand(self.widget, self.widget.tool)
        self.undo_stack.push(cmd)

    def reset_props(self):
        if self.undo_stack.index() == self.undo_stack.count():
            self.setText(f"Drawing ({self.undo_stack.index()})")
        else:
            self.setText(f"Drawing ({self.undo_stack.index()}/{self.undo_stack.count()})")
        if self.scribbles:
            s = self.scribbles[-1]
            if s.final.pixmap:
                self.setIcon(s.final.pixmap)
            else:
                self.setIcon(QIcon())
        else:
            self.setIcon(QIcon())

class SignalingProperty:
    def __init__(self, signal, default=None, *, name=None):
        self.signal = signal
        self.default = default
        self.name = name

    def __set_name__(self, owner, name):
        if self.name is None:
            self.name = name

    def __get__(self, instance, owner):
        assert self.name
        if instance:
            return instance.__dict__.get(self.name, self.default)
        else:
            return super().__get__(instance, owner)

    def __set__(self, instance, value):
        assert self.name
        prev = instance.__dict__.get(self.name, self.default)
        if value != prev:
            instance.__dict__[self.name] = value
            self.signal.__get__(instance, type(instance)).emit(value)

class OverlayWidget(QWidget):
    grab_updated = Signal(bool)
    can_clear_changed = Signal(bool)
    can_undo_changed = Signal(bool)
    can_redo_changed = Signal(bool)
    can_clear = SignalingProperty(can_clear_changed)
    can_undo = SignalingProperty(can_undo_changed)
    can_redo = SignalingProperty(can_redo_changed)
    _last_cursor_pos = None
    _grabbing_mouse = False

    def __init__(self):
        super().__init__()
        self.setWindowTitle('pointout canvas')
        self.setWindowFlags(
            self.windowFlags()
            | Qt.Window
            | Qt.WindowTransparentForInput
            | Qt.WindowDoesNotAcceptFocus
            | Qt.FramelessWindowHint
            | Qt.WindowStaysOnTopHint
        )
        self.setAttribute(Qt.WA_TransparentForMouseEvents)
        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setAttribute(Qt.WA_TabletTracking)

        self.current_wet = Overlay()

        self.undo_group = QUndoGroup()
        self.picture_model = QStandardItemModel()
        self.selection_model = QItemSelectionModel(self.picture_model)
        self.clear(force=True)
        self.selection_model.currentChanged.connect(self.picture_switched)
        self.picture_switched()
        self.undo_group.canUndoChanged.connect(self.update_action_availability)
        self.undo_group.canRedoChanged.connect(self.update_action_availability)

        cursor_bitmap = QBitmap.fromData(QSize(5, 5), bytes((
            0b00000, 0b00000, 0b00100, 0b00000, 0b00000,
        )))
        mask_bitmap = QBitmap.fromData(QSize(5, 5), bytes((
            0b00100, 0b00000, 0b10101, 0b00000, 0b00100,
        )))
        self.setCursor(QCursor(cursor_bitmap, mask_bitmap))

        self.anim_timer = QTimer()
        self.anim_timer.timeout.connect(self.anim_update)
        self.anim_timer.start(1000//30)
        self.anim_timer.setTimerType(Qt.CoarseTimer)
        self.wet_end = time.monotonic()

        self.eraser = Eraser()
        self.tool = Marker()
        self.last_point = 0

    def picture_switched(self):
        self.undo_group.setActiveStack(self.picture.undo_stack)
        self.update_action_availability()
        self.update()

    def update_action_availability(self):
        self.can_clear = bool(self.undo_stack.count())
        self.can_undo = (
            self.undo_stack.canUndo()
            or self.selection_model.currentIndex().row() > 0
        )
        rc = self.picture_model.rowCount()
        self.can_redo = (
            self.undo_stack.canRedo()
            or self.selection_model.currentIndex().row() < rc - 1
        )

    @property
    def picture(self):
        idx = self.selection_model.currentIndex()
        return self.picture_model.itemFromIndex(idx)

    @property
    def scribbles(self):
        return self.picture.scribbles

    @property
    def undo_stack(self):
        return self.picture.undo_stack

    @property
    def tool(self):
        return self._tool
    @tool.setter
    def tool(self, new_tool):
        self._tool = new_tool
        if new_tool is None:
            self.update_grab(False)

    def anim_update(self):
        if self.current_wet.rect is not None:
            with self.current_wet.painter_context() as painter:
                painter.setBrush(QColor(0, 0, 0, 255))
                painter.setPen(QPen(0))
                painter.setOpacity(0.1)
                painter.setCompositionMode(QPainter.CompositionMode_DestinationOut)
                painter.drawRect(self.current_wet.rect)
            self.update(self.current_wet.rect)
            if self.wet_end < time.monotonic():
                self.current_wet = Overlay()

    def paintEvent(self, e):
        painter = QPainter(self)
        if self.scribbles:
            self.scribbles[-1].final.paint(painter)
        painter.setOpacity(1)
        if self.current_wet:
            self.current_wet.paint(painter)
        painter.end()

    def tabletEvent(self, e):
        if e.type() == QEvent.TabletPress:
            self.start_line(e.posF())
        if e.type() in (QEvent.TabletMove, QEvent.TabletRelease):
            self.add_point(
                pos=e.posF(),
                pressure=e.pressure(),
                erase=e.pointerType() == QPointingDevice.PointerType.Eraser,
            )
        e.accept()

    def mousePressEvent(self, e):
        self.start_line(e.localPos())

    def mouseMoveEvent(self, e):
        self.add_point(e.localPos())

    def start_line(self, pos):
        self.last_point = pos
        self.picture.start_scribble()
        self.update_action_availability()

    def add_point(self, pos, *, pressure=0.5, erase=False):
        tool = self.tool
        if self.tool is None:
            return
        if erase:
            tool = self.eraser
        if not self.scribbles:
            self.start_line(pos)
        if self.last_point:
            tool.set_size(pressure)
            update_rect = QRect(self.last_point.toPoint(), pos.toPoint())
            update_rect = update_rect.normalized().adjusted(
                -tool.size-1, -tool.size-1, tool.size+1, tool.size+1,
            )
            tool.draw(
                self.last_point, pos,
                update_rect,
                self.scribbles, self.current_wet
            )
            self.update(update_rect)
        self.last_point = pos
        self.picture.reset_props()
        self.update_wet()

    def clear(self, *, force=False):
        if force or self.can_clear:
            pi = PictureItem(self)
            idx = self.selection_model.currentIndex()
            if idx:
                self.picture_model.insertRow(idx.row() + 1, pi)
            else:
                self.picture_model.appendRow(pi)
            self.selection_model.setCurrentIndex(
                self.picture_model.indexFromItem(pi),
                QItemSelectionModel.ClearAndSelect,
            )

    def undo(self):
        if self.undo_stack.canUndo():
            self.undo_stack.undo()
        elif self.can_undo:
            idx = self.selection_model.currentIndex()
            if idx.row() > 0:
                idx = self.picture_model.index(idx.row() - 1, 0)
                self.selection_model.setCurrentIndex(
                    idx,
                    QItemSelectionModel.ClearAndSelect,
                )

    def redo(self):
        if self.undo_stack.canRedo():
            self.undo_stack.redo()
        elif self.can_redo:
            idx = self.selection_model.currentIndex()
            if idx.row() < self.picture_model.rowCount() - 1:
                idx = self.picture_model.index(idx.row() + 1, 0)
                self.selection_model.setCurrentIndex(
                    idx,
                    QItemSelectionModel.ClearAndSelect,
                )

    def create_undo_action(self):
        act = QAction('Undo')
        act.triggered.connect(self.undo)
        act.setEnabled(False)
        self.can_undo_changed.connect(act.setEnabled)
        return act

    def create_redo_action(self):
        act = QAction('Redo')
        act.triggered.connect(self.redo)
        act.setEnabled(False)
        self.can_redo_changed.connect(act.setEnabled)
        return act

    def update_wet(self, seconds=1):
        self.wet_end = time.monotonic() + seconds

    def update_grab(self, grab):
        was_grabbing_mouse = self._grabbing_mouse
        if self.tool is None:
            grab = False
        if grab:
            if not self.tool:
                return False
            self._grabbing_mouse = True
            self.grabMouse()
        else:
            self.releaseMouse()
            self._grabbing_mouse = False
            if self._last_cursor_pos:
                QCursor.setPos(self._last_cursor_pos)
        self.grab_updated.emit(self._grabbing_mouse)

class Tool:
    name = 'tool'

    def __init__(self):
        self.pen = QPen(
            QColor(0, 0, 0, 0),
            0,
            Qt.SolidLine,
            Qt.RoundCap,
            Qt.BevelJoin,
        )
        self.set_size(1)

    def set_size(self, size):
        self.size = size
        self.alpha = 255
        if size < 1:
            self.alpha = int(255 * size)
            self.size = 1
        self.pen.setWidth(self.size)
        color = self.pen.color()
        color.setAlpha(self.alpha)
        self.pen.setColor(color)

    def draw(self, last, now, update_rect, scribbles, wet):
        for overlay in scribbles[-1], wet:
            if overlay:
                overlay.reserve(update_rect)
                with overlay.painter_context() as painter:
                    painter.setPen(self.pen)
                    painter.setRenderHint(QPainter.Antialiasing)
                    painter.drawLine(last, now)

class Marker(Tool):
    name = 'Marker'
    def set_size(self, size):
        super().set_size(size * MAX_RADIUS / 10)

class ColorMarker(Tool):
    name = 'Color Marker'
    def __init__(self, r, g, b, name=None):
        super().__init__()
        self.pen.setColor(QColor(int(r*255), int(g*255), int(b*255)))
        if name:
            self.name = f'{name} Marker'

    def set_size(self, size):
        super().set_size(size * MAX_RADIUS / 5)

class Highlighter(Tool):
    name = 'Highlighter'
    def set_size(self, size):
        self.pen.setColor(QColor(255, 250, 0, 255))
        super().set_size(size * MAX_RADIUS / 2)

class Eraser(Tool):
    name = 'Eraser'
    def set_size(self, size):
        super().set_size(size * MAX_RADIUS)
        self.pen.setColor(QColor(255, 255, 255, 255))

    def draw(self, last, now, update_rect, scribbles, wet):
        overlay = scribbles[-1]
        overlay.composition_mode = QPainter.CompositionMode_DestinationOut
        overlay.opacity = 1
        super().draw(last, now, update_rect, scribbles, wet)

class WidgetFinder:
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, name):
        widget = self.obj.findChild(QObject, name)
        if widget is None:
            raise AttributeError(name)
        return widget

def make_tool_button(text, shortcut):
    btn = QToolButton()
    btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
    btn.setText(text)
    btn.setShortcut(shortcut)
    btn.setCheckable(True)
    btn.setAutoExclusive(True)
    return btn

def make_toolbox_window(overlay_widget):
    window = QMainWindow()
    window.setWindowFlags(
        window.windowFlags()
        | Qt.FramelessWindowHint
        | Qt.WindowStaysOnTopHint
    )
    window.resize(0, 0)
    central = QWidget()
    window.setCentralWidget(central)
    window.shortcut_to_action = {}
    main_layout = QVBoxLayout()
    central.setLayout(main_layout)

    def add_layout():
        layout = QHBoxLayout(window)
        main_layout.addLayout(layout)
        return layout

    def tool_setter(tool):
        def func():
            overlay_widget.tool = tool
        return func

    layout = add_layout()

    for text, shortcut, tool, activate in (
        ("&Disable", "D", None, False),
        ("&Marker", "M", Marker(), True),
        ("&Hilite", "H", Highlighter(), False),
        ("&Eraser", "E", Eraser(), False),
    ):
        btn = make_tool_button(text, shortcut)
        layout.addWidget(btn)
        if activate:
            btn.setChecked(True)
        window.shortcut_to_action[shortcut] = btn.click
        btn.clicked.connect(tool_setter(tool))

    layout = add_layout()

    for i, (name, color) in enumerate(COLORS.items(), 1):
        tool = ColorMarker(*color, name)
        btn = make_tool_button(str(i), str(i))
        btn.setStyleSheet("background-color: rgb({}, {}, {});".format(
            *[c*255 for c in color])
        )
        layout.addWidget(btn)
        btn.setToolTip(name)
        window.shortcut_to_action[str(i)] = btn.click
        btn.clicked.connect(tool_setter(tool))

    toolbar = window.addToolBar("Main toolbar")

    act_draw = QAction('Draw', window)
    act_draw.setCheckable(True)
    act_draw.setShortcut('Esc')
    act_draw.toggled.connect(overlay_widget.update_grab)
    overlay_widget.grab_updated.connect(act_draw.setChecked)
    window.shortcut_to_action['Esc'] = act_draw.toggle
    window.shortcut_to_action['D'] = act_draw.toggle
    toolbar.addAction(act_draw)

    def add_action(text, func, icon, shortcut=None):
        act = QAction(QIcon.fromTheme(icon), text, window)
        act.triggered.connect(func)
        if shortcut:
            act.setShortcut(shortcut)
            window.shortcut_to_action[shortcut] = act.trigger
        toolbar.addAction(act)
        return act

    for action_factory, icon, shortcut in (
        (overlay_widget.create_undo_action, 'edit-undo-symbolic', 'Z'),
        (overlay_widget.create_redo_action, 'edit-redo-symbolic', 'Y'),
    ):
        act = action_factory()
        act.setIcon(QIcon.fromTheme(icon))
        act.setShortcut(shortcut)
        window.shortcut_to_action[shortcut] = act.trigger
        toolbar.addAction(act)

    clr = add_action('Clear', overlay_widget.clear, 'document-new-symbolic', 'Q')
    overlay_widget.can_clear_changed.connect(clr.setEnabled)
    clr.setEnabled(overlay_widget.can_clear)
    toolbar.addSeparator()
    add_action('Close', sys.exit, 'process-stop-symbolic')

    layout = add_layout()
    ilv = QListView()
    ilv.setModel(overlay_widget.picture_model)
    ilv.setSelectionModel(overlay_widget.selection_model)
    layout.addWidget(ilv)
    layout.addWidget(QUndoView(overlay_widget.undo_group))

    return window

def make_overlay_widget():
    w = OverlayWidget()

    for screen in reversed(app.screens()):
        print(screen.manufacturer())
        if screen.manufacturer().startswith(('Wacom', 'Chimei')):
            geom = screen.geometry()
            w.move(geom.left(), geom.top())
            w.resize(geom.width(), geom.height())

    return w

class Application(QApplication):
    def __init__(self, *args):
        super().__init__(*args)
        self._grabbing_mouse = False
        self._last_cursor_pos = QCursor.pos()

        def update_pos():
            if not self._grabbing_mouse:
                self._last_cursor_pos = QCursor.pos()

        self._timer = QTimer()
        self._timer.timeout.connect(update_pos)
        self._timer.start(100)

    def event(self, e):
        print(e)
        if e.type() == QEvent.TabletEnterProximity:
            print('enter', toolbox.geometry(), QCursor.pos())
            if toolbox.geometry().contains(QCursor.pos()):
                return False
            overlay_widget.update_grab(True)
            return True
        elif e.type() == QEvent.TabletLeaveProximity:
            print('leave')
            overlay_widget.update_grab(False)
            return True
        elif e.type() == QEvent.TabletTrackingChange:
            print('track')
            return True
        elif e.type() == QEvent.User:
            print('app handling', e.key)
            try:
                act = toolbox.shortcut_to_action[e.key]
            except KeyError:
                print(f'no {e.key}...')
            else:
                print(act)
                act()
        return False

def watch_shortcuts(app, widget):
    def post(key):
        app.postEvent(app, MyEvent(key))
    global_shortcuts.watch_shortcuts(post)

class MyEvent(QEvent):
    def __init__(self, key):
        super().__init__(QEvent.User)
        self.key = key

    def __repr__(self):
        return f'my event! {self.key}'

def main():
    global app, toolbox, overlay_widget
    app = Application(sys.argv)

    overlay_widget = make_overlay_widget()

    overlay_widget.showFullScreen()

    toolbox = make_toolbox_window(overlay_widget)
    toolbox.show()
    toolbox.move(overlay_widget.geometry().topLeft())

    app._toolbox = toolbox

    threading.Thread(
        target=watch_shortcuts,
        args=(app, overlay_widget, ),
        daemon=True
    ).start()

    sys.exit(app.exec())

if __name__ == '__main__':
    main()


import math
import numpy as np
from numpy import genfromtxt
import random
from sklearn.cluster import k_means
import matplotlib.pyplot as plt

class ParticleFilter:
    rows = 0
    cols = 0
    x_pos = 0
    y_pos = 0
    th_pos = 0
    particles = 0
    fig = 0
    plot = 0

    def __init__(self, file_name, cell_size, n_angles, n_samples, resample_rate, sigma_measure, sigma_resample_pos,
                 sigma_resample_angle, start_x=None, start_y=None, start_th=None):
        self.grid_map = genfromtxt(file_name, delimiter=',')  # read in file_name and store as numpy array
        #self.grid_map = np.flip(self.grid_map, axis=0)
        self.plot_map = self.grid_map
        self.cell_size = cell_size
        self.n_angles = n_angles
        self.angle_resolution = 360 / n_angles
        self.n_samples = n_samples
        self.resample_rate = resample_rate
        self.sigma_measure = sigma_measure
        self.sigma_resample_pos = sigma_resample_pos
        self.sigma_resample_angle = sigma_resample_angle
        self.rows = np.size(self.grid_map, 0)
        self.cols = np.size(self.grid_map, 1)

        self.init_plot()
        self.init_particles(start_x=start_x, start_y=start_y, start_th=start_th)
        self.update_estimation()

    def init_plot(self):
        self.plot = plt
        plt.ion()
        self.fig = plt.figure()

    def pad_border(self):
        self.grid_map = np.pad(self.grid_map, pad_width=1, mode='constant', constant_values=1)

    def update_map(self, x, y):
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()
        self.plot_map = np.copy(self.grid_map)
        self.plot_map[int(y / self.cell_size), int(x / self.cell_size)] = 1
        self.plot_map[int(self.y_pos / self.cell_size), int(self.x_pos / self.cell_size)] = 0.3
        self.plot.imshow(self.plot_map, 'Greys')

    def buffer_map(self, size):

        # Switcharoo
        self.grid_map = 1 - self.grid_map

        [num_rows, num_cols] = self.grid_map.shape

        ones_row = np.ones((1, num_cols), dtype=np.int)  # add to top and bottom
        ones_col = np.ones(num_rows, dtype=np.int)  # add to left and right

        for k in range(size):
            # arr1 - shift up (remove first row, add bottom row)
            arr1 = np.delete(self.grid_map, 0, axis=0)  # removes first row
            arr1 = np.insert(arr1, (num_rows - 1), ones_row, axis=0)  # zero adds to the row axis

            # arr2 - shift down (remove last row, add first row)
            arr2 = np.delete(self.grid_map, (num_rows - 1), axis=0)  # removes last row
            arr2 = np.insert(arr2, 0, ones_row, axis=0)

            # arr3 - shift right (remove last column, add first column)
            arr3 = np.delete(self.grid_map, (num_cols - 1), axis=1)
            arr3 = np.insert(arr3, 0, ones_col, axis=1)

            # arr4 - shift left (remove first column, add last column)
            arr4 = np.delete(self.grid_map, 0, axis=1)
            arr4 = np.insert(arr4, (num_cols - 1), ones_col, axis=1)

            # arr5 shift up one AND left one, arr1 is already shifted up, now shift left
            arr5 = np.delete(arr1, 0, axis=1)
            arr5 = np.insert(arr5, (num_cols - 1), ones_col, axis=1)

            # arr6 shift up one AND right one -- shift arr1 right
            arr6 = np.delete(arr1, (num_cols - 1), axis=1)
            arr6 = np.insert(arr6, 0, ones_col, axis=1)

            # arr7 shift down one AND left one -- shift arr2 left
            arr7 = np.delete(arr2, 0, axis=1)
            arr7 = np.insert(arr7, (num_cols - 1), ones_col, axis=1)

            # arr8 shift down one AND right one -- shift arr2 right
            arr8 = np.delete(arr2, (num_cols - 1), axis=1)
            arr8 = np.insert(arr8, 0, ones_col, axis=1)

            self.grid_map = self.grid_map * arr1 * arr2 * arr3 * arr4 * arr5 * arr6 * arr7 * arr8

        # Switcharoo
        self.grid_map = 1 - self.grid_map

    def ray_tracing(self, x_pos, y_pos, direct):

        # Set Max Row/Col to Extremities
        max_row = self.rows
        max_col = self.cols

        # Set Start Row/Col based on Current Location
        start_row = math.floor(y_pos / self.cell_size)
        start_col = math.floor(x_pos / self.cell_size)

        # Wrap Direction to 360 Degrees
        direct = direct % 360

        # Band-aid for Values Where Slopes are 0 or Inf
        if direct % 90 == 0:
            direct = (direct + np.spacing(1000)) % 360

        # Determine the Quadrant of The Direction
        inc_col = int(np.sign(math.cos(direct * np.pi / 180)))
        inc_row = int(np.sign(math.sin(direct * np.pi / 180)))

        ########################################
        # Get Horizontal Scan and Intersection #
        ########################################
        if inc_row > 0:
            delta_y1 = self.cell_size * (start_row + 1) - y_pos
        else:
            delta_y1 = self.cell_size * start_row - y_pos

        delta_x1 = delta_y1 / math.tan(direct * np.pi / 180)

        y_step = inc_row * self.cell_size
        x_step = y_step / math.tan(direct * np.pi / 180)

        current_x = x_pos + delta_x1
        current_y = y_pos + delta_y1

        current_row = start_row + inc_row
        current_col = math.floor(current_x / self.cell_size)

        while True:
            if current_col < 0 or current_col >= max_col:
                x_intersection_h = np.nan
                y_intersection_h = np.nan
                break
            elif current_row < 0 or current_row >= max_row:
                x_intersection_h = current_x
                y_intersection_h = current_y
                break
            elif self.grid_map[current_row, current_col] != 0:
                x_intersection_h = current_x
                y_intersection_h = current_y
                break

            current_x = current_x + x_step
            current_y = current_y + y_step
            current_col = math.floor(current_x / self.cell_size)
            current_row = current_row + inc_row

        ########################################
        # Get Vertical Scan and Intersection #
        ########################################
        if inc_col > 0:
            delta_x1 = self.cell_size * (start_col + 1) - x_pos
        else:
            delta_x1 = self.cell_size * start_col - x_pos

        delta_y1 = delta_x1 * math.tan(direct * np.pi / 180)

        x_step = inc_col * self.cell_size
        y_step = x_step * math.tan(direct * np.pi / 180)

        current_x = x_pos + delta_x1
        current_y = y_pos + delta_y1

        current_col = start_col + inc_col
        current_row = math.floor(current_y / self.cell_size)

        while True:
            if current_row < 0 or current_row >= max_row:
                x_intersection_v = np.nan
                y_intersection_v = np.nan
                break
            elif current_col < 0 or current_col >= max_col:
                x_intersection_v = current_x
                y_intersection_v = current_y
                break
            elif self.grid_map[current_row, current_col] != 0:
                x_intersection_v = current_x
                y_intersection_v = current_y
                break

            current_x = current_x + x_step
            current_y = current_y + y_step
            current_row = math.floor(current_y / self.cell_size)
            current_col = current_col + inc_col

        #####################
        # COMPUTE DISTANCES #
        #####################
        dist_h = math.sqrt(math.pow((x_pos - x_intersection_h), 2) + math.pow((y_pos - y_intersection_h), 2))
        dist_v = math.sqrt(math.pow((x_pos - x_intersection_v), 2) + math.pow((y_pos - y_intersection_v), 2))

        my_list = [dist_h, dist_v]
        min_index = my_list.index(min(my_list))

        # Both NaN
        if np.isnan(dist_h) and np.isnan(dist_v):
            return np.nan

        # Python's min method does not work if NaN's are present
        # Double if statement shrunk into one
        if np.isnan(dist_v) or min_index == 0:
            return dist_h
        else:
            return dist_v

    def reinit_particles(self):

        num_new_needed = self.n_samples - len(self.particles)

        weight = 1 / self.n_samples
        max_x = 0.99998 * (self.cols * self.cell_size)
        max_y = 0.99998 * (self.rows * self.cell_size)

        particle = []

        for i in range(num_new_needed):

            particle.append(max_x * random.uniform(0, 1.0) + 0.00001)
            particle.append(max_y * random.uniform(0, 1.0) + 0.00001)
            particle.append(359 * random.uniform(0, 1.0))
            particle.append(weight)

            ind_row = math.floor(particle[1] / self.cell_size)
            ind_col = math.floor(particle[0] / self.cell_size)

            while self.grid_map[ind_row, ind_col] != 0:
                particle[0] = max_x * random.uniform(0, 1) + 0.00001
                particle[1] = max_y * random.uniform(0, 1) + 0.00001

                ind_row = math.floor(particle[1] / self.cell_size)
                ind_col = math.floor(particle[0] / self.cell_size)

            particle = np.array(particle)
            vector_scans = self.get_scans(particle[0], particle[1], particle[2])
            particle = np.append(particle, vector_scans)

            self.particles = np.append(self.particles, [particle], axis=0)
            particle = []

        # if this method works all removed particles should be replaced
        assert len(self.particles[:]) == self.n_samples

    def init_particles(self, start_x=None, start_y=None, start_th=None):

        self.particles = np.full([self.n_samples, 4 + self.n_angles], np.nan)

        weight = 1 / self.n_samples
        max_x = 0.99998 * (self.cols * self.cell_size)
        max_y = 0.99998 * (self.rows * self.cell_size)

        for i in range(len(self.particles)):

            if start_x is not None:
                self.particles[i, 0] = start_x
            else:
                self.particles[i, 0] = max_x * random.uniform(0, 1.0) + 0.00001
            if start_y is not None:
                self.particles[i, 1] = start_y
            else:
                self.particles[i, 1] = max_y * random.uniform(0, 1.0) + 0.00001
            if start_th is not None:
                self.particles[i, 2] = start_th
            else:
                self.particles[i, 2] = 359 * random.uniform(0, 1.0)

            self.particles[i, 3] = weight

            ind_row = math.floor(self.particles[i, 1] / self.cell_size)
            ind_col = math.floor(self.particles[i, 0] / self.cell_size)

            while self.grid_map[ind_row, ind_col] != 0:
                self.particles[i, 0] = max_x * random.uniform(0, 1) + 0.00001
                self.particles[i, 1] = max_y * random.uniform(0, 1) + 0.00001
                # self.particles[i][0] = max_x * 0.707
                # self.particles[i][1] = max_y * 0.707

                ind_row = math.floor(self.particles[i, 1] / self.cell_size)
                ind_col = math.floor(self.particles[i, 0] / self.cell_size)

            vector_scans = self.get_scans(self.particles[i, 0], self.particles[i, 1], self.particles[i, 2])
            self.particles[i, 4:] = vector_scans

    def get_scans(self, x, y, th):

        vector_scans = np.full(self.n_angles, np.nan)

        for i in range(self.n_angles):
            vector_scans[i] = self.ray_tracing(x, y, th)
            th = th + self.angle_resolution

        return vector_scans

    def move_particles(self, delta_x, delta_y, delta_theta):

        max_x = self.cols * self.cell_size
        max_y = self.rows * self.cell_size
        nan_vec = np.full(4 + self.n_angles, np.nan)

        for i in range(self.n_samples):
            self.particles[i, 0] = self.particles[i, 0] + delta_x
            self.particles[i, 1] = self.particles[i, 1] + delta_y
            self.particles[i, 2] = (self.particles[i, 2] + delta_theta) % 360

            ind_row = math.floor(self.particles[i, 1] / self.cell_size)
            ind_col = math.floor(self.particles[i, 0] / self.cell_size)

            if not 0 <= self.particles[i, 0] < max_x:
                self.particles[i, :] = nan_vec  # outside map in x
            elif not 0 <= self.particles[i, 1] < max_y:
                self.particles[i, :] = nan_vec  # outside map in t
            elif self.grid_map[ind_row, ind_col] != 0:
                self.particles[i, :] = nan_vec  # inside obstacle

    def weight_computation(self, particle_vector, measurements_vector):

        if not len(particle_vector) == len(measurements_vector):
            raise RuntimeError('Lidar measurements must have same resolution of particle filter!')

        weight = 1
        for i in range(len(particle_vector)):
            if np.isnan(particle_vector[i]) or np.isnan(measurements_vector[i]):
                continue

            diff = abs(particle_vector[i] - measurements_vector[i])
            pdf = (1 / (self.sigma_measure * np.sqrt(2 * np.pi))) * np.exp(-0.5 * pow(diff / self.sigma_measure, 2))
            weight = weight * pdf

        return weight

    def re_sample(self, measurements_vec):

        max_x_gen = 0.99998 * self.cols * self.cell_size
        max_y_gen = 0.99998 * self.rows * self.cell_size

        n_old_samples = round(self.n_samples * (1 - self.resample_rate))

        new_particles = np.full([self.n_samples, 4 + self.n_angles], np.nan)

        # removing nan rows without replacement is no good
        self.particles = self.particles[~np.isnan(self.particles).all(axis=1)]  # replace full nan rows

        # randomly add back in particles that were put off the map or in an obby
        self.reinit_particles()

        for i in range(len(self.particles)):
            self.particles[i, 3] = self.weight_computation(self.particles[i, 4:], measurements_vec)

        total_weight = np.sum(self.particles[:, 3])

        if total_weight != 0:
            for i in range(len(self.particles)):
                self.particles[i, 3] = round((self.particles[i, 3] / total_weight) * n_old_samples)

        index = 0
        weight = 1 / self.n_samples

        for i in range(len(self.particles)):

            for j in range(int(self.particles[i, 3])):

                thth = np.random.normal(self.particles[i, 2], self.sigma_resample_angle) % 360
                xx = abs(np.random.normal(self.particles[i, 0], self.sigma_resample_pos))
                yy = abs(np.random.normal(self.particles[i, 1], self.sigma_resample_pos))

                if xx > max_x_gen:
                    xx = max_x_gen
                elif xx <= 0:
                    xx = 0.00001

                if yy > max_y_gen:
                    yy = max_y_gen
                elif yy <= 0:
                    yy = 0.00001

                ind_row = math.floor(yy / self.cell_size)
                ind_col = math.floor(xx / self.cell_size)

                while self.grid_map[ind_row, ind_col] != 0:

                    xx = abs(np.random.normal(self.particles[i, 0], self.sigma_resample_pos))
                    yy = abs(np.random.normal(self.particles[i, 1], self.sigma_resample_pos))

                    if xx > max_x_gen:
                        xx = max_x_gen
                    elif xx <= 0:
                        xx = 0.00001

                    if yy > max_y_gen:
                        yy = max_y_gen
                    elif yy <= 0:
                        yy = 0.00001

                    ind_row = math.floor(yy / self.cell_size)
                    ind_col = math.floor(xx / self.cell_size)

                new_particles[index, 0] = xx
                new_particles[index, 1] = yy
                new_particles[index, 2] = thth

                vector_scans = self.get_scans(xx, yy, thth)

                new_particles[index, 4:] = vector_scans
                new_particles[index, 3] = weight
                index += 1

                if index > n_old_samples:
                    break

        for i in range(index, len(self.particles)):

            new_particles[i, 0] = max_x_gen * random.uniform(0, 1) + 0.00001
            new_particles[i, 1] = max_y_gen * random.uniform(0, 1) + 0.00001
            new_particles[i, 2] = 359 * random.uniform(0, 1)
            new_particles[i, 3] = weight

            ind_row = math.floor(new_particles[i, 1] / self.cell_size)
            ind_col = math.floor(new_particles[i, 0] / self.cell_size)

            while self.grid_map[ind_row][ind_col] != 0:
                new_particles[i, 0] = max_x_gen * random.uniform(0, 1) + 0.00001
                new_particles[i, 1] = max_y_gen * random.uniform(0, 1) + 0.00001

                ind_row = math.floor(new_particles[i, 1] / self.cell_size)
                ind_col = math.floor(new_particles[i, 0] / self.cell_size)

            vector_scans = self.get_scans(new_particles[i, 0], new_particles[i, 1], new_particles[i, 2])

            new_particles[i, 4:] = vector_scans

        self.particles = new_particles

    def update_estimation(self):

        # COULD USE MODE, MUCH FASTER, SEE WHAT THE PROBLEM REQUIRES
        pos_centroid = k_means(X=self.particles[:, 0:2], n_clusters=1)
        theta_centroid = k_means(X=self.particles[:, 2].reshape(-1, 1), n_clusters=1)

        self.y_pos = pos_centroid[0][0][1]
        self.x_pos = pos_centroid[0][0][0]
        self.th_pos = theta_centroid[0][0][0]

    def update_state(self, delta_x, delta_y, delta_theta, distance_vec):

        # Move Particles
        self.move_particles(delta_x, delta_y, delta_theta)

        # Resample
        self.re_sample(distance_vec)

        # Update Estimation
        self.update_estimation()


import datetime
import json
import socket
import sys
import threading
import argparse
import os

def run_server(host, port, verbose, directory):
    listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        listener.bind((host, port))
        listener.listen(5)
        print('The server is ready to receive at port', port) if verbose else ''
        while True:
            conn, addr = listener.accept()
            threading.Thread(target=handle_client, args=(conn, addr, verbose, directory)).start()
    finally:
        listener.close()

def handle_client(conn, addr, verbose, directory):
    print('New client from', addr) if verbose else ''
    try:
        while True:
            data = conn.recv(1024)
            if not data:
                break
            query = readQuery(data.decode(), directory, verbose)
            conn.sendall(query.encode("utf-8"))
    finally:
        print("Connection with client from", addr, "is now closed") if verbose else ''
        conn.close()

def readQuery(query, directory, verbose):
    queryList = query.split("\r\n")
    request_type = queryList[0].split(' ')[0]
    fileName = queryList[0].split(' ')[1]
    headers = get_all_content_headers(query, request_type)
    if '.py' in fileName:
        print('HTTP Error 400: Access Restrictions. You cannot read or write this file') if verbose else ''
        return format_verbose(headers, 'HTTP Error 400: Access Restrictions. You cannot read or write this file\r\n') + "\r\nPlease try again"
    if request_type == 'GET':
        if queryList[0].split(' ')[1] == '/':
            list_of_files = getListOfFiles(directory)
            client_query = "The files in the directory " + directory + " are the following:\r\n"
            for file in list_of_files:
                client_query += os.path.basename(os.path.normpath(file))
                client_query += "\r\n"
            print('HTTP/1.0 200 OK') if verbose else ''
            full_query = format_verbose(headers, 'HTTP/1.0 200 OK\r\n') + "\r\n" + client_query
            return full_query.strip()
        else:
            fileName = queryList[0].split(' ')[1]
            fileContent = readFileContent(fileName, directory, query, verbose)
            return fileContent
    if request_type == 'POST':
        fileName = queryList[0].split(' ')[1]
        if fileName == '/':
            print('HTTP ERROR 404: You need to append a file name to the request') if verbose else ''
            full_query = format_verbose(headers, "HTTP ERROR 404: You need to append a file name to the request\r\n") + "\r\nHTTP ERROR 404: Please retry"
            return full_query
        query_body = get_query_body(queryList)
        res = writeFile(fileName, directory, query_body, query, verbose)
        return res
    return request_type

def get_query_body(queryList):
    counter = 0
    for line in queryList:
        if line == '':
            break
        counter = counter + 1
    body_index = counter + 1
    return queryList[body_index]

def writeFile(fileName, directory, query_body, query, verbose):
    if directory == '/':
        fileName = fileName[1:]
    file_to_write = directory[1:] + fileName
    if '/' in file_to_write:
        os.makedirs(os.path.dirname(file_to_write), exist_ok=True)
    headers = get_all_content_headers(query, 'POST')
    try:
        f = open(file_to_write, 'w')
    except OSError:
        print("HTTP ERROR 404: Could not write to file: " + file_to_write + "\r\n") if verbose else ''
        full_query = format_verbose(headers, "HTTP ERROR 404: Could not write to file: " + file_to_write + "\r\n")  + "\r\nHTTP ERROR 404: Please retry"
        return full_query
    f.write(query_body)
    print ('HTTP 200 OK') if verbose else ''
    res = format_verbose(headers, "HTTP 200 OK\r\n") + "\r\n" + query_body
    return res

def readFileContent(fileName, directory, query, verbose):
    headers = get_all_content_headers(query, 'GET')
    if directory == '/':
        fileName = fileName[1:]
    file_to_open = directory[1:] + fileName
    try:
        f = open(file_to_open, 'r')
    except OSError:
        print("HTTP ERROR 404: Could not read file: " + file_to_open + "\r\n") if verbose else ''
        return format_verbose(headers, "HTTP ERROR 404: Could not read file: " + file_to_open + "\r\n") + "\r\nHTTP ERROR 404: Please retry"
    file_data = f.read()
    print ('HTTP/1.0 200 OK') if verbose else ''
    response = format_verbose(headers, 'HTTP/1.0 200 OK\r\n') + "\r\n" + file_data
    return response

def getListOfFiles(directory):
    files_list = []
    path = os.getcwd().replace("\\", "/") + directory + "/"
    for filename in os.listdir(path):
        f = os.path.join(filename)
        absolute_path = path + f
        if os.path.isfile(absolute_path) and '.py' not in f:
            files_list.append(absolute_path)
    return files_list

def get_all_content_headers(query, request_type):
    query_list = query.split("\r\n")
    headers = ""
    if request_type != 'POST':
        headers = "Content-Length: " + str(len(query)) + "\r\n"
    for line in query_list[2:]:
        headers += line
        headers += "\r\n"
        if line == '':
            break
    return headers.strip()

def format_verbose(headers, status_code):
    verbose = ""
    verbose += status_code
    verbose += datetime.datetime.now().strftime("%c") + "\r\n"
    verbose += headers
    verbose += '\r\n'
    return verbose

# Usage python httpfs.py [--port port-number]
parser = argparse.ArgumentParser()
parser.add_argument("-v", action='store_true', help='verbose')
parser.add_argument("-p", help="port", type=int, default=8080)
parser.add_argument("-d", help="directory", default='/')
args = parser.parse_args()
run_server('', args.p, args.v, args.d)


import logging

import torch
import torch.nn.functional as F
from torch import nn

class AffinityLoss:
    """Affinity loss based on pre-calculated shape similarity.

    Parameters
    ----------
    lookup : np.ndarray (M, M)
        A square symmetric matrix where each column and row is the index of an
        object from the training set, consisting of M different objects. The
        value at (i, j) is a scalar value encoding the shape similarity between
        objects i and j, pre-calculated using some shape (or other) metric. The
        identity of the matrix should be 1 since these objects are the same
        shape. The affinity similarity should be normalized to the range
        (-1, 1).

    Notes
    -----
    The final loss is calculated using L1-norm. This could be changed, e.g.
    L2-norm. Not sure what the best one is yet.
    """

    def __init__(self, lookup: torch.Tensor, device: torch.device):
        self.device = device
        self.lookup = torch.tensor(lookup).to(device)
        self.cos = nn.CosineSimilarity(dim=1, eps=1e-8)
        self.l1loss = nn.L1Loss()

    def __call__(
        self, y_true: torch.Tensor, y_pred: torch.Tensor
    ) -> torch.Tensor:
        """Return the affinity loss.

        Parameters
        ----------
        y_true : torch.Tensor (N, )
            A vector of N objects in the mini-batch of the indices representing
            the identity of the object as an index. These indices should
            correspond to the rows and columns of the `lookup` table.
        y_pred : torch.Tensor (N, latent_dims)
            An array of latent encodings of the N objects.

        Returns
        -------
        loss : torch.Tensor
            The affinity loss.
        """
        # first calculate the affinity, for the real classes
        c = (
            torch.combinations(y_true, r=2, with_replacement=False)
            .to(self.device)
            .long()
        )
        affinity = self.lookup[c[:, 0], c[:, 1]].to(self.device)

        # now calculate the latent similarity
        z_id = torch.tensor(list(range(y_pred.shape[0])))
        c = torch.combinations(z_id, r=2, with_replacement=False)
        latent_similarity = self.cos(y_pred[c[:, 0], :], y_pred[c[:, 1], :])
        loss = self.l1loss(latent_similarity, affinity)
        return loss

class AVAELoss:
    """AffinityVAE loss consisting of reconstruction loss, beta
    parametrised latent regularisation loss and
    gamma parametrised affinity regularisation loss. Reconstruction loss
    should be Mean Squared Error for real
    valued data and Binary Cross-Entropy for binary data. Latent
    regularisation loss is KL Divergence. Affinity
    regularisation is defined in AffinityLoss class.

    Parameters
    ----------
    device : torch.device
        Device used to calculate the loss.
    beta: list
        Beta parameter list defining weight on latent regularisation term.
    gamma : list
        Gamma parameter list defining weight on affinity regularisation term,
        default = 1. Only used if lookup_aff is present.
    lookup_aff : np.ndarray [M, M]
        A square symmetric matrix where each column and row is the index of an
        object class from the training set, consisting of M different classes.
    recon_fn : 'MSE' or 'BCE'
        Function used for reconstruction loss. BCE uses Binary
        Cross-Entropy for binary data and MSE uses Mean
        Squared Error for real-valued data.

    """

    def __init__(self, device, beta, gamma, lookup_aff=None, recon_fn="MSE"):
        self.device = device
        self.recon_fn = recon_fn
        self.beta = beta

        self.affinity_loss = None
        self.gamma = gamma

        if lookup_aff is not None and max(gamma) != 0:
            self.affinity_loss = AffinityLoss(lookup_aff, device)

        elif lookup_aff is None and max(gamma) != 0:
            raise RuntimeError(
                "Affinity matrix is needed to compute Affinity loss"
                ". Although you've set gamma, you have not provided --af/"
                "--affinity parameter."
            )
        elif lookup_aff is not None and max(gamma) == 0:
            logging.warning(
                "\n\nWARNING: You provided affinity matrix but no gamma. Unless "
                "you provide gamma, affinity will be ignored and you're "
                "running a vanilla beta-VAE.\n"
            )
            self.affinity_loss = None

    def __call__(self, x, recon_x, mu, logvar, epoch, batch_aff=None):
        """Return the aVAE loss.

        Parameters
        ----------
        x : torch.Tensor (N, CH, Z, Y, X)
            Mini-batch of inputs, where N stands for the number of samples in
            the mini-batch, CH stands for number of
            channels and X, Y, Z define input dimensions.
        recon_x : torch.Tensor (N, CH, Z, Y, X)
            Mini-batch of outputs, where N stands for the number of samples in
            the mini-batch, CH stands for number of
            channels and X, Y, Z define input dimensions.
        mu : torch.Tensor (N, latent_dims)
            Mini-batch of encoder outputs representing latent means, where N
            stands for the number of samples in the
            mini-batch and 'latent_dims' defines the number of latent
            dimensions.
        logvar : torch.Tensor (N, latent_dims)
            Mini-batch of encoder outputs representing latent log of the
            variance, where N stands for the number of
            samples in the mini-batch and 'latent_dims' defines the number of
            latent dimensions.
        batch_aff : torch.Tensor (N, )
            Optional, must be present if AVAELoss was
            initialised with 'lookup_aff' parameter containing affinity
            lookup matrix. A vector of N objects in the mini-batch of the
            indices representing the identity of the object's class as
            an index. These indices should correspond to the rows and columns
            of the `lookup_aff` table.

        Returns
        -------
        total_loss : torch.Tensor
            Combined reconstruction, latent regularisaton and affinity loss.
        recon_loss : torch.Tensor
            Reconstruction loss.
        kldivergence : torch.Tensor
            Non-weighted KL Divergence loss.
        affin_loss : torch.Tensor
            Non-weighted affinity loss.
        """
        if self.affinity_loss is not None and batch_aff is None:
            raise RuntimeError(
                "aVAE loss function requires affinity ids for the batch."
            )

        # recon loss
        if self.recon_fn == "BCE":
            recon_loss = F.binary_cross_entropy(x, recon_x, reduction="mean")
        elif self.recon_fn == "MSE":
            recon_loss = F.mse_loss(x, recon_x, reduction="mean")
        else:
            raise RuntimeError(
                "AffinityVAE loss requires 'BCE' or 'MSE' for 'loss_fn' "
                "parameter."
            )

        # kldiv loss
        kldivergence = -0.5 * torch.mean(1 + logvar - mu.pow(2) - logvar.exp())

        # affinity loss
        affin_loss = torch.Tensor([0]).to(self.device)
        if self.affinity_loss is not None:
            affin_loss = self.affinity_loss(batch_aff, mu)

        # total loss
        total_loss = (
            recon_loss
            + self.beta[epoch] * kldivergence
            + self.gamma[epoch] * affin_loss
        )

        return total_loss, recon_loss, kldivergence, affin_loss


import socket

def main():
    # 1. 创建套接字
    server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定本地信息
    server_sock.bind(("", 54321))
    # 3. 开始监听
    server_sock.listen(128)  # 参数表示处于连接请求状态的最大请求数量
    # 开始循环，为多个套接字服务
    while True:
        print("等待一个新的客户端连接")
        # 4. 等待新的连接请求，此函数会返回一个元组：客户端套接字，客户端地址
        client_sock, client_addr = server_sock.accept()
        # 内存循环，为客户端服务
        while True:
            # 5. 接收客户端的数据，此函数会阻塞，直到“接收到客户端发送的数据”或者“客户端套接字关闭”
            recv_data = client_sock.recv(1024)
            # 如果recv解阻塞，那么有两种方式：
            # 1. 客户端发送过来数据
            # 2. 客户端调用 close，此时recv_data为空
            print(type(client_addr[0]))

            if recv_data:
                # 服务：将数据回送给客户端
                print("接收到客户端 %s 发送过来的数据，内容是：\n\t%s" % (str(client_addr), recv_data.decode("utf-8")))
                client_sock.send("I have get your message!".encode("utf-8"))
            else:
                print("%s 已断开" % str(client_addr))
                break
        # 关闭客户端套接字
        client_sock.close()
    # 关闭服务端套接字
    server_sock.close()

if __name__ == '__main__':
    main()

循环为多个客户端服务.py


from Cheetah.Template import Template
import json
class DeplGenerator():
    def __init__(self):
        self.templateDef = '''
        app $appName {
            #for $host, $actor in $deplMap
            #if len($modelFile['actors'][actor]['formals']) > 0
            on ($host) ${actor}(#echo ', '.join($argsList[$actor]) #) ;
            #else
            on ($host) $actor;
            #end if
            #end for
            }
        '''

        #if then (  #echo ','.join([param+'=' for param in modelFile['actors'][actor]['formals']]) # ) else # ;

    def gen_deplModel(self, appName, deplMap):
        with open(appName+'.json') as f:
            modelFile = json.load(f)
        argsList = {}
        for actor in modelFile['actors']:
            argsList[actor] = [param['name']+'=' for param in modelFile['actors'][actor]['formals']]
        t = Template(self.templateDef, searchList = [{'appName' : appName, 'deplMap' : deplMap, 'modelFile' : modelFile, 'argsList' : argsList}])
        with open(appName+'auto.depl', 'w') as file:
            file.write(t.respond())

if __name__ == '__main__':
    gen = DeplGenerator()
    t = gen.gen_deplModel(appName, deplMap)


import requests
from jsonpath_rw import parse

import cumulus
from cumulus.common import check_status

ssh_cluster = ['trad', 'ec2']

def get_assetstore_url_base(cluster):
    if cluster['type'] in ssh_cluster:
        return 'sftp_assetstores'
    elif cluster['type'] == 'newt':
        return 'newt_assetstores'
    else:
        raise Exception('Unsupported cluster type')

def get_assetstore_id(girder_token, cluster):
    if 'assetstoreId' in cluster:
        return cluster['assetstoreId']

    headers = {'Girder-Token':  girder_token}
    url_base = get_assetstore_url_base(cluster)
    create_url = '%s/%s' % (cumulus.config.girder.baseUrl, url_base)
    body = {
        'name': cluster['_id'],
        'host': cluster['config']['host'],
        'machine': cluster['config']['host'],
        'authKey': cluster['_id']
    }

    user = parse('config.ssh.user').find(cluster)
    if user:
        body['user'] = user[0].value

    r = requests.post(create_url, json=body, headers=headers)

    # If the assetstore has been created, patch the cluster to point to it
    if r.status_code == 200:
        assetstore_id = r.json()['_id']

        cluster_url = '%s/clusters/%s' % (cumulus.config.girder.baseUrl,
                                          cluster['_id'])
        body = {
            'assetstoreId': assetstore_id
        }
        r = requests.patch(cluster_url, json=body, headers=headers)
        check_status(r)

    # The assetstore may have already been created by another concurrently
    # running task flow. If thats the case, just fetch it and return its id.
    elif r.status_code == 400:
        body = r.json()
        if body.get('field') == 'name' and body.get('type') == 'validation':
            assetstores_url = '%s/assetstore/lookup' % (
                cumulus.config.girder.baseUrl)
            params = {'name': cluster['_id']}
            r = requests.get(assetstores_url, params=params, headers=headers)
            check_status(r)
            assetstores = r.json()
            if len(assetstores) == 0:
                raise Exception(
                    'Could not find assetstore with name "%s" even though '
                    'it should already exist.' % cluster['_id']
                )

            assetstore_id = assetstores[0]['_id']
        else:
            check_status(r)

    # Raise any other errors
    else:
        check_status(r)

    cluster['assetstoreId'] = assetstore_id

    return assetstore_id


from cvzone.FaceDetectionModule import FaceDetector
import cv2
import numpy as np
import spO2
import sys

cap = cv2.VideoCapture(0)
# cap = cv2.VideoCapture('./Video 004a V.Trujillo.mp4')
# cap = cv2.VideoCapture('./Video 009c M.CUBILLOS.mp4')
# cap = cv2.VideoCapture('./Video 014a E.Trujillo.mp4')
# cap = cv2.VideoCapture('./Video 003 G.Trujillo.MOV')
### Acceso a la cámara
if (sys.argv[1]=="0"):
    capture = cv2.VideoCapture(0)
else:
    cap = cv2.VideoCapture(sys.argv[1])

detector = FaceDetector()
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_righteye_2splits.xml')

mouth_cascade = cv2.CascadeClassifier('./mouth.xml')
count = 0
FDC_B, FDC_G, FDC_R = 0, 0, 0
FAC_B, FAC_G, FAC_R = 0, 0, 0
FMAX_B, FMAX_G, FMAX_R = 0, 0, 0
FMIN_B, FMIN_G, FMIN_R = 255, 255, 255

MDC_B, MDC_G, MDC_R = 0, 0, 0
MAC_B, MAC_G, MAC_R = 0, 0, 0
MMAX_B, MMAX_G, MMAX_R = 0, 0, 0
MMIN_B, MMIN_G, MMIN_R = 255, 255, 255

regressor = spO2.creat_SVR_FUNCTION()

def grabCam():
    success, img = cap.read()
    img, bboxs = detector.findFaces(img)
    forehead_img,mouth_img = [],[]
    mouth_intensity, forehead_intensity = 0,0

    if bboxs:
        center = bboxs[0]["center"]
        cv2.circle(img, center, 5, (255, 0, 255), cv2.FILLED)

        eyes = eye_cascade.detectMultiScale(img, 1.03, 5, 0, (40, 40))
        x = bboxs[0]['bbox'][0]
        y = bboxs[0]['bbox'][1]
        w = bboxs[0]['bbox'][2]
        h = bboxs[0]['bbox'][3]
        cx = bboxs[0]['center'][0]
        cy = bboxs[0]['center'][1]

        # Se dibuja el rectangulo, arriba de los parametros de los ojos.
        ex,ey,ew,eh = 99999,0,0,0
        izq = 0
        for (exx,eyy,eww,ehh) in eyes:
            if eyy < cy :
                if eyy > y :
                    if ex > exx :
                        ex = exx
                    if izq < exx+eww :
                        izq = exx+eww
                        ey = eyy

        if (izq > 0):
            cv2.rectangle(img, (ex,y), (izq,ey), (0,255,0), 2)
            forehead_img = img[y:y+ey, x+ex:x+izq].copy()

        # Se aplica el reconociento de boca dentro del cuadro del rostro.
        mouth = mouth_cascade.detectMultiScale(img, 1.1, 20)

        ## Se elimina el reconocimiento de bocas sobre la mitad superior de la cara.
        for (mx,my,mw,mh) in mouth:
            if my > cy:
                if my+mh < y+h:
                    cv2.rectangle(img, (mx,my), (mx+mw,my+mh), (255,255,0), 2)
                    mouth_img = img[my:my+mh, mx:mx+mw].copy()

    cv2.imshow("Image", img)

    return img, forehead_img, mouth_img

while True:
    count += 1
    img, forehead_img, mouth_img = grabCam()
    if (len(forehead_img) > 0):
        FP_b, FP_g, FP_r = spO2.Color_Mean(forehead_img)
        FAC_R, FAC_G, FAC_B, FMIN_B, FMIN_G, FMIN_R, FMAX_B, FMAX_G, FMAX_R = spO2.AC_Calculation(FP_b, FP_g, FP_r, FAC_R, FAC_G, FAC_B, FMIN_B, FMIN_G, FMIN_R, FMAX_B, FMAX_G, FMAX_R, count)
        FDC_R, FDC_G, FDC_B = spO2.DC_Calculation(FP_b, FP_g, FP_r, FDC_R, FDC_G, FDC_B, count)

    if (len(mouth_img) > 0):
        MP_b, MP_g, MP_r = spO2.Color_Mean(mouth_img)
        MAC_R, MAC_G, MAC_B, MMIN_B, MMIN_G, MMIN_R, MMAX_B, MMAX_G, MMAX_R = spO2.AC_Calculation(MP_b, MP_g, MP_r, MAC_R, MAC_G, MAC_B, MMIN_B, MMIN_G, MMIN_R, MMAX_B, MMAX_G, MMAX_R, count)
        MDC_R, MDC_G, MDC_B = spO2.DC_Calculation(MP_b, MP_g, MP_r, MDC_R, MDC_G, MDC_B, count)

    if (count == 50):
        if(FAC_R > 0):
            Fsat = spO2.SVR_PREDICT(FAC_R, FAC_G, FAC_B, FDC_R, FDC_G, FDC_B, regressor)
            print('spO2 Frente: ', Fsat)

        if(MAC_R > 0):
            Msat = spO2.SVR_PREDICT(MAC_R, MAC_G, MAC_B, MDC_R, MDC_G, MDC_B, regressor)
            print('spO2 Boca: ', Msat)

        count = 0

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()


#! usr/bin/python3
"""
This module creates a hash table with sequences and the corresponding
secondary structures.

USAGE:
    python csvtohash.py secondarystructure_COMP533.csv prothashtable.p

OUTPUT:
    GENERAL OUTPUT:
        hashtable = { "sequence" : {"secondary structure" : counts} }

    SPECIFIC OUTPUT EXAMPLE:
        hashtable = {"AGCTH" : {"CEEEH" : 2, ..., "EEEEE" : 30},
                      ...
                     "TTPGH" : {"HHHEE" : 34, ..., "HHEEE" : 2}}
"""
from typing import Dict
import sys
import pandas as pd
from tqdm import tqdm
import pickle
from pathlib import Path

HashTableType = Dict[str, Dict[str, float]]
# class for the hash table
class ProteinHash:
    """
    This object holds the mappings from sequence to potential
    secondary structure. This allows for a fast mapping of
    sequence to structure for building a graph.
    """

    def __init__(self, csv_in, kmer_size):
        self.csv_file: Path = Path(csv_in)
        self.prothash = None # must construct on initialization
        self.k_mersize = kmer_size
        self.sequence_column = 2
        self.structure_column = 3

    def parse_csv(self, csv_file=None, delimitor: str=",") -> pd.DataFrame:
        """
        This method parses an input csv and places the sequences
        and corresponding secondary structures into a pandas dataframe.

        Parameters
        ----------
        delimitor : str [DEFAULT: ","]
            The delimitor to use per row of the input file.

        Returns
        -------
        potential_secondaries: pd.DataFrame
            Returns a dataframe connecting primary sequences with the
            corresponding secondary structure.
        """
        if csv_file == None:
            csv_file = self.csv_file
        with open(csv_file) as opened_file:
            file_by_lines = opened_file.readlines()
            # construct the sequence and structure vectors from csv
            sequence_vector = []
            structure_vector = []
            for line_number, csv_row in enumerate(file_by_lines):
                if line_number > 0:
                    csv_row_list = csv_row.strip("\n").split(delimitor)
                    sequence_vector.append(csv_row_list[self.sequence_column].strip("'"))
                    structure_vector.append(csv_row_list[self.structure_column].strip("'"))
            # add sequences and structures to a pandas dataframe
            df = {'sequence': sequence_vector, 'structure': structure_vector}
            structseq_dataframe = pd.DataFrame(data=df)

        return structseq_dataframe

    def construct_hash(self, seq_column_name: str="sequence",
                             struct_column_name: str="structure") -> HashTableType:
        """
        This method creates the hash table used by the DebruijnExtend algorithm.

        Parameters
        ----------
        seq_column_name : str [DEFAULT: "sequence"]
            The column name for the sequences in a pandas dataframe
        struct_column_name : str [DEFAULT: "structure"]
            The column name for the structures in a pandas dataframe

        Returns
        -------
        potential_secondaries: HashTableType
            returns a hashable datastructure.
        """
        prothash = {}
        protein_df = self.parse_csv()
        print(f"Creating hash table for kmer size = {self.k_mersize} (takes a couple minutes)")
        # make the hash table
        for kmer_start_position, row in tqdm(protein_df.iterrows()):
            primary_sequence, secondary_structure = row[seq_column_name], row[struct_column_name]
            for kmer_start_position in range(len(primary_sequence) - (self.k_mersize-1)):
                kmer_end_position = kmer_start_position + self.k_mersize
                protein_seq_at_index = primary_sequence[kmer_start_position:kmer_end_position]
                structure_seq_at_index = secondary_structure[kmer_start_position:kmer_end_position]
                prothash = self.update_protein_hash_table(prothash,
                                                          protein_seq_at_index,
                                                          structure_seq_at_index)
        return prothash

    def update_protein_hash_table(self, prothash: HashTableType,
                                        protein_seq_at_index:str,
                                        structure_seq_at_index:str) -> HashTableType:
        """
        This method updates the protein hash table.
        """
        if "*" not in protein_seq_at_index: # TODO: check what asterisk is!!!!!!!
            if protein_seq_at_index in prothash.keys():
                if structure_seq_at_index in prothash[protein_seq_at_index].keys():
                    prothash[protein_seq_at_index][structure_seq_at_index] += 1
                else:
                    prothash[protein_seq_at_index][structure_seq_at_index] = 1
            else:
                prothash[protein_seq_at_index] = {}
                prothash[protein_seq_at_index][structure_seq_at_index] = 1
        return  prothash

    def map(self, input_key: str) -> Dict[str, float]:
        """
        return the values for the input key.

        Parameters
        ----------
        input_key: str
            a sequence of length k, where k is the sliding window length

        Returns
        -------
        the potential secondary structures and associated counts.
        """
        return self.prothash[input_key]

def main():
    # defining the input arguments
    csvfile = "/Users/dreyceyalbin/Dropbox/Fall2020-classes/Algorithms/project/DebruijnExtend/py_scripts/training_1.csv"; #sys.argv[1]
    outpickle_name = "out" #sys.argv[2]
    kmer_size = 4 # int(sys.argv[3])
    # construct the hash table
    prothashOBJ = ProteinHash(csvfile, kmer_size)
    prothashtable = prothashOBJ.construct_hash()
    print(prothashtable)
    # pickle the hash table
    outfile = open(outpickle_name,'wb')
    pickle.dump(prothashtable, outfile)

if __name__ == "__main__":
    main()


from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt

m = Basemap(projection='mill',
            llcrnrlat = 7,
            llcrnrlon = 65,
            urcrnrlat = 37,
            urcrnrlon = 100,
            resolution='l')
m.drawcoastlines()
m.drawcountries(linewidth=1)
m.etopo()
xs=[]
ys=[]
Dlat, Dlon = 28.7041, 77.1025
xpt, ypt = m(Dlon, Dlat)
xs.append(xpt)
ys.append(ypt)
m.plot(xpt, ypt, 'co', markersize=10)

Clat, Clon = 13.0827, 80.2707
xpt, ypt = m(Clon, Clat)
xs.append(xpt)
ys.append(ypt)
m.plot(xpt, ypt, 'ro', markersize=10)
m.plot(xs,ys,color='orange',label='Delhi to Chennai')
plt.legend()
plt.title('Pollution Hotspots')
plt.show()


import logging
import threading

import pygame
from maplepy.base.constants import CAMERA_SPEED, GAME_STATE, PYGAME_FLAGS
from maplepy.base.display import ImageDisplay
from maplepy.base.sprite import ConsoleSprite
from maplepy.helper.config import Config
from maplepy.nx.displaynx import DisplayNx

class Game():

    def __init__(self, config_file):

        # Config
        self.config = Config.instance()
        self.config.init(config_file)
        self.width = self.config['width']
        self.height = self.config['height']
        self.fps = self.config['fps']
        self.asset_path = self.config['asset_path']
        self.asset_type = self.config['asset_type']
        self.map = self.config['map']
        self.loading_display = self.config['loading_display_loop']

        # Start pygame
        pygame.init()
        pygame.mixer.init(frequency=44100,
                          size=-16,
                          channels=2,
                          allowedchanges=0)
        pygame.display.set_caption(self.config['caption'])
        icon = pygame.image.load(self.config['icon'])
        pygame.display.set_icon(icon)

        # Create pygame objects
        size = self.width, self.height
        self.screen = pygame.display.set_mode(size, PYGAME_FLAGS)
        self.clock = pygame.time.Clock()

        # Set sprite display
        available_displays = {'nx': DisplayNx}
        SpriteDisplay = available_displays[self.asset_type]

        # Create all displays
        self.displays = {
            GAME_STATE.LOADING: ImageDisplay(self.width, self.height),
            GAME_STATE.DEFAULT: SpriteDisplay(self.width, self.height, self.asset_path)
        }

        # Additional config
        self.displays[GAME_STATE.DEFAULT].set_fixed_background(1280, 720)

        # Game state
        self.threads = []
        self.running = False
        self.state = GAME_STATE.DEFAULT
        self.pressed = {}

        # Console
        self.typing = False
        self.text = ''
        self.console = ConsoleSprite(200, 100)

    def get_state(self):

        if self.threads:
            return GAME_STATE.LOADING
        else:
            return self.state

    def handle_command(self, text):

        # Parse text
        command = text.split()
        if len(command) < 1:
            return

        # Process command
        try:
            cmd = command[0].lower()
            if cmd == 'loading':
                fn = self.displays[GAME_STATE.LOADING].load
                args = tuple(command[1:3])
                thread = threading.Thread(target=fn, args=args)
                thread.start()
                self.threads.append(thread)
            if cmd == 'map':
                fn = self.displays[GAME_STATE.DEFAULT].load_map
                args = tuple(command[1:2])
                thread = threading.Thread(target=fn, args=args)
                thread.start()
                self.threads.append(thread)
            if cmd == 'rand':
                fn = self.displays[GAME_STATE.DEFAULT].load_random_map
                thread = threading.Thread(target=fn)
                thread.start()
                self.threads.append(thread)
        except:
            logging.exception('Command failed')

    def handle_threads(self):

        # Get the result of the thread
        for thread in self.threads:
            if not thread.is_alive():
                thread.join()

        # Remove thread from list if not alive
        self.threads = [thread for thread in self.threads if thread.is_alive()]

    def handle_events(self):

        # Get current state
        state = self.get_state()

        # Handle pygame events
        for event in pygame.event.get():

            # Quit application
            if event.type == pygame.QUIT:
                self.running = False

            # Resize window
            if event.type == pygame.VIDEORESIZE:
                self.width, self.height = event.w, event.h
                for _, display in self.displays.items():
                    display.resize(event.w, event.h)

            # Console input
            if state != GAME_STATE.LOADING and event.type == pygame.KEYDOWN:
                if self.typing:
                    if event.key == pygame.K_ESCAPE:
                        self.typing = False
                        self.text = ''
                        pygame.key.set_repeat()
                    elif event.key == pygame.K_BACKSPACE:
                        self.text = self.text[:-1]
                    elif event.key == pygame.K_RETURN:
                        self.handle_command(self.text)
                        self.typing = False
                        self.text = ''
                    else:
                        self.text += event.unicode
                elif event.key == pygame.K_BACKQUOTE:
                    self.typing = True
                    self.text = ''
                    pygame.key.set_repeat(200)

        # Empty
        pygame.event.pump()

    def handle_inputs(self):

        # Get current state
        state = self.get_state()

        # Prevent quickly pressed keys, remove if done
        self.pressed = {k: v-1 for k, v in self.pressed.items() if v > 1}

        # Get inputs
        # mouse_x, mouse_y = pygame.mouse.get_pos()
        mouse_dx, mouse_dy = pygame.mouse.get_rel()
        mouse_input = pygame.mouse.get_pressed()
        key_input = pygame.key.get_pressed()

        # Camera movement
        if state == GAME_STATE.DEFAULT and mouse_input[2]:
            self.displays[state].move_view(-mouse_dx, -mouse_dy)
        if state == GAME_STATE.DEFAULT and key_input[pygame.K_UP]:
            self.displays[state].move_view(0, -CAMERA_SPEED)
        if state == GAME_STATE.DEFAULT and key_input[pygame.K_DOWN]:
            self.displays[state].move_view(0, CAMERA_SPEED)
        if state == GAME_STATE.DEFAULT and key_input[pygame.K_LEFT]:
            self.displays[state].move_view(-CAMERA_SPEED, 0)
        if state == GAME_STATE.DEFAULT and key_input[pygame.K_RIGHT]:
            self.displays[state].move_view(CAMERA_SPEED, 0)

    def run(self):

        # Setup loading display
        self.handle_command(f'loading {" ".join(self.loading_display)}')

        # Setup initial map
        self.handle_command(f'map {self.map}')

        # Main loop
        self.running = True
        while self.running:

            # Get current state
            state = self.get_state()

            # Handle threads
            self.handle_threads()

            # Handle pygame events
            self.handle_events()

            # Handle inputs
            self.handle_inputs()

            # Clear screen
            self.screen.fill((0, 0, 0))

            # Render environment
            self.displays[state].update()
            self.displays[state].blit(self.screen)

            # Console
            if self.typing:
                self.console.update()
                self.console.blit(self.screen, self.text)

            # Update
            pygame.display.update()
            self.clock.tick(self.fps)


def build_prefix_array(word: str):
    prefix_array = [0 for _ in word]
    i, j = 0, 1
    while j < len(word):
        if word[j] == word[i]:  # character match!
            i += 1  # advance both i and j
            prefix_array[j] = prefix_array[j-1] + 1  # update the length
        else:
            prefix_pointer = i - 1
            i = prefix_array[prefix_pointer]

            while i > 0 and word[j] != word[i]:  # go back to identical suffixes until we get a char match
                prefix_pointer = i-1
                i = prefix_array[prefix_pointer]
            if word[j] == word[i]:
                # We have managed to recover some sort of pattern
                prefix_array[j] = prefix_array[prefix_pointer] + 1
        j += 1
    return prefix_array

text = 'abcxabcdabxabcdabcdabcy'
pattern = 'abcdabcy'
prefix_array = build_prefix_array(pattern)

def find_match(text, pattern, prefix_array):
    j = 0
    for i in range(len(text)):
        if text[i] == pattern[j]:
            j += 1
            if j == len(pattern):
                # Found a match!
                return i - len(pattern) + 1
        else:
            # non-match, try to continue off
            while j > 0:
                j = prefix_array[j-1]
                if text[i] == pattern[j]:
                    # Managed to recover some preffix and continue matching!
                    j += 1
                    break

    if j == len(pattern):
        # Found a match!
        return i - len(pattern)

substring_start_index = find_match(text, pattern, prefix_array)


import sys
sys.path.append('../')

import os
import shutil
import numpy as np
import matplotlib.pyplot as plt

from Parse_instance import parserInstance
from Parse_instance import dataFormat
from Parse_instance import readOutput
from Parse_instance import displaySolution

instanceName = 'captANOR225_9_20'
#instanceName = 'captGRID100_10_10'
#instanceName = 'captANOR900_15_20'
#instanceName = 'captANOR1500_15_100'
instanceDir = '../Instances/'
instancePath = instanceDir + instanceName + '.dat'

# algo = 'branch_and_bound_OPL' or 'cutting_planes'
algo = 'cutting_planes'

if algo == 'branch_and_bound_OPL':
    optimDir = '../OPL_flow/'
    oplModel = 'february_flow_linear'
    oplModelPath = optimDir + oplModel + '.mod'
elif algo == 'cutting_planes':
    optimDir = '../cutting_planes/bin/'
    cppModel = 'cutting_planes'
    cppPath = optimDir + cppModel
modelType = 'full'

Rcapt = 1
Rcom = 2

# parse data
Acapt, Acom, NeighCapt, NeighCom = parserInstance.parseData(
    instancePath, Rcapt, Rcom)

# upper bound
M = 100

# build a file instance
oplInstanceFile = dataFormat.writeData(
    instanceName, NeighCapt, NeighCom, M, \
    modelType=modelType, dataDir=optimDir)

if algo == 'branch_and_bound_OPL':
    # run OPL for optim
    os.system('oplrun.exe {} {}'.format(oplModelPath, oplInstanceFile))
elif algo == 'cutting_planes':
    # run C++ executable
    os.system('{} -instancePath {}'.format(cppPath, oplInstanceFile))

# delete file instance
os.remove(oplInstanceFile)

if algo == 'branch_and_bound_OPL':
    # move output file
    shutil.move(oplDir+'output.dat', 'output.dat')

# read output
output = readOutput.OutputFile(algo)
solution = np.array([1] + output.select)
if output.isOpt():
    if algo == 'branch_and_bound_OPL':
        score = output.bestInteger
        displaySolution.display(instancePath, Rcapt, Rcom, solution, score)
        plt.show()
    elif algo == 'cutting_planes':
        score = output.infBound
        displaySolution.display(instancePath, Rcapt, Rcom, solution, score)
        plt.savefig('solution.png')
else:
    print('No integer solution found in the given time')


from src.main import count_islands
import pytest

test_cases = [
    ("tests/valid_inputs/input.txt", 2),
    ("tests/valid_inputs/6_one_column.txt", 6),
    ("tests/valid_inputs/7_one_row.txt", 7),
    ("tests/valid_inputs/emptyfile.txt", 0),
    ("tests/valid_inputs/1_big_island_small_pond.txt", 1),
    ("tests/valid_inputs/4_corners.txt", 4),
    ("tests/valid_inputs/frame.txt", 1),
    ("tests/valid_inputs/one.txt", 1),
    ("tests/valid_inputs/zero.txt", 0),
    ("tests/valid_inputs/10_adjacent_corners.txt", 10),
]

@pytest.mark.parametrize("sample, expected", test_cases)
def test_count_islands(sample, expected):
    assert count_islands(sample) == expected

err_test = [
    ("tests/test_err_inputs/abcd.txt", FileNotFoundError),
    ("tests/test_err_inputs/other_chars.txt", ValueError),
    ("tests/test_err_inputs/extra_whitespaces.txt", ValueError),
    ("tests/test_err_inputs/not_an_array.txt", ValueError),
]

@pytest.mark.parametrize("sample, expected", err_test)
def test_file_not_found(sample, expected):
    with pytest.raises(expected):
        count_islands(sample)

longrun = pytest.mark.skipif("not config.getoption('longrun')")
longrun_test = [("tests/longrun_inputs/10000x10000_big_file.txt", 1)]

@longrun
@pytest.mark.parametrize("sample, expected", longrun_test)
def test_longrun(sample, expected):
    assert count_islands(sample) == expected


import pygame, sys

def tela_inicial(fundo, logo, start):

    pygame.init()

    #resolução da tela
    resolucaox = 420
    resolucaoy =720

    tela = pygame.display.set_mod (resolucaox,resolucaoy)
    pygame.display.set_caption("teste mouse")

    #Fundo
    imagemFundo = pygame.image.load("Sprites/Fundo.png")
    imagemFundo = pygame.transform.scale(imagemFundo, (resolucaox, resolucaoy)) #Ajusta a imagem de fundo para o tamanho da tela

    #Imagens
    fundoMenu = "Sprites/Menu/fundo_menu.png"
    startMenu = "Sprites/Menu/start_menu.png"
    logoMenu = "Sprites/Menu/logo_menu.png"

    imagemFundo = pygame.image.load(fundo)
    fundoRect = imagemFundo.get_rect()
    imagemLogo = pygame.image.load(logo)
    rectLogo = imagemLogo.get_rect()
    imagemStart = pygame.image.load(start)
    rectStart = imagemStart.get_rect()

    while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RETURN:
                        return
                    if event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        sys.exit()

    tela.fill((0, 0, 0))
    tela.blit(imagemFundo, (0, 0))
    tela.blit(imagemLogo, (fundoRect.centerx - rectLogo.centerx, fundoRect.centery - rectLogo.bottom * 1.3))
    tela.blit(imagemStart, (fundoRect.centerx - rectStart.centerx, fundoRect.bottom - rectLogo.bottom * 0.87))

    pygame.display.flip()


"""
You are given an array of intervals - that is, an array of tuples (start, end).
The array may not be sorted, and could contain overlapping intervals.
Return another array where the overlapping intervals are merged.

For example:
[(1, 3), (5, 8), (4, 10), (20, 25)]

This input should return [(1, 3), (4, 10), (20, 25)] since (5, 8) and (4, 10) can be merged into (4, 10).
"""

from operator import itemgetter

def merge(intervals):  # O((N + 1) log(N))
    intervals = sorted(intervals, key=itemgetter(0))
    ans = []
    tmp = None
    for i in intervals:
        if tmp is None:
            tmp = i
        else:
            if tmp[1] < i[0]:
                ans.append(tmp)
                tmp = i
            else:
                tmp = (tmp[0], max(tmp[1], i[1]))
    if tmp is not None:
        ans.append(tmp)
    return ans

if __name__ == "__main__":
    print(merge([(1, 3), (5, 8), (4, 10), (20, 25)]))
    # [(1, 3), (4, 10), (20, 25)]


import nltk, random

word = ""
word_len = 0
word_string = ""
letters_found = 0
used_list = []
hangman = ""

def print_info(wrongs):
    print("\n")
    global hangman
    print(hangman)
    print(word_string)
    print("Letters used: " + str(used_list).replace("[","").replace("]","").replace("'",""))

def change_hangman(wrongs):
    global hangman
    if wrongs == 1:
        hangman = hangman[:42]+"0"+hangman[43:]
    elif wrongs == 2:
        hangman = hangman[:52]+"|"+hangman[53:]
        hangman = hangman[:62]+"|"+hangman[63:]
    elif wrongs == 3:
        hangman = hangman[:51]+"\\"+hangman[52:]
    elif wrongs == 4:
        hangman = hangman[:53]+"/\n"+hangman[54:]
    elif wrongs == 5:
        hangman = hangman[:72]+"/"+hangman[73:]
    elif wrongs == 6:
        hangman = hangman[:74]+"\ \n"+hangman[75:]

def set_game():
    ran_number = round(random.uniform(0, (len(words_list) -1)))
    global word
    word = words_list[ran_number]
    global word_len
    word_len = len(word)
    global word_string
    word_string = ""
    for letter in word:
        word_string += "_"
    global letters_found
    letters_found = 0
    global used_list
    used_list = []
    global hangman
    hangman = "  ------   \n |      | \n |      | \n |       \n |       \n |       \n |       \n |       \n/ \\"

def run_game():
    wrongs = 0
    global word_string
    global letters_found
    global word_len
    while (wrongs != 6):
        letter = input("Enter a letter")
        if (len(letter) != 1) or (letter.isalnum() != True) or (letter.isnumeric() == True):
            print("Please enter a valid letter.")
            print_info(wrongs)
            continue
        found = False
        i = 0
        if letter in used_list:
            print("You already used this letter!")
            print_info(wrongs)
            continue
        else:
            used_list.append(letter)
        while i < word_len:
            if word[i] == letter:
                found = True
                word_string = word_string[:i]+letter+word_string[i+1:]
                letters_found += 1
            i += 1
        if found == True:
            print("The letter '" + letter + "' is in the word.")
            print_info(wrongs)
            if letters_found == word_len:
                print("Congratulations! You win!")
                end_game()
        else:
            print("The letter '" + letter + "' is not found in the word.")
            wrongs += 1
            change_hangman(wrongs)
            print_info(wrongs)
    if wrongs == 6:
        print("Game over!")
        end_game()

def end_game():
    answer = False
    while answer == False:
        inp = input("Do you want to play again? Y/N")
        if inp == "Y":
            set_game()
            run_game()
        elif inp == "N":
            exit()
        else:
            print("Please answer with Y (Yes) or N (No)")

words_listf = open("Words.txt", encoding="utf-8")
words_list = words_listf.read()
words_listf.close()
words_list = nltk.word_tokenize(words_list)

set_game()
run_game()


import logging
from math import log10
from decimal import *

import numpy as np
import laygo2.object
import laygo2.util.transform as tf

__author__ = ""
__maintainer__ = ""
__status__ = "Prototype"

def _py2magic_number(value, scale=1):
    fmt_str = "%." + "%d" % (-1 * log10(scale) + 1) + "f "  # for truncations
    return fmt_str % (value * scale)

def _py2magic_list(pylist, scale=1):
    """Convert a python list object to a magic(tcl) list."""
    list_str = "{ "
    for item in pylist:
        if isinstance(item, list):  # nested list
            list_str += _py2magic_list(item, scale=scale) + " "
        elif isinstance(item, np.ndarray):  # nested list
            list_str += _py2magic_list(item, scale=scale) + " "
        elif isinstance(item, str):
            list_str += "\"" + str(item) + "\" "
        elif isinstance(item, int) or isinstance(item, np.integer):
            # fmt_str = "%."+"%d" % (-1*log10(scale)+1)+"f "  # for truncations
            # list_str += fmt_str%(item*scale) + " "
            list_str += _py2magic_number(item, scale=scale) + " "
    list_str += "}"
    return list_str

def _translate_obj(libpath, objname, obj, scale=1, master=None, offset=np.array([0, 0])):
    """
    Convert an object to corresponding scale commands.
    offset : np.array([int, int])
        Offsets to obj.xy
    """
    global pin_info
    if master is None:
        mxy = np.array([0, 0])
        mtf = 'R0'
    else: # if the translated object has a master (e.g. VirtualInstance)
        mxy = master.xy
        mtf = master.transform
    if obj.__class__ == laygo2.object.Rect:
    #    color = obj.color # coloring func. added
        # Invoke _laygo2_generate_rect( cv layer bbox ) in {header_filename}
        _xy = np.sort(obj.xy, axis=0)  # make sure obj.xy is sorted
        _xy = mxy + np.dot(_xy + np.array([[-obj.hextension, -obj.vextension], [obj.hextension, obj.vextension]]),
                           tf.Mt(mtf).T)
        #_xy = mxy + np.dot(obj.xy + np.array([[-obj.hextension, -obj.vextension], [obj.hextension, obj.vextension]]),
        #                   tf.Mt(mtf).T)
    #    return "_laygo2_generate_rect(cv, %s, %s, \"%s\") ; # for the Rect object %s \n" \
    #           % (_py2magic_list(obj.layer), _py2magic_list(_xy, scale=scale), objname) # coloring func. added
        return "_laygo2_generate_rect %s %s ; # for the Rect object %s \n" \
               % (obj.layer[0], _py2magic_list(_xy, scale=scale), objname) # coloring func. added
    elif obj.__class__ == laygo2.object.Path:
        # TODO: implement path export function.
        pass
    elif obj.__class__ == laygo2.object.Pin:
        if obj.elements is None:
            _objelem = [obj]
        else:
            _objelem = obj.elements
        for idx, _obj in np.ndenumerate(_objelem):
            # Invoke _laygo2_generate_pin(cv, name, layer, bbox) in {header_filename}
            _xy = mxy + np.dot(_obj.xy, tf.Mt(mtf).T)
            # return "_laygo2_generate_pin(cv, \"%s\", %s, %s ) ; # for the Pin object %s \n" \
            #        % (_obj.netname, _py2magic_list(_obj.layer), _py2magic_list(_xy, scale=scale),
            #           objname)
            pin_info.append([_obj.netname, obj.layer[0], _py2magic_list(_xy, scale=scale), objname])
            return ''
    elif obj.__class__ == laygo2.object.Text:
        # TODO: implement text export function.
        pass
    elif obj.__class__ == laygo2.object.Instance:
        # Invoke _laygo2_generate_instance( cv name libname cellname viewname loc orient num_rows num_cols
        # sp_rows sp_cols params params_order )
        _xy = mxy + np.dot(obj.xy, tf.Mt(mtf).T)
        if master is None:
            transform = obj.transform
        else: # if the translated object has a master (e.g. VirtualInstance)
            transform = tf.combine(obj.transform, master.transform)
        if obj.shape is None:
            num_rows = 1
            num_cols = 1
            sp_rows = 0
            sp_cols = 0
        else:
            num_rows = obj.shape[1]
            num_cols = obj.shape[0]
            sp_rows = _py2magic_number(obj.pitch[1], scale=scale)
            sp_cols = _py2magic_number(obj.pitch[0], scale=scale)
# Problem: if there is no cell at '/WORK/hjpark/laygo2_workspace_sky130/magic_layout' but exist at search path, this function dosen't work
# Solution 1: change  '/WORK/hjpark/laygo2_workspace_sky130/magic_layout' -> libpath (from layout generating script not here)
# Solution 2: just use search path generate_instance function don't care where the libpath is
# solution 1: has serious problem -> microtemplate_dense lib has to be inside of libpath
# current state solution 2
        if obj.libname.find("_microtemplates_dense") != -1:
            cellfile_name = obj.cellname
        else:
            cellfile_name = obj.libname + '_' + obj.cellname
        return "_laygo2_generate_instance %s %s/%s %s %s %s %d %d %s %s " \
               "; # for the Instance object %s \n" \
               % (objname, libpath, obj.libname, cellfile_name, _py2magic_list(_xy, scale=scale), transform,
                  num_rows, num_cols, sp_rows, sp_cols, objname) # /WORK/magc_layout -> temp libpath
    elif obj.__class__ == laygo2.object.VirtualInstance:
        cmd = ""
        if obj.shape is None:
            for elem_name, elem in obj.native_elements.items():
                if not elem.__class__ == laygo2.object.Pin:
                    if obj.name == None:
                        obj.name='NoName'
                    else:
                        pass
                    cmd += _translate_obj(libpath, obj.name + '_' + elem_name, elem, scale=scale, master=obj)
        else:  # arrayed VirtualInstance
            for i, j in np.ndindex(tuple(obj.shape.tolist())):  # iterate over obj.shape
                for elem_name, elem in obj.native_elements.items():
                    if not elem.__class__ == laygo2.object.Pin:
                        cmd += _translate_obj(libpath, obj.name + '_' + elem_name + str(i) + '_' + str(j),
                                              elem, scale=scale, master=obj[i, j])
        return cmd
    else:
        return None

    return ""

def export(db, filename=None, cellname=None, libpath='./magic_layout', scale=1,
           reset_library=False, tech_library=None, gds_filename=None):
    """
    Export a laygo2.object.database.Library object to magic's tcl code.

    Parameters
    ----------
    db: laygo2.database.Library
        The library database to be exported.
    filename: str, optional
        If specified, the generated magic(tcl) script is stored in filename.
    cellname: str or List[str]
        The name(s) of cell(s) to be exported.
    libpath: str
        The path where the generated magic layout is stored.
    scale: float
        The scaling factor between laygo2's integer coordinats actual physical coordinates.
    reset_library: bool, optional
        If True, the library to export the cells is reset.
    tech_library: str, optional
        The name of technology library to be attached to the resetted library.
    gds_filename: str, optional
        If specified, export a gds file with the filename provided.

    Example
    -------
    >>> import laygo2
    >>> from laygo2.object.database import Design
    >>> from laygo2.object.physical import Rect, Pin, Instance, Text
    >>> # Create a design.
    >>> dsn = Design(name="mycell", libname="genlib")
    >>> # Create layout objects.
    >>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
    >>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
    >>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
    >>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
    >>> # Add the layout objects to the design object.
    >>> dsn.append(r0)
    >>> dsn.append(p0)
    >>> dsn.append(i0)
    >>> dsn.append(t0)
    >>> #
    >>> # Export to magic tcl.
    >>> lib = laygo2.object.database.Library(name="mylib")
    >>> lib.append(dsn)
    >>> scr = laygo2.interface.magic.export(lib, filename="myscript.tcl")
    >>> print(scr)
    (definitions of laygo2 tcl functions)
    # exporting mylib__mycell
    _laygo2_create_layout ./magic_layout/mylib mylib_mycell None
    _laygo2_generate_rect M1 { { 0.0  0.0  } { 100.0  100.0  } } ; # for the Rect object NoName_0
    _laygo2_generate_pin P M1 { { 0.0  0.0  } { 50.0  50.0  } }  ; # for the Pin object P
    _laygo2_generate_instance I0 ./magic_layout/tlib tlib_t0 { 0.0  0.0  } R0 1 1 0 0 ; # for the Instance object I0
    save

    Returns
    -------
    str: the string object contains corresponding tcl scripts.
    """

    # parse header functions.
    cmd = "# laygo2 layout export magic(tcl) script.\n\n"
    import os
    header_filename = os.path.abspath(laygo2.interface.__file__)[:-11] + 'magic_export.tcl'
    with open(header_filename, 'r') as f:
        cmd += f.read()
        cmd += '\n'

    cellname = db.keys() if cellname is None else cellname  # export all cells if cellname is not given.
    cellname = [cellname] if isinstance(cellname, str) else cellname  # convert to a list for iteration.
    # if reset_library: (not implemented)
    global pin_info
    pin_info = list()
    for cn in cellname:
        cmd += "\n# exporting %s__%s\n" % (db.name, cn)  # open the design.
        logging.debug('Export_to_MAGIC: Cellname:' + cn)
        cmd += "_laygo2_create_layout %s %s %s\n" % ((libpath+'/'+db.name), (db.name+'_'+cn), tech_library)  # open the design, /WORK/magc_layout -> temp libpath
        # export objects
        for objname, obj in db[cn].items():
            cmd += _translate_obj(libpath, objname, obj, scale=scale)
        # attach zeros to pin index for sorting by alphabet (ex: pin<1> -> pin<000000001>)
        # set length of every pin index to 10
        for info in pin_info:
            if '<' in info[0] and '>' in info[0]:
                _idx = info[0].find('<')
                _len = info[0].find('>') - (_idx + 1)
                if _len <= 0:
                    print("wrong pin format: "+info[0])
                    exit(-1)
                _prefix = '0'*(10-_len)
                info[0] = info[0][:_idx+1] +_prefix + info[0][_idx+1:]
                info.append(10-_len)

        pin_info.sort(key=lambda info: info[0])
        # detach zeros from pin index
        for info in pin_info:
            if len(info) == 5:
                _idx = info[0].find('<')
                info[0] = info[0][:_idx+1] + info[0][_idx+1+info[4]:]
        # translate pin info to magic functon
        for port_num, info in enumerate(pin_info):
            cmd += "_laygo2_generate_pin %s %s %s %d ; # for the Pin object %s \n" \
                    % (info[0], info[1], info[2], port_num+1, info[3])
        cmd += "save\n"
        pin_info = []
    # optional gds export
    if gds_filename is not None:
        cmd += "gds write "+gds_filename+"\n"

    if filename is not None:  # export to a file.
        with open(filename, "w") as f:
            f.write(cmd)

    return cmd