import gtk
import gobject
import conventions
from quickly.widgets.grid_column import StringColumn
from grid_column import CheckColumn

class DictionaryGrid(gtk.TreeView):
    __gtype_name__ = "DictionaryGrid"

    def __init__(self, dictionaries=None, editable = False, keys=None, type_hints=None):
        """
        Creates a new DictionaryGrid
        arguments:

        dictionaries - a list of dictionaries to initialize in the
        grid.

        keys - a list of strings specifying keys to use in
        the columns of the DictionaryGrid.

        The types for the columns will be inferred by the key based on
        some conventions. the key "id" is assumed to be an integer, as
        is any key ending in " count". A key ending in "?" is assumed
        to be a Boolean displayed with a checkbox. The key "price" is
        assumed to be currency, as is any key ending in "count". There
        may be others. Defaults can be overridden using type-hints. All
        other keys will be assumed to be strings.

        type-hints - a dictionary containing keys specificed for the
        TreeView and GridColumns. Used to override types inferred
        by convention, or for changing the type of a column from
        the default of a string to something else.

        """

        gtk.TreeView.__init__(self)
        self.list_store = None
        self.unfiltered_store = None
        self._keys = keys
        self._editable = editable
        if dictionaries is None:
            self._dictionaries = []
        else:
            self._dictionaries = dictionaries
        if type_hints is None:
            self._type_hints = {}
        else:
            self._type_hints = type_hints
        self.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self._refresh_treeview()

        #signal handlers to track selection in the treeview
        #utlmiately these all emit the "selection_changed signal
        self.connect("cursor_changed", self.__selection_changed)
        self.connect("move-cursor", self.__cursor_moved)
        self.connect("select-all", self.__selection_all)
        self.connect("select-cursor-row", self.__selection_changed)
        self.connect("unselect-all", self.__selection_none)
        self.connect("toggle-cursor-row", self.__selection_changed)

    def __cursor_moved(self, grid, step, count, data=None):
        self.__selection_changed(self)

    def __selection_all(self, treeview, data=None):
        self.emit("selection-changed", self.rows)

    def __selection_none(self, treeview, data=None):
        self.emit("selection-changed", [])

    def __selection_changed(self, treeiew, data=None):
        self.emit("selection-changed", self.selected_rows)

    def __edited_toggled(self, cell, path, col):
        iter = self.get_model().get_iter(path)
        key = col.key
        active = not cell.get_active()
        self.__edited(cell, path, active, col)

    def __edited(self, cell, path, new_val, col):
        """ _edited - internal signal handler.
        Updates the database if a cell in the Treeview
        has been edited.

        """
        iter = self.get_model().get_iter(path)
        row_dict = self.get_model().get_value(iter,len(self.keys))
        key = col.key
        dictionary = self.get_model().get_value(iter,len(self.keys))
        self.emit("cell-edited",cell, path, key, new_val, row_dict)

    @property
    def keys(self):
        """ keys - A list of strings to act as keys for the
        backing dictionaries and the default titles for the columns.

        Setting this property will cause the widget to reload.

        """

        return self._keys

    @keys.setter
    def keys(self, keys):
        self._keys = keys
        self._refresh_treeview()

    @property
    def editable(self):
        """editable - bool value, True to make editable

        Setting this property will cause the widget to reload.

        """
        return self._editable

    @editable.setter
    def editable(self, editable):
        self._editable = editable

        #refresh the treeview if possible
        self._refresh_treeview()

    @property
    def columns(self):
        """ columns - A dictionary of the GridColumns indexed by the
        keys for that column. This allows access to columns by the key,
        for example to change the title of a specific column:
        grid.columns["complete?"].set_title(_("Completed"))

        This property is read only.

        """

        cols = {}
        for c in self.get_columns():
            cols[c.key] = c
        return cols

    def set_column_titles(self, titles):
        """set_column_titles - sets the specified titles for the GridColumns
        in the DictionaryGrid. Use a dictionary of strings indexed by keys.
        For example:
        titles = {"complete?":_("Complete"),"id":_("ID")}
        grid.set_column_titles(titles)

        """

        for t in titles:
            if t in self.columns:
                self.columns[t].set_title(titles[t])

    def get_dictionaries_copy(self):
        """get_dictionaries_copy -returns a copy of the dictionaries in
        the dictionary grid.

        """
        return self._dictionaries[:]

    def _infer_keys_from_dictionaries(self):
        """_infer_keys_from_dictionaries: an internal function to
        set _keys suitable for column titles from a set of dictionaries.

        _infer_keys_from_dictionaries is not typically called directly,
        but may be useful to override in subclasses.

        """
        key_collector = []
        for r in self._dictionaries:
            for k in r.keys():
                if k not in key_collector and not k.startswith("__"):
                    key_collector.append(k)

        self._keys = key_collector

    def _refresh_treeview(self):
        """
        _refresh_treeview: internal function to handle rebuilding
        the gtk.TreeView along with columns and cell renderers..

        _refresh_treeview is not typically called directly,
        but may be useful to override in subclasses.

        """

        #if keys are already set, set up titles and columns
        if self.keys is not None:
            self.__reset_model()

        #if keys aren't set, infer them from the collection
        if len(self._dictionaries) > 0 and self.keys is None:
            self._infer_keys_from_dictionaries()
            self.__reset_model()

        for dictionary in self._dictionaries:
            #lists have to match the list_store columns in length
            #so we have to make rows as long as the headerings
            #note that the last value is reserved for extra data
            self.append_row(dictionary)

        #apply the model to the Treeview if possible
        if self.list_store != None:
            self.unfiltered_store = self.list_store
            self.set_model(self.list_store)

    def append_row(self, dictionary):
        """append_row: add a row to the TreeView. If keys are already set up
        only the the keys in the dictionary matching the keys used
        for columns will be used. If no keys are set up, and this is the
        first row, keys will be inferred from the dictionary keys.

        arguments:
        dictionary - a dictionary to the TreeView.

        """

        new_row = []

        for i, k in enumerate(self.keys):
                if k in dictionary:
                    display_val = self.__columns_map[k].display_val(dictionary[k])
                    real_val = self.__columns_map[k].real_val(dictionary[k])
                    #TODO: store a "real_val" instead of display val
                    #that was "converted_val"
                    dictionary[k] = real_val
                else:
                    display_val = self.__columns_map[k].default_display_val()
                new_row.append(display_val)
        new_row.append(dictionary)
        self.list_store.append(new_row)

    @property
    def rows(self):
        """ rows - returns a list of dictionaries
        for each row in the grid.

        This property is read only.

        """
        model = self.get_model()
        rows = [] #list of rows to return
        model.foreach(self.__append_dict, rows)
        return rows

    def __append_dict(self, model, path, iter, rows):
        """ __append_dict: internal function, do not call directly"""

        row = model.get_value(iter,len(self.keys))
        rows.append(row)

    @property
    def selected_rows(self):
        """ selected_rows - returns a list of dictionaries
        for each row selected.

        This property is read only.

        """

        #get the selected rows in the ListStore
        selection = self.get_selection()
        model, model_rows = selection.get_selected_rows()

        rows = [] #list of rows to return

        for mr in model_rows:
            row = {} #a row to be added to the list of rows
            iter = model.get_iter(mr)

            row = model.get_value(iter,len(self.keys))
            rows.append(row)
        return rows

    def remove_selected_rows(self):
        """
        remove_selected_rows: removes the rows currently selected
        in the TreeView UI from the TreeView as well as the backing
        gtk.ListStore.

        """

        #get the selected rows, and return if nothing is selected
        model, rows = self.get_selection().get_selected_rows()

        if len(rows) == 0:
            return

        #store the last selected row to reselect after removal
        next_to_select = rows[-1][0] + 1 - len(rows)

        #loop through and remove

        if type(model) is not gtk.ListStore:
            iters = [model.get_model().get_iter(path) for path in rows]
            store_iters = []

            for i in iters:
                store_iters.append(model.get_model().convert_iter_to_child_iter(i))

            for store_iter in store_iters:
                self.unfiltered_store.remove(store_iter)

        else:
            iters = [model.get_iter(path) for path in rows]

            for i in iters:
                model.remove(i)

        #select a row for the user, nicer that way
        rows_remaining = len(self.get_model())

        #don't try to select anything if there are no rows left
        if rows_remaining < 1:
            return

        #select the next row down, unless it's out of range
        #in which case just select the last row
        if next_to_select < rows_remaining:
            self.get_selection().select_path(next_to_select)
        else:
            self.get_selection().select_path(rows_remaining - 1)

    def __reset_model(self):
        """ __reset_model - internal funciton, do not call directly.
        This function is typically called when the TreeView needs
        to be rebuilt. Creates new columns.

        """

        #remove the current columns from the TreeView
        cols = self.get_columns()
        for c in cols:
            self.remove_column(c)

        #reinitialize the column variables
        col_count = len(self.keys) + 1
        col_types = []
        self.__columns_map = {}

        #create a column for each key
        for i, k in enumerate(self.keys):
            #use any supllied columns
            if k in self._type_hints:
                column = self._type_hints[k](k,i,len(self.keys))
            else:
                #no column supplied, use conventions to get a column
                column = conventions.get_column(k,i,len(self.keys), self.editable)

            #add the created column, and remember it's key
            self.append_column(column)
            self.__columns_map[k] = column

            #store the into for creating the list store
            col_types.append(column.column_type)

        #create the liststore with the designated types
        #the last column is always for storing the backing dict
        col_types.append(gobject.TYPE_PYOBJECT)
        self.list_store = gtk.ListStore(*col_types)

        for c in self.get_columns():
            self.__last_sorted_col = None
            c.list_store = self.list_store

            #TODO: store and delete these, this is a leak
            c.connect("clicked",self.__remove_sort_icon)

            #connect to the edit events to rip it a
            if type(c) == CheckColumn:
               c.renderer.connect("toggled",self.__edited_toggled, c)
            else:
                c.renderer.connect("edited",self.__edited, c)

    def __remove_sort_icon(self, column):
        """__remove_sort_icon: internal function used in handling
        display of sort buttons. Do not call this function directly.

       """

        if self.__last_sorted_col is not None:
            if self.__last_sorted_col is not column:
                self.__last_sorted_col.set_sort_indicator(False)
        self.__last_sorted_col = column

    __gsignals__ = {'cell-edited' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
        (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)),

            'selection-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
            (gobject.TYPE_PYOBJECT,))
        }

def __show_selected(widget, selected_rows, data=None):
    """handles displaying text for test app"""

    tv.get_buffer().set_text(str(selected_rows))

def __on_edited(widget, cell, row, key,  new_value, row_dict, tv):
    """handles displaying text for test app"""

    string = "row: " + str(row)
    string += ", key: " + str(key)
    string += ", new value: " + str(new_value)
    string += "\n" + str(row_dict)
    tv.get_buffer().set_text(string)

if __name__ == "__main__":
    """creates a test CouchGrid if called directly"""

    dicts = [{"key?": True, "price":0.00,"tags" : "aaa bbb ccc","_foo":"bar","bing count":20},
                 {"ID": 11, "key?": False, "price":2.00,"tags" : "bbb ccc ddd","_foo":"bar"},
                 {"key?": True, "price":33.00,"tags" : "ccc ddd eee","_foo":"bar","bing count":15},
                 {"ID": 3, "tags" : "ddd eee fff","_foo":"bar"},
                 {"ID": 4, "price":5.00,"_foo":"bar"}]
    #create and show a test window
    win = gtk.Window(gtk.WINDOW_TOPLEVEL)
    win.set_title("DictionaryGrid Test Window")
    win.connect("destroy",gtk.main_quit)
    win.show()

    #create a top level container
    vbox = gtk.VBox(False, False)
    vbox.show()
    win.add(vbox)

    #create a test widget with test database values
    grid = DictionaryGrid(dicts, editable=True)#, ["ID","tags","price","bing count","key?"])

    #allow editing
    #grid.editable = True

    #show the control, add it to the window, and run the main loop
    grid.show()
    vbox.pack_start(grid, False, True)

    #create a test display area
    hbox = gtk.HBox(False, 5)
    hbox.show()
    tv = gtk.TextView()
    tv.show()
    grid.connect("selection-changed",__show_selected, tv)
    grid.connect("cell-edited",__on_edited, tv)

    hbox.pack_start(tv, False, False)
    vbox.pack_end(hbox, False, False)

    #run the test app
    gtk.main()


# -*- coding: utf-8 -*-
# @Time     : 2021/6/8 下午7:42
# @Author   : binger

import os
import zipfile
from flask_os.setting import ROOT_PATH

def build_project_zip(path="project", dst_zip_file=None):
    dst_filename = dst_zip_file or os.path.join(ROOT_PATH, "conf", "project.zip")
    with zipfile.ZipFile(dst_filename, "w", zipfile.ZIP_DEFLATED) as fw:

        for parent, dirnames, filenames in os.walk(path):
            dst_parent = parent.replace(path, "")
            for filename in filenames:
                if filename.startswith("."):
                    continue
                src_file = os.path.join(parent, filename)
                dst_name = os.path.join(dst_parent, filename)
                fw.write(src_file, dst_name)

build_project_zip()


# -*- coding: utf-8 -*-
"""
Item 3: Know the Difference between bytes and str

"""

a = b'h\x65llo'
print(list(a))
print(a)

a ='it is a\u0300 propos'
print(list(a))
print(a)

def to_str(bytes_or_str):
	if isinstance(bytes_or_str, bytes):
		value = bytes_or_str.decode('utf-8')
	else:
		value = bytes_or_str
	return value # Instance of str

print(repr(to_str(b'foo')))
print(repr(to_str('bar')))

def to_bytes(bytes_or_str):
	if isinstance(bytes_or_str,str):
		value = bytes_or_str.encode('utf-8')
	else:
		value = bytes_or_str
	return value # Instance of bytes

print(repr(to_bytes(b'foo')))
print(repr(to_bytes('bar')))

# You can add str and str as well as bytes and bytes.
# You can add str and bytes

# bytes contains sequences of 8-bit values, and str contains
# sequences of unicode patterns.
# If you want to read and write files use 'rb' and 'wb' respectively.

print(b'one' + b'two')
print('one' + 'two')

assert b'red' > b'blue'
assert 'red' > 'blue'

try:
	assert 'red' > b'blue'
except TypeError:
	print('Oops!  > not supported between bytes and str')

print(b'foo' == 'foo')

with open('data.bin', 'wb') as f:
	f.write(b'\xf1\xf2\xf3\xf4\xf5')

with open('data.bin', 'rb') as f:
	data = f.read()

assert data == b'\xf1\xf2\xf3\xf4\xf5'

with open('data.bin', 'r', encoding='cp1252') as f:
	data = f.read()

print(data)


import json
import string
from threading import Lock

import requests
import time
from zeroconf import ServiceBrowser, ServiceStateChange
from zeroconf import Zeroconf

IDENTIFIER = "restsysmon"
HA_URL = "http://192.168.1.8:8123"
HA_TOKEN = "..."

class HASensorPusher:
    def __init__(self, identifier=IDENTIFIER):
        self.zero = None
        self.browser = None
        self.nodes = {}
        self.running = False
        self.identifier = identifier.encode("utf-8")
        self.ttl = 10  # seconds between rounds of sensor readings
        self.sleep_time = 0.3  # seconds between individual sensor readings
        self.lock = Lock()

    @staticmethod
    def ha_binary_sensor_update(device_id, state="on", attrs=None):
        device_id = device_id.replace(" ", "_")
        for s in string.punctuation:
            device_id = device_id.replace(s, "_")
        attrs = attrs or {"friendly_name": device_id,
                          "state_color": True,
                          "device_class": "presence"}

        print("updating binary sensor - ", device_id)
        try:
            response = requests.post(
                f"{HA_URL}/api/states/binary_sensor.{IDENTIFIER}_{device_id}",
                headers={
                    "Authorization": f"Bearer {HA_TOKEN}",
                    "content-type": "application/json",
                },
                data=json.dumps({"state": state, "attributes": attrs}),
            )
            print(response.text)
        except:
            print("failed to push data to HA")

    @staticmethod
    def ha_sensor_update(device_id, state="on", attrs=None):
        attrs = attrs or {"friendly_name": device_id,
                          "state_color": True}
        print("updating sensor - ", device_id)
        try:
            response = requests.post(
                f"{HA_URL}/api/states/sensor.{IDENTIFIER}_{device_id}",
                headers={
                    "Authorization": f"Bearer {HA_TOKEN}",
                    "content-type": "application/json",
                },
                data=json.dumps({"state": state, "attributes": attrs}),
            )
            print(response.text)
        except:
            print("failed to push data to HA")

    def on_new_node(self, node):
        device_id = node["name"]
        print("found", node)
        self.on_node_update(node)
        self.get_readings()
        self.get_info(device_id)  # one time sensor readings

    def on_lost_node(self, node):
        print("lost", node)
        self.on_node_update(node)

    def on_node_update(self, node):
        device_id = node["name"]
        self.nodes[device_id] = node
        self.ha_binary_sensor_update(device_id, state=node["state"],
                                     attrs={"friendly_name": node["name"],
                                            "state_color": True,
                                            "device_class": "presence"})

    def on_service_state_change(self, zeroconf, service_type, name,
                                state_change):
        info = zeroconf.get_service_info(service_type, name)
        if info and info.properties:
            for key, value in info.properties.items():
                if key == b"type" and value == self.identifier:
                    host = info._properties[b"host"].decode("utf-8")
                    port = info._properties[b"port"].decode("utf-8")
                    name = info._properties[b"name"].decode("utf-8")
                    node = {"host": host, "port": port, "name": name}
                    node["last_seen"] = time.time()
                    if state_change is ServiceStateChange.Added:
                        node["state"] = "on"
                        self.on_new_node(node)
                    elif ServiceStateChange.Removed:
                        node["state"] = "off"
                        self.on_lost_node(node)
                    else:
                        node["state"] = "on"
                        self.on_node_update(node)

    def start(self):
        self.zero = Zeroconf()
        self.browser = ServiceBrowser(self.zero, "_http._tcp.local.",
                                      handlers=[self.on_service_state_change])
        self.running = True
        while self.running:
            try:
                self.get_readings()
                time.sleep(self.ttl)
            except KeyboardInterrupt:
                break
        self.stop()

    def stop(self):
        if self.zero:
            self.zero.close()
        self.zero = None
        self.browser = None
        self.running = False

    def get_info(self, device_id):
        data = self.nodes[device_id]
        url = f"{data['host']}:{data['port']}"
        readings = {
            "os": f"{url}/os_name",
            "boot_time": f"{url}/boot_time",
            "system": f"{url}/system",
            "release": f"{url}/release",
            "machine": f"{url}/machine",
            "architecture": f"{url}/architecture",
            "cpu_count": f"{url}/cpu_count",
            "fans": f"{url}/fans",
            "network_interfaces": f"{url}/network_interfaces",
            "external_ip": f"{url}/external_ip",
            "pulseaudio_version": f"{url}/pulseaudio/version",
            "is_systemd": f"{url}/is_systemd",
            "is_dbus": f"{url}/is_dbus",
            "cpu_freq_max": f"{url}/cpu_freq_max",
            "cpu_freq_min": f"{url}/cpu_freq_min",
            "disk_total": f"{url}/disk_total",
            "pulseaudio_hostname": f"{url}/pulseaudio/hostname",
            "memory_total": f"{url}/memory_total"
        }
        for sensor_name, url in readings.items():
            self.read_sensor(device_id, sensor_name, url)
            time.sleep(self.sleep_time)

    def read_sensor(self, device_id, sensor_name, url):
        sensor_id = f"{device_id}_{sensor_name}"
        try:
            res = requests.get("http://" + url)
            try:
                res = res.json()
            except:
                res = res.text
            try:  # numeric
                if "/is_" in url:
                    res = str(res) == "1"
                    self.ha_binary_sensor_update(sensor_id, state="on" if res else "off",
                                                 attrs={"friendly_name": sensor_name,
                                                        "state_color": True,
                                                        "device_class": "presence"})
                elif url.endswith("_count"):
                    res = int(res)
                    a = {"friendly_name": sensor_name,
                         "state_color": True}
                    self.ha_sensor_update(sensor_id, state=str(res), attrs=a)
                else:
                    res = float(res)  # numeric reading
                    a = {"friendly_name": sensor_name,
                         "state_color": True}
                    if "temperature" in url:
                        a["unit_of_measurement"] = "°C"
                    self.ha_sensor_update(sensor_id, state=str(res), attrs=a)

            except Exception as e:
                # text
                if isinstance(res, list):
                    if sensor_id.endswith("pulseaudio_list_cards"):
                        for e in res:
                            sensor_id = f"{device_id}_pulseaudio_card_{e['index']}"
                            f = e.get("card_name") or e.get("name") or sensor_id
                            self.ha_binary_sensor_update(sensor_id, state="on",
                                                         attrs={"friendly_name": f.lower().strip(),
                                                                "state_color": True,
                                                                "device_class": "presence"})
                    elif sensor_id.endswith("pulseaudio_list_sources"):
                        for e in res:
                            sensor_id = f"{device_id}_pulseaudio_source_{e['index']}"
                            self.ha_binary_sensor_update(sensor_id, state="on",
                                                         attrs={"friendly_name": e.get("name") or sensor_id,
                                                                "state_color": True,
                                                                "device_class": "presence"})
                    elif sensor_id.endswith("pulseaudio_list_sinks"):
                        for e in res:
                            sensor_id = f"{device_id}_pulseaudio_sink_{e['index']}"
                            self.ha_binary_sensor_update(sensor_id, state="on",
                                                         attrs={"friendly_name": e.get("name") or sensor_id,
                                                                "state_color": True,
                                                                "device_class": "presence"})
                    elif sensor_id.endswith("pulseaudio_list_input_sinks"):
                        # streams of interest, even if not currently playing will report a status
                        APPS = [
                            "netflix",
                            "spotify"
                        ]
                        for app in APPS:

                            if any(app == _["application"] for _ in res):
                                # app names handled below, we just want streams here
                                # eg, detect netflix in firefox via pulseaudio playback
                                continue

                            if any(app == _.get('media_name', "").lower() for _ in res):
                                # detected application running via pulseaudio playback
                                state = "on"
                                mute_state = "off"  # TODO - check the playback info
                            else:
                                state = mute_state = "off"

                            sensor_id = f"{device_id}_pulseaudio_stream_{app}"
                            self.ha_binary_sensor_update(sensor_id, state=state,
                                                         attrs={"friendly_name": app,
                                                                "state_color": True,
                                                                "device_class": "presence"})
                            sensor_id = f"{device_id}_pulseaudio_stream_{app}_muted"
                            self.ha_binary_sensor_update(sensor_id, state=mute_state,
                                                         attrs={"friendly_name": app + " muted",
                                                                "state_color": True,
                                                                "device_class": "presence"})

                        for e in res:
                            sensor_id = f"{device_id}_pulseaudio_stream_{e['application']}"
                            f = e.get('media_name') or e.get('name') or e.get('application')
                            self.ha_binary_sensor_update(sensor_id, state="on" if e.get("playing") else "off",
                                                         attrs={"friendly_name": f.lower().strip(),
                                                                "state_color": True,
                                                                "device_class": "presence"})

                            sensor_id = f"{device_id}_pulseaudio_stream_{e['application']}_muted"
                            f = e.get('media_name') or e.get('name') or e.get('application')
                            self.ha_binary_sensor_update(sensor_id, state="on" if e.get("mute") else "off",
                                                         attrs={"friendly_name": f.lower().strip() + " muted",
                                                                "state_color": True,
                                                                "device_class": "presence"})

                            sensor_id = f"{device_id}_pulseaudio_stream_{e['application']}_sink"
                            f = e.get('media_name') or e.get('name') or e.get('application')
                            self.ha_sensor_update(sensor_id, state=str(e["sink"]),
                                                  attrs={"friendly_name": f.lower().strip() + " sink",
                                                         "state_color": True,
                                                         "device_class": "presence"})
                    elif sensor_id.endswith("network_interfaces"):
                        for e in res:
                            sensor_id = f"{device_id}_network_if_{e}"
                            self.ha_binary_sensor_update(sensor_id, state="on",
                                                         attrs={"friendly_name": e,
                                                                "state_color": True,
                                                                "device_class": "presence"})
                    else:
                        print("## TODO", sensor_id, res)
                    pass
                elif isinstance(res, dict):
                    # print("## TODO", sensor_id, res)
                    pass
                else:
                    a = {"friendly_name": sensor_name,
                         "state_color": True}
                    self.ha_sensor_update(sensor_id, state=str(res), attrs=a)
        except:
            return False
        return True

    def get_readings(self):
        with self.lock:
            for device_id, data in dict(self.nodes).items():
                alive = False
                if data["state"] == "on":
                    url = f"{data['host']}:{data['port']}"
                    readings = {
                        "swap_usage": f"{url}/swap_usage",
                        "swap_total": f"{url}/swap_total",
                        "disk_usage": f"{url}/disk_usage",
                        "external_ip": f"{url}/external_ip",
                        "is_kdeconnect": f"{url}/is_kdeconnect",
                        "is_pulseaudio": f"{url}/is_pulseaudio",
                        "is_pipewire": f"{url}/is_pipewire",
                        "is_plasma": f"{url}/is_plasma",
                        "is_hivemind": f"{url}/is_hivemind",
                        "is_ovos": f"{url}/is_ovos",
                        "is_spotify": f"{url}/is_spotify",
                        "is_firefox": f"{url}/is_firefox",
                        "is_upmpdcli": f"{url}/is_upmpdcli",
                        "is_minidlna": f"{url}/is_minidlna",
                        "pulseaudio_channel_count": f"{url}/pulseaudio/channel_count",
                        "pulseaudio_default_sink": f"{url}/pulseaudio/default_sink",
                        "pulseaudio_default_source": f"{url}/pulseaudio/default_source",
                        "pulseaudio_list_cards": f"{url}/pulseaudio/list_cards",
                        "pulseaudio_list_sources": f"{url}/pulseaudio/list_sources",
                        "pulseaudio_list_sinks": f"{url}/pulseaudio/list_sinks",
                        "pulseaudio_list_input_sinks": f"{url}/pulseaudio/list_input_sinks",
                        "cpu_usage": f"{url}/cpu_usage",
                        "cpu_freq": f"{url}/cpu_freq",
                        "cpu_temperature": f"{url}/cpu_temperature",
                        "memory_usage": f"{url}/memory_usage",
                        "disk_percent": f"{url}/disk_percent",
                        "battery_percent": f"{url}/battery_percent",
                        "pulseaudio_now_playing": f"{url}/pulseaudio/now_playing",
                        "pulseaudio_is_playing": f"{url}/pulseaudio/is_playing",
                        "pulseaudio_bluez_active": f"{url}/pulseaudio/is_bluez_active",
                        "pulseaudio_bluez_connected": f"{url}/pulseaudio/is_bluez_connected",
                        "brightness": f"{url}/brightness"
                    }
                    for sensor_name, url in readings.items():
                        alive = self.read_sensor(device_id, sensor_name, url) or alive
                        time.sleep(self.sleep_time)

                data["state"] = alive
                self.on_node_update(data)

if __name__ == "__main__":
    ha = HASensorPusher()
    ha.start()
    while True:
        try:
            time.sleep(1)
        except KeyboardInterrupt:
            break
    ha.stop()


#%%
import torch
from torch_geometric.nn import MessagePassing
from torch_geometric.utils import add_self_loops, degree
import torch.nn.functional as F
from torch_geometric.data import Data
from torch.utils.data import random_split
import matplotlib.pyplot as plt
import pickle
import pandas as pd
from scipy.spatial import Delaunay
import numpy as np
from torch_geometric.loader import DataLoader
from tqdm import tqdm
import torch.optim as optim
import math
from tqdm import tqdm
from itertools import combinations

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class EdgeConv(MessagePassing):
    def __init__(self, num_node_features, num_edge_features, out_channels):
        super(EdgeConv, self).__init__(aggr='add')  # "Add" aggregation.
        self.lin = torch.nn.Linear(num_node_features * 2 + num_edge_features, out_channels)

    def forward(self, x, edge_index, edge_attr):
        # x has shape [N, in_channels]
        # edge_index has shape [2, E]
        # edge_attr has shape [E, edge_attr_dim]

        # Add self-loops to the adjacency matrix.
        edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))

        # Add edge attributes for self-loops.
        loop_attr = torch.zeros((x.size(0), edge_attr.size(1)), device=edge_attr.device)
        edge_attr = torch.cat([edge_attr, loop_attr], dim=0)

        return self.propagate(edge_index, size=(x.size(0), x.size(0)), x=x, edge_attr=edge_attr)

    def message(self, x_i, x_j, edge_attr):
        # x_i has shape [E, in_channels]
        # x_j has shape [E, in_channels]
        # edge_attr has shape [E, edge_attr_dim, 1]
        #print(f'x_i shape (in model): {x_i.shape}')
        #print(f'x_j shape (in model): {x_j.shape}')
        #print(f'edge_attr shape (in model): {edge_attr.shape}')
        edge_attr = edge_attr.squeeze(-1)  # Remove the singleton dimension
        edge_input = torch.cat([x_i, x_j, edge_attr], dim=1)  # shape [E, in_channels * 2 + edge_attr_dim]
        return self.lin(edge_input)

class GCN(torch.nn.Module):
    def __init__(self, num_node_features, num_edge_features, num_classes):
        super(GCN, self).__init__()
        self.conv1 = EdgeConv(num_node_features, num_edge_features, 512)
        self.conv2 = EdgeConv(512, num_edge_features, 256)
        self.conv3 = EdgeConv(256, num_edge_features, 128)
        self.conv4 = EdgeConv(128, num_edge_features, 64)
        self.conv5 = EdgeConv(64, num_edge_features, 32)
        self.batch_norm = torch.nn.BatchNorm1d(32)
        self.classifier = torch.nn.Linear(32, num_classes)

    def forward(self, data):
        x, edge_index, edge_attr = data.x, data.edge_index, data.edge_attr

        x = self.conv1(x, edge_index, edge_attr)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)

        x = self.conv2(x, edge_index, edge_attr)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)

        x = self.conv3(x, edge_index, edge_attr)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)

        x = self.conv4(x, edge_index, edge_attr)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)

        x = self.conv5(x, edge_index, edge_attr)
        x = self.batch_norm(x)
        x = F.dropout(x, training=self.training)

        x = self.classifier(x)

        return F.log_softmax(x, dim=1)
#%%
with open('dataset_hist.pkl', 'rb') as f:
    data = pickle.load(f)

point_sets = data['dataframes']
print(len(point_sets))

def edge_features(points, edge):
    # Edge length
    length = np.linalg.norm(points[edge[0]] - points[edge[1]])

    if length == 0:
        print(f"Zero length encountered. Points: {points[edge[0]], points[edge[1]]}")

    # Calculate the edge vector, taking the point with the largest y value minus the other
    if points[edge[0], 1] > points[edge[1], 1]:
        vec = points[edge[0]] - points[edge[1]]
    else:
        vec = points[edge[1]] - points[edge[0]]

    # Cosine of the angle
    cosine = vec[0] / length
    # Sine of the angle
    sine = vec[1] / length

    return np.array([length, cosine, sine])

def calculate_angle(p1, p2, p3):
    """
    Calculates the angle between three points.
    """
    v1 = p1 - p2
    v2 = p3 - p2

    cos_theta = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
    cos_theta = np.clip(cos_theta, -1, 1)  # ensure the value is within [-1, 1]
    return np.arccos(cos_theta)

data_list = []
for idx, df in enumerate(point_sets):
    points = df[['x', 'y']].values
    tri = Delaunay(points)

    edges = set()
    for simplex in tri.simplices:
        for i in range(3):
            edge = tuple(sorted([simplex[i], simplex[(i+1)%3]]))
            edges.add(edge)

    adjacency_matrix = np.zeros((len(points), len(points)))

    num_nodes = len(points)
    print(f"Number of nodes in dataframe {idx}: {num_nodes}")

    edge_index = torch.tensor(list(edges), dtype=torch.long).t().contiguous()

    num_edges = edge_index.shape[1]
    print(f"Number of edges in dataframe {idx}: {num_edges}")

    for edge in edge_index.T:
        #print(f"Edge: {edge}, Edge[0]: {edge[0]}, Edge[1]: {edge[1]}")
        # Since it's an undirected graph, we add 1 for both (i, j) and (j, i)
        adjacency_matrix[edge[0], edge[1]] = 1
        adjacency_matrix[edge[1], edge[0]] = 1

    edge_attr = []
    for edge in edge_index.t().numpy():
        edge_attr.append(edge_features(points, edge))
    edge_attr = np.array(edge_attr)

    edge_attr = torch.tensor(edge_attr, dtype=torch.float)

    degree = np.sum(adjacency_matrix, axis=1)
    df['degree'] = degree

    df['x'] = (df['x'] - df['x'].min()) / (df['x'].max() - df['x'].min())
    df['y'] = (df['y'] - df['y'].min()) / (df['y'].max() - df['y'].min())

    centroid_x = df['x'].mean()
    centroid_y = df['y'].mean()

    df['relative_x'] = df['x'] - centroid_x
    df['relative_y'] = df['y'] - centroid_y

    # Initialize average_neighbor_distance
    df['average_neighbor_distance'] = 0

    # Iterate over edges
    for edge in edge_index.T:
        # Compute distance between nodes
        distance = np.linalg.norm(points[edge[0]] - points[edge[1]])

        # Convert tensor to numpy for indexing
        edge_numpy = edge.numpy()

        # Add the distance to both nodes, we will average it later
        df.loc[edge_numpy[0], 'average_neighbor_distance'] += distance
        df.loc[edge_numpy[1], 'average_neighbor_distance'] += distance

    # Get the degrees of the nodes
    degrees = np.sum(adjacency_matrix, axis=1)

    # Average the distances
    df['average_neighbor_distance'] /= degrees

    df['min_n_dist'] = 0
    df['max_n_dist'] = 0

    # Compute pairwise distance matrix
    distance_matrix = np.linalg.norm(points[:, None, :] - points[None, :, :], axis=-1)

    for i in range(len(points)):
        # Get indices of neighbors
        neighbors = np.where(adjacency_matrix[i, :] > 0)[0]

        if len(neighbors) > 0:  # Check if node has any neighbors
            # Get distances to neighbors
            neighbor_distances = distance_matrix[i, neighbors]

            # Compute minimum and maximum neighbor distance
            min_n_dist = np.min(neighbor_distances)
            max_n_dist = np.max(neighbor_distances)

            # Update the dataframe
            df.loc[i, 'min_n_dist'] = min_n_dist
            df.loc[i, 'max_n_dist'] = max_n_dist
        else:  # For isolated nodes, we'll set the distance to inf
            df.loc[i, 'min_n_dist'] = np.inf
            df.loc[i, 'max_n_dist'] = np.inf

    df['min_relative_angle'] = 0
    df['max_relative_angle'] = 0

    for i in range(len(points)):
        # Get indices of neighbors
        neighbors = np.where(adjacency_matrix[i, :] > 0)[0]

        if len(neighbors) > 1:  # Check if node has more than one neighbor
            # Calculate all angles between neighbors
            angles = [calculate_angle(points[i], points[n1], points[n2]) for n1, n2 in combinations(neighbors, 2)]

            # Compute minimum and maximum neighbor angle
            min_angle = np.min(angles)
            max_angle = np.max(angles)

            # Update the dataframe
            df.loc[i, 'min_relative_angle'] = min_angle
            df.loc[i, 'max_relative_angle'] = max_angle
        else:  # For nodes with one or no neighbors, we'll set the angles to 0
            df.loc[i, 'min_relative_angle'] = 0
            df.loc[i, 'max_relative_angle'] = 0

    #print(df['average_neighbor_distance'])
    #print("degree",df['degree'])
    node_features = torch.tensor(df[['relative_x', 'relative_y', 'degree','average_neighbor_distance','min_n_dist','max_n_dist', 'min_relative_angle', 'max_relative_angle']].values, dtype=torch.float)

    labels = torch.tensor(df['label'].values.astype(int), dtype=torch.long)
    data = Data(x=node_features, edge_index=edge_index, edge_attr=edge_attr, y=labels)

    data_list.append(data)

#%%
# Split your data into a training set and a validation set
train_size = int(0.75 * len(data_list))  # Assuming you want 80% of the data for training
val_size = len(data_list) - train_size
train_dataset, val_dataset = random_split(data_list, [train_size, val_size])

# Create a DataLoader for the training set and the validation set
train_loader = DataLoader(train_dataset, batch_size=32)
val_loader = DataLoader(val_dataset, batch_size=32)

# Define your model, loss function and optimizer
model = GCN(num_node_features=8, num_edge_features=3, num_classes=2)
loss_fn = torch.nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# Keep track of losses for each epoch
train_losses = []
val_losses = []

# Training function
def train(epoch):
    model.train()
    total_loss = 0
    for batch in tqdm(train_loader, desc=f"Training batches (Epoch {epoch+1})"):
        out = model(batch)
        loss = loss_fn(out, batch.y)
        total_loss += loss.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    avg_loss = total_loss / len(train_loader)
    train_losses.append(avg_loss)  # Append to list
    print(f"Train Epoch {epoch+1}, Loss: {avg_loss:.4f}")

# Validation function
def validate(epoch):
    model.eval()
    total_loss = 0
    with torch.no_grad():
        for batch in val_loader:
            out = model(batch)
            loss = loss_fn(out, batch.y)
            total_loss += loss.item()
    avg_loss = total_loss / len(val_loader)
    val_losses.append(avg_loss)  # Append to list
    print(f"Val Epoch {epoch+1}, Loss: {avg_loss:.4f}")

# Initialize best validation loss with a high value
best_val_loss = float('inf')

# Training and validation function
for epoch in range(300):  # Number of epochs
    train(epoch)
    validate(epoch)

    # Save the model weights at the best epoch
    if val_losses[-1] < best_val_loss:
        best_val_loss = val_losses[-1]
        torch.save(model.state_dict(), 'best_model_weights.pt')

# Load the best model weights
model.load_state_dict(torch.load('best_model_weights.pt'))

# Plotting losses
plt.plot(range(1, len(train_losses)+1), train_losses, label='Train')
plt.plot(range(1, len(val_losses)+1), val_losses, label='Validation')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

# %%
from torch_geometric.data import Batch
# Select the point_set you want to plot
point_set_idx = 94 # or whichever point_set you want to plot
point_set = val_dataset[point_set_idx]

# Convert point_set to a batch for model input
point_set = point_set.to('cpu')  # Assuming you are using CPU for inference
point_set = Batch.from_data_list([point_set])

# Run the point_set through the model to get the predicted labels
model.eval()  # Ensure model is in evaluation mode
with torch.no_grad():
    out = model(point_set)
predicted_labels = torch.argmax(out, dim=1).numpy()

# Extract the points and plot
points = point_set.x.numpy()
plt.scatter(points[:, 0], points[:, 1], c=predicted_labels)
plt.title(f'Point Set {point_set_idx} Predicted Labels')
plt.axis("off")
plt.axis("equal")
plt.show()
# %%


"""Unit tests for djblets.extensions.hooks.TemplateHook."""

from django.template import Context, RequestContext, Template
from django.test.client import RequestFactory
from kgb import SpyAgency
from mock import Mock

from djblets.extensions.extension import Extension
from djblets.extensions.hooks import TemplateHook
from djblets.extensions.testing import ExtensionTestCaseMixin
from djblets.testing.testcases import TestCase

class MyTestExtension(Extension):
    def initialize(self):
        self.hook_no_applies_name = 'template-hook-no-applies-name'
        self.template_hook_no_applies = TemplateHook(
            self,
            self.hook_no_applies_name,
            'test_module/some_template.html',
            [])

        self.hook_with_applies_name = 'template-hook-with-applies-name'
        self.template_hook_with_applies = TemplateHook(
            self,
            self.hook_with_applies_name,
            'test_module/some_template.html',
            [
                'test-url-name',
                'url_2',
                'url_3',
            ]
        )

class TemplateHookTests(SpyAgency, ExtensionTestCaseMixin, TestCase):
    """Unit tests for djblets.extensions.hooks.TemplateHook."""

    extension_class = MyTestExtension

    def setUp(self):
        super(TemplateHookTests, self).setUp()

        self.request = Mock()
        self.request._djblets_extensions_kwargs = {}
        self.request.path_info = '/'
        self.request.resolver_match = Mock()
        self.request.resolver_match.url_name = 'root'

    def test_hook_added_to_class_by_name(self):
        """Testing TemplateHook registration"""
        self.assertIn(
            self.extension.template_hook_with_applies,
            TemplateHook._by_name[self.extension.hook_with_applies_name])

        # The TemplateHook should also be added to the Extension's collection
        # of hooks.
        self.assertIn(self.extension.template_hook_with_applies,
                      self.extension.hooks)

    def test_hook_shutdown(self):
        """Testing TemplateHook shutdown"""
        self.extension.template_hook_with_applies.disable_hook()
        self.assertNotIn(
            self.extension.template_hook_with_applies,
            TemplateHook._by_name[self.extension.hook_with_applies_name])

        # The TemplateHook should still be in the Extension's collection
        # of hooks.
        self.assertIn(self.extension.template_hook_with_applies,
                      self.extension.hooks)

    def test_applies_to_default(self):
        """Testing TemplateHook.applies_to defaults to everything"""
        self.assertTrue(
            self.extension.template_hook_no_applies.applies_to(self.request))
        self.assertTrue(
            self.extension.template_hook_no_applies.applies_to(None))

    def test_applies_to(self):
        """Testing TemplateHook.applies_to customization"""
        self.assertFalse(
            self.extension.template_hook_with_applies.applies_to(self.request))

        self.request.resolver_match.url_name = 'test-url-name'
        self.assertTrue(
            self.extension.template_hook_with_applies.applies_to(self.request))

    def test_render_to_string(self):
        """Testing TemplateHook.render_to_string"""
        hook = TemplateHook(
            self.extension,
            name='test',
            template_name='deco/box.html',
            extra_context={
                'content': 'Hello world',
            })

        request = RequestFactory().request()
        result = hook.render_to_string(request, RequestContext(request, {
            'classname': 'test',
        }))

        self.assertHTMLEqual(
            result,
            '
'
            '
'
            '
'
            '   Hello world'
            '
'
            '
'
            '
')

    def test_context_doesnt_leak(self):
        """Testing TemplateHook's context won't leak state"""
        class MyTemplateHook(TemplateHook):
            def render_to_string(self, request, context):
                context['leaky'] = True

                return ''

        MyTemplateHook(self.extension, 'test')
        context = Context({})
        context['request'] = None

        t = Template(
            '{% load djblets_extensions %}'
            '{% template_hook_point "test" %}')
        t.render(context).strip()

        self.assertNotIn('leaky', context)

    def test_render_to_string_sandbox(self):
        """Testing TemplateHook sandboxing"""
        class MyTemplateHook(TemplateHook):
            def render_to_string(self, request, context):
                raise Exception('Oh noes')

        MyTemplateHook(self.extension, 'test')
        context = Context({})
        context['request'] = None

        t = Template(
            '{% load djblets_extensions %}'
            '{% template_hook_point "test" %}')
        t.render(context).strip()

        # Didn't crash. We're good.

    def test_applies_to_sandbox(self):
        """Testing TemplateHook for applies_to"""
        class MyTemplateHook(TemplateHook):
            def applies_to(self, request):
                raise Exception

        hook = MyTemplateHook(extension=self.extension, name='test')
        context = Context({})
        context['request'] = self.request

        self.spy_on(hook.applies_to)

        t = Template(
            '{% load djblets_extensions %}'
            '{% template_hook_point "test" %}')
        string = t.render(context).strip()

        self.assertEqual(string, '')

        self.assertTrue(hook.applies_to.called)


'''10.2 Write a program to read through the mbox-short.txt and figure out
the distribution by hour of the day for each of the messages. You can pull
the hour out from the 'From ' line by finding the time and then splitting
the string a second time using a colon.
From stephen.marquard@uct.ac.za Sat Jan  5 09:14:16 2008
Once you have accumulated the counts for each hour,
print out the counts, sorted by hour as shown below'''

# Answer

name = input("Enter file:")
if len(name) < 1 : name = "mbox-short.txt"
handle = open(name)
lst=list()
di=dict()
for line in handle:
    if line.startswith("From "):
    	pos=line.find(":")
    	lst.append(line[pos-2:pos])
for word in lst:
    di[word]=di.get(word,0)+1
newlst=list()
for key,val in di.items():
    newtup=(key,val)
    newlst.append(newtup)
newlst=sorted(newlst)
for key,val in newlst:
    print(key,val)

# file_name = mbox-short.txt


# let's say player o is the AI and player x is the human
# let's say the maximum time for the AI to play his turn is 2 seconds
import random
from collections import defaultdict
from abc import ABC, abstractmethod
import math

# Node Tree class
class Node:
    # Node Tree constructor
    def __init__(self, board_state, parent):
        # Initalize board state
        self.board_state = board_state

        # Initalize parent node
        self.parent = parent

        # Initialze number of visit
        self.visits = 0

        # Initialize score of the node, higher the score the most likely it will be chosen
        self.score = 0

        # Initialize node's children
        self.children = {}

        print("Created node with state:")
        print(self.board_state)

# Monte Carlo Tree Search Class
class MCTS:
    # remove this because this should be tied the nodes, not the actual algorithm
    #def __init__(self):
        #self.V = defaultdict(int) #the total reward for each node
        #self.N = defaultdict(int) #the total times the node has been visited
        #self.children = dict(); #children of each node, for now we set the dictionnary as being empty

    # added the search loop here because it made sense
    def search(self, starting_state):
        # create node tree
        self.root = Node(starting_state, None)

        # iterate X amount of times
        for iteration in range(1000):
            # Selection Phase, Expansion Phase in the select function
            node = self.select(self.root)

            # Simulation Phase
            score = self.rollout(node.board)

            # Backpropagate Phase
            self.backpropagate(node, score)

        # pick the AI's best move
        try:
            return self.choose_next_move(self.root, 0)

        except:
            pass

    def select(self, board_state):
    # starting at the root node
      node = board_state

      # traverse the tree until a leaf node is reached
      while not node.check_winner() and node in self.children:
          # the UCB algorithm will select a child node to explore
          if node not in self.children:
              # add the node to the tree and expand it
              self.children[node] = {move: node.next_state(move) for move in node.get_possible_moves()}
          else:
              _, node = max(((self.V[child] / self.N[child]) + math.sqrt(2 * math.log(self.N[node]) / self.N[child]), child) for child in self.children[node])

          # perform some action on the child node

          # expand the node if it hasn't been expanded yet and add it to the tree
          if not node.check_winner():
              unexplored_moves = [move for move in node.get_possible_moves() if move not in self.children[node]]
              # chooses unexplored move randomly
              if unexplored_moves:
                  move = random.choice(unexplored_moves)
                  new_node = node.next_state(move)
                  self.children[node][move] = new_node
                  node = new_node

      return node

    def backpropagate(self, node, score):
        # update nodes's up to root node
        while node is not None:
            # update node's visits
            node.visits += 1

            # update node's score
            node.score += score

            # set node to parent
            node = node.parent

    def rollout(self, board_state):
        #check if there is a winner in the current state
        winner = board_state.check_winner()
        if winner:
            if winner == 'O':
                return -1
            else:
                return 1
            #if there is no winner continue playing
        while not board_state.is_draw():
            row, col = random.choice(board_state.available_play())
            board_state.play_move(row,col)
            winner = board_state.check_winner()
            if winner:
                if winner == 'O':
                    return -1
                else:
                    return 1
        return 0
    def rollout_policy(board_state):
        #returns a random valid move for the given board state
        return random.choice(board_state.available_play())
    def choose_next_move(self,board_state):
        #choosing the best sucessor out of all
        if board_state.check_winner():
            raise RuntimeError(f"choose_next_move was called when no more moves are possible {board_state}")
        def score(n):
            if self.N[n] == 0:
                return float("-inf")
                #by doing this we are avoiding to choose before having explored the node
            return self.V[n] / self.N[n] #this is the average number
        return max(self.children[board_state], key = score)
        #self.children[board_state] needs a row and a col function for the main to work and get the movment they want it to be

class TicTacToe:
    # initialize tic tac toe board
    def __init__(self):
        # creates a 2D list of size 3x3
        self.board = [[" " for _ in range(3)] for _ in range(3)]
        # player is X
        self.current_player = 'X'

    # all moves that are currently available
    def available_play(self):
        # list of the different available possible plays, we could make a list with all the different poissible move, so that we can pop that possibility when we want to expand that node
        list_of_possible_moves = []
        for row in range(3):
            for col in range(3):
                if self.board[row][col] == " ":
                    #add moves to the list
                    list_of_possible_moves.append((row,col))
        return list_of_possible_moves

    # print the current game board
    def print_board(self):
        for row in self.board:
            print(" | ".join(row))
            print("-" * 9)

    # check if there is a winner
    def check_winner(self):
        # Check rows
        for row in self.board:
            if row[0] == row[1] == row[2] and row[0] != " ":
                return row[0]

        # Check columns
        for col in range(3):
            if self.board[0][col] == self.board[1][col] == self.board[2][col] and self.board[0][col] != " ":
                return self.board[0][col]

        # Check diagonals
        if self.board[0][0] == self.board[1][1] == self.board[2][2] and self.board[0][0] != " ":
            return self.board[0][0]
        if self.board[0][2] == self.board[1][1] == self.board[2][0] and self.board[0][2] != " ":
            return self.board[0][2]

        return None

    #check if there is a draw
    def is_draw(self):
        for row in self.board:
            if " " in row:
                return False
        return True

    # play move
    def play_move(self, row, col):
        # check if move is valid
        if row < 0 or row > 2 or col < 0 or col > 2 or self.board[row][col] != " ":
            print("Invalid move. Try again.")

        else:
            # assign current player to grid they select
            self.board[row][col] = self.current_player
            #swap players since player and AI take turns
            self.current_player = "X" if self.current_player == "O" else "O"

    # Main function to run the game
    def main(self):

        # print welcome
        print("Welcome to Tic-Tac-Toe!")
        print("X goes first.")

        #print board
        self.print_board()

        #print available moves
        print(self.available_play())

        #initialize MCTS class, class should be here our we keep creating the class over
        mcts = MCTS()

        # while game is not a draw, do:
        while not self.is_draw():
            # player's turn to pick row and col
            if self.current_player == 'X':
                row = int(input("Enter row: "))
                col = int(input("Enter col: "))
            # AI's turn
            else:
                print("AI is computing move...")

                # this code is causing some error, I think this should be written in the MCTS class tbh
                ##for i in range(1000):
                    #mcts.N[node] += 1
                    #leaf = mcts.select(node)
                    #reward = mcts.rollout(leaf)
                    #mcts.backpropagate(leaf, reward)
                #row, col = mcts.choose_next_move(node)

                # search for the ai's move here
                AI_move = mcts.search(self)
                # make AI move here

                #print(f"AI plays {row}, {col}")

            # player makes mmove on the board
            self.play_move(row, col)

            # print board
            self.print_board()

            # check if there is a winner
            winner = self.check_winner()
            if winner:
                print(f"{winner} wins!")
                return

        print("Draw.")

if __name__ == "__main__":
    #create tic tac toe board
    game = TicTacToe()
    #start the game
    game.main()

class board_state(ABC):
    #these is what can be considered as a node. MCTS will create a tree of these nodes, expand from the current node and explore, simulate and backtrack
    def __init__(self) -> None:
        super().__init__()


from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('', views.home, name='home'),
    path('login/', views.VRegistro.as_view(), name="autenticacion"),
    path('autenticar/', views.autenticar, name="autenticar"),
    path('logout/', views.LogOut, name="LogOut"),

    path('perfil/', views.act_info, name="act_info"),
    path('cambiar_contraseña/', views.cambiar_contrasena, name="cambiar_contraseña"),

    path('añadir_categoria/', views.categoria_add, name="categoria_add"),
    path('ver_categoria/', views.categoria_list, name="categoria_list"),
    path('delete_categoria/<id>', views.delete_categoria, name='categoria_delete'),
    path('update_categoria/<id>', views.update_categoria, name='categoria_update'),

    path('añadir_area_especialidad/', views.area_especialidad_add, name="area_especialidad_add"),
    path('ver_area_especialidad/', views.area_especialidad_list, name="area_especialidad_list"),
    path('delete_area_especialidad/<id>', views.delete_area_especialidad, name='area_especialidad_delete'),
    path('update_area_especialidad/<id>', views.update_area_especialidad, name='area_especialidad_update'),

    path('añadir_rol_trabajo/', views.rol_trabajo_add, name="rol_trabajo_add"),
    path('ver_rol_trabajo/', views.rol_trabajo_list, name="rol_trabajo_list"),
    path('ver_rol_trabajo/edit_rol_trabajo/<id>', views.update_rol_trabajo, name='rol_trabajo_edit'),
    path('ver_rol_trabajo/rol_trabajo/<id>', views.rol_trabajo, name='rol_trabajo_ver'),
    path('delete_rol_trabajo/<id>', views.delete_rol_trabajo, name='rol_trabajo_delete'),

    path('añadir_conocimiento/', views.conocimiento_add, name="conocimiento_add"),
    path('ver_conocimiento/', views.conocimiento_list, name="conocimiento_list"),
    path('delete_conocimiento/<id>', views.delete_conocimiento, name='conocimiento_delete'),
    path('update_conocimiento/<id>', views.update_conocimiento, name='conocimiento_update'),

    path('añadir_habilidad/', views.habilidad_add, name="habilidad_add"),
    path('ver_habilidad/', views.habilidad_list, name="habilidad_list"),
    path('delete_habilidad/<id>', views.delete_habilidad, name='habilidad_delete'),
    path('update_habilidad/<id>', views.update_habilidad, name='habilidad_update'),

    path('añadir_tarea/', views.tarea_add, name="tarea_add"),
    path('ver_tarea/', views.tarea_list, name="tarea_list"),
    path('delete_tarea/<id>', views.delete_tarea, name='tarea_delete'),
    path('update_tarea/<id>', views.update_tarea, name='tarea_update'),

    path('añadir_herramienta/', views.herramienta_add, name="herramienta_add"),
    path('ver_herramienta/', views.herramienta_list, name="herramienta_list"),
    path('delete_herramienta/<id>', views.delete_herramienta, name='herramienta_delete'),
    path('update_herramienta/<id>', views.update_herramienta, name='herramienta_update'),

    path('añadir_centro_trabajo/', views.centro_trabajo_add, name="centro_trabajo_add"),
    path('ver_centro_trabajo/', views.centro_trabajo_list, name="centro_trabajo_list"),
    path('delete_centro_trabajo/<id>', views.delete_centro_trabajo, name='centro_trabajo_delete'),
    path('update_centro_trabajo/<id>', views.update_centro_trabajo, name='centro_trabajo_update'),

    path('añadir_genero/', views.genero_add, name="genero_add"),
    path('ver_genero/', views.genero_list, name="genero_list"),
    path('delete_genero/<id>', views.delete_genero, name='genero_delete'),
    path('update_genero/<id>', views.update_genero, name='genero_update'),

    path('añadir_municipio/', views.municipio_add, name="municipio_add"),
    path('ver_municipio/', views.municipio_list, name="municipio_list"),
    path('delete_municipio/<id>', views.delete_municipio, name='municipio_delete'),
    path('update_municipio/<id>', views.update_municipio, name='municipio_update'),

    path('añadir_provincia/', views.provincia_add, name="provincia_add"),
    path('ver_provincia/', views.provincia_list, name="provincia_list"),
    path('delete_provincia/<id>', views.delete_provincia, name='provincia_delete'),
    path('update_provincia/<id>', views.update_provincia, name='provincia_update'),

    path('añadir_admin/', views.AdminAdd.as_view(), name="admin_add"),
    path('ver_admin/', views.admin_list, name="admin_list"),
    path('delete_admin/<id>', views.delete_admin, name='admin_delete'),

    path('añadir_especialista/', views.EspecialistaAdd.as_view(), name="especialista_add"),
    path('ver_especialista/', views.especialista_list, name="especialista_list"),
    path('delete_especialista/<id>', views.delete_especialista, name='especialista_delete'),

    path('evaluar_especialista/<rt_id>', views.evaluar_especialista, name='especialista_evaluar'),

]

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


def regressionLine(x, y):
    sumSquareX = sum([n**2 for n in x])
    sumSquareY = sum([n**2 for n in y])
    sumX = sum(x)
    sumY = sum(y)
    sumXY = sum([X*Y for X,Y in zip(x,y)])
    a = ((sumSquareX*sumY) - (sumX*sumXY)) / float(((len(x) * sumSquareX) - sumX**2))
    b = ((len(x)*sumXY) - (sumX*sumY)) / float(((len(x)*sumSquareX) - sumX**2))
    a = round(a,4)
    b = round(b,4)
    return a,b

print(regressionLine([25,30,35,40,45,50], [78,70,65,58,48,42]))
#(114.381, -1.4457)
#a =  [(Σx²)(Σy) - (Σx)(Σxy)]  /  [n(Σx²) - (Σx)²]
#b =  [n(Σxy) - (Σx)(Σy)] / [n(Σx²) - (Σx)²]


american_date = "05.17.2016"
point_idx = american_date.find('.')
mounth = american_date[:point_idx + 1 ]
point2 = american_date.find('.', point_idx + 1 )
day = american_date[point_idx + 1 : point2 + 1 ]
year = american_date[ point2 + 1 : ]
europe_date = day + mounth + year
print(europe_date)

first = 'aaaaaa'
second = 'bbbbbb'
inp = second [:int(len(second)/2)] + first + second[int(len(second)/2):]
result = first[:int(len(first)/2)] + inp + first[int(len(first)/2):]
print(result)

string = 'aaaaa bb xx ccc ddd'
capt = string.find(' ')
capt2 = string.find(' ', capt +1)
strint2 =  string[:capt] + string[capt:capt2].upper() + string[capt2:]
print(strint2)

import math
leo = 'Leo Tolstoy*1828-08-28*1910-11-20'
find_idx = leo.find('*')
space_ind =  leo.find('-')
birthday = leo[find_idx+1:space_ind]
find_idx1 = leo.find("*", find_idx + 1)
space_ind1= leo.find("-", find_idx1 )
death = leo[find_idx1+1:space_ind1]
age =  int(death) - int(birthday)
final = leo[:find_idx] + ', ' + str(age)
print(final)


import json

# Cria um dicionário
database = {"nome": "João", "idade": 30, "cidade": "São Paulo"}

# Abre o arquivo database.json no modo de escrita
with open("database.json", "w") as file:
    # Escreve o dicionário no arquivo
    json.dump(database, file)

print("Dados salvos com sucesso!")


from keras.applications import *
from keras.layers.pooling import GlobalAveragePooling2D, GlobalMaxPooling2D
from keras.layers import Dense
from keras.models import Model
from keras.callbacks import ModelCheckpoint,EarlyStopping, ReduceLROnPlateau
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import *
import os

nb_classes = 5
batch_size = 32
img_w = 299
img_h = 299
img_channels = 3
rotation_degrees = 15
transformation_ratio = .05
nb_epoch = 150
keep_frozen = 100

base_model = Xception(include_top=False, weights='imagenet', input_shape=(img_w,img_h,img_channels))

x = base_model.output
x = GlobalAveragePooling2D()(x)

predictions = Dense(nb_classes, activation='softmax')(x)

model = Model(base_model.input, predictions)

for layer in model.layers[:keep_frozen]:
    layer.trainable = False
for layer in model.layers[keep_frozen:]:
    layer.trainable = True

train_datagen = ImageDataGenerator(rotation_range=10,
    width_shift_range=0.2,
    height_shift_range=0.2,
    zoom_range=0.2,
    fill_mode='constant',
    horizontal_flip=True)

validation_datagen = ImageDataGenerator(rotation_range=10,
    width_shift_range=0.2,
    height_shift_range=0.2,
    zoom_range=0.2,
    fill_mode='constant',
    horizontal_flip=True)

train_generator = train_datagen.flow_from_directory("images/training_set/",
                                                        target_size=(img_w, img_h),
                                                        batch_size=batch_size,
                                                        class_mode='categorical')

validation_generator = validation_datagen.flow_from_directory("images/validation_set/",
                                           target_size=(img_w, img_h),
                                           batch_size=batch_size,
                                           class_mode='categorical')

opt = SGD(lr=1e-3)

model.compile(optimizer=opt,
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

top_weights_path = os.path.join("model", 'top_model_weights_xception.h5')

callbacks_list = [
    ModelCheckpoint(top_weights_path, monitor='val_acc', verbose=1, save_best_only=True),
    EarlyStopping(monitor='val_acc', patience=60, verbose=0),
    ReduceLROnPlateau(monitor='val_loss', factor=0.3, patience=40, verbose=1, mode='auto', epsilon=1e-10, cooldown=0, min_lr=1e-10)]
print(model.summary())

model.fit_generator(train_generator,
                    steps_per_epoch=(train_generator.n/batch_size)/3,
                    epochs=1,#nb_epoch*3,
                    callbacks=callbacks_list,
                    validation_data=validation_generator,
                    validation_steps=(validation_generator.n / batch_size)/5)

model_json = model.to_json()
with open(os.path.join("model/", 'model_xception.json'), 'w') as json_file:
    json_file.write(model_json)


# need to revisit this script
# this does not do much other than list all the available ips
# no longer shows available ip's errors out

import subprocess
import ipaddress

network_address = input('Enter a network address in CIDR format(example 192.168.1.0/24): ')

ip_network = ipaddress.ip_network(network_address)
for all_hosts in ip_network.hosts():
    print(all_hosts)

    status, result = subprocess.getstatusoutput('ping -c1 -w2 ' + all_hosts)

if status == 0:
    print('Host ' + all_hosts + ' is UP')
else:
    print('Host ' + all_hosts + ' is DOWN')


import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
    """A Class to manage the Bullets behavor."""

    def __init__(self, ai_game):
        super().__init__()

        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.color = ai_game.settings.BULLET_COLOR

        # Creates a Bullet Rect
        self.rect = pygame.Rect(0, 0, self.settings.BULLET_WIDTH, self.settings.BULLET_HEIGHT)
        self.rect.midtop = ai_game.ship.rect.midtop

        #Store the bullets position as a decimal.
        self.y = float(self.rect.y)

    def update(self):
        """Move the bullet up the screen"""
        self.y -= self.settings.bullet_speed

        #Update Position
        self.rect.y = self.y

    def draw_bullet(self):
        """Draws the bullet to the screen."""
        pygame.draw.rect(self.screen, self.color, self.rect)


import pytest
import sys
from selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from webdriver_manager.microsoft import IEDriverManager
from webdriver_manager.utils import ChromeType

sys.path.append('pageobjects')
sys.dont_write_bytecode = True

# add cli options
def pytest_addoption(parser):
    parser.addoption('--url', action='store', default='https://jisho.org/', help='Specify the base URL for testing')
    parser.addoption('--driver', action='store', default='chrome', help='Supported browsers: Firefox, Chrome, Chromium, Edge, and IE')

# driver fixture passed to all tests
@pytest.fixture(scope='session')
def driver(request):
    browserName = request.config.getoption('--driver')
    if browserName == "firefox":
        driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
    elif browserName == "chrome":
        driver = webdriver.Chrome(ChromeDriverManager().install())
    elif browserName == "chromium":
        driver = webdriver.Chrome(ChromeDriverManager(chrome_type=ChromeType.CHROMIUM).install())
    elif browserName == "edge":
        driver = webdriver.Edge(EdgeChromiumDriverManager().install())
    elif browserName == "ie":
        driver = webdriver.Ie(IEDriverManager().install())
    else:
        raise ValueError('Invalid browser name: ' + browserName)
    driver.set_window_size(1280, 800)
    driver.base_url = request.config.getoption('--url')
    yield driver
    driver.quit()


import pandas as pd
import os
import sys
import json

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
import common.bert.constants as constants

def get_sentiment(x):
    if x['opos'] == 0 and x['oneg'] == 1:
        sentiment = 0  # negative
    elif x['opos'] == 1 and x['oneg'] == 0:
        sentiment = 1  # positive
    elif x['opos'] == 1 and x['oneg'] == 1:
        sentiment = 2  # mixed
    else:
        sentiment = 3  # neutral

    return sentiment

def convert(dataset, basedir=os.path.join('data', 'classification')):

    path_data = os.path.join(basedir, dataset)
    data = pd.read_csv(path_data)

    data['sentiment'] = data.apply(lambda x: get_sentiment(x), axis=1)
    data['sentiment'].value_counts()
    data.to_csv(os.path.join(path_data))

    index2category = {0: 'negative', 1: 'positive', 2: 'mixed', 3: 'neutral'}
    with open(os.path.join(basedir, constants.LABELS_FILE), 'w') as outfile:
        json.dump(index2category, outfile)

if __name__ == '__main__':
    convert(dataset=sys.argv[1], basedir=sys.argv[2])


from ...utils.logger import logger as log

def get_drawdowns(
    data: list[float | int],
    as_percentage: bool = True,
) -> list[float | int]:
    """Gets a list of all drawdown values of a univariate timeseries.

    Args:
        data (list[float | int]): The timeseries data for which to obtain drawdowns.

    Returns:
        dict[str, Any]: Dictionary describing the max drawdown value.
    """
    log.info("Calling get_drawdowns")

    drawdowns = []
    previous_datum = -1  # data values are assumed to be positive semi-definite
    for i, datum in enumerate(data):
        if i + 1 < len(data) and datum >= previous_datum:
            drawdown = 0
            proceeding = data[i + 1 :]  # all data after the current point
            for p in proceeding:
                if p < datum and (datum - p) > drawdown:
                    drawdown = datum - p
                else:
                    break
            if as_percentage:
                drawdown = drawdown / datum * 100
            drawdowns.append(drawdown)
            previous_datum = datum

    return drawdowns


"""
QUES: Power Set
Note: no. of element in power set is 2^n where n is the number of elements in the set
"""

# Time(n2^n)
# Space(1)

# Method 1: iterative
import math

def printPowerSet(set, set_size):
    # set_size of power set of a set
    # with set_size n is (2**n -1)
    pow_set_size = int(math.pow(2, set_size))

    # Run from counter 000..0 to 111..1
    for counter in range(0, pow_set_size):
        for j in range(0, set_size):

            # Check if jth bit in the
            # counter is set If set then
            # print jth element from set
            if (counter & (1 << j)) > 0:
                print(set[j], end="")
        print("")

set = ['a', 'b', 'c']
# printPowerSet(set, 3)

# Method 2: recursive
# Time(2^n)
# Space(1)

def powerSet(string, index, curr):
    if index == len(string):
        return print(curr)
    powerSet(string, index + 1, curr + string[index])
    powerSet(string, index + 1, curr)

string = "abc"
curr = ""
index = 0
print(powerSet(string, index, curr))


height = 170
weight = 70
index = height // weight  # индекс массы тела#
print(index)
height = int(input("enter height:"))
weight = int(input("enter weight:"))
print(height, weight, index)
time_sec = int(input("enter time:"))
hour = time_sec // 3600
min = time_sec % 3600 // 60
sec = time_sec % 3600 % 60
print(f"{hour:02}:{min:02}:{sec:02}")
# № 3
n = input("enter number: ")
print(int(n) + int(n + n) + int(n + n + n))
# № 4
a = int(input("enter number: "))  # 67588
max = 0
while a > 0:
    surplas = a % 10
    if surplas > max:
        max = surplas
    a //= 10
    break
print("Максимальная цифра:", max)
# №4
profit = int(input("enter прибыль:"))
cost = int(input("enter издержки:"))
ind = profit - cost
if ind < 0:
    print("bad")
if ind > 0:
    print("cool!!")
    rent = profit / cost
    work_man = int(input("enter количество рабоников: "))
    profit_each_work = rent / work_man
    print("прибыль из расчета на одного сотрудника", profit_each_work)
# № 5
a = int(input("enter distance:"))
b = int(input("enter right distance"))
day = 1
while a < b:
    a *= 1.1
    day += 1
print(f"на {day}-й день спортсмен пробежал {b}км")


# -*- coding: utf-8 -*-
"""
Created on Fri Feb 23 09:16:30 2018

@author: arhen
"""

import matplotlib.pyplot as plt
x = range(0,5)
y1 = [0.1, 0.2, 0.5, 0.3, 0.3]
y2 = [0.3, 0.6, 0.8, 0.7, 0.5]
plt.close()
plt.plot(x, y1)
plt.plot(x, y2)
plt.ylim([0,1])
plt.show()


import os
import torch
import torch.utils.data
import torchvision
import numpy as np
import cv2
from math import*

from pix_co_to_cartesian_co import pix_orientation
# from data.apple_dataset import AppleDataset
from data.apple_dataset_pre import AppleDataset
# from data.apple_dataset_data1 import AppleDataset_data1
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
from torchvision.models.detection.mask_rcnn import MaskRCNNPredictor

import utility.utils as utils
import utility.transforms as T

######################################################
# Predict with either a Faster-RCNN or Mask-RCNN predictor
######################################################
def get_transform(train):
	transforms = []
	transforms.append(T.ToTensor())
	if train:
		transforms.append(T.RandomHorizontalFlip(0.5))
	return T.Compose(transforms)

def get_maskrcnn_model_instance(num_classes):
	# load an instance segmentation model pre-trained pre-trained on COCO
	model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=False)
	# get number of input features for the classifier
	in_features = model.roi_heads.box_predictor.cls_score.in_features
	# replace the pre-trained head with a new one
	model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)

	# now get the number of input features for the mask classifier
	in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channels
	hidden_layer = 256
	# and replace the mask predictor with a new one
	model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask, hidden_layer, num_classes)
	return model

def get_frcnn_model_instance(num_classes):
	# load an instance segmentation model pre-trained pre-trained on COCO
	model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=False)

	# get number of input features for the classifier
	in_features = model.roi_heads.box_predictor.cls_score.in_features
	# replace the pre-trained head with a new one
	model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
	return model

def drawBoundingBox(stacked,centers,roll_yaw_pitch,args,f_x,f_y,depth_array):#,imgcv,result):
#	imgcv= cv2.imread('/home/nalin/Desktop/DataSet/detection/original_data_sets/test/images/{}'.format(stacked[0][0]))
	imgcv= cv2.imread(os.path.join(args.data_path, 'images/{}'.format(stacked[0][0])))
	h,w,_ = imgcv.shape
	for box in stacked:
		print('========')
		print(box)
		print('========')
		x1 = int(box[-5])
		y1 = int(box[-4])
		x2 = int(box[-3])
		y2 = int(box[-2])
		# x.astype(int)
		conf = box[-1]
		print('x1 = ',x1)
		print('y1 = ',y1)
		print('x2 = ',x2)
		print('y2 = ',y2)
		# print(conf)
		# label = box['label']
		if float(conf) > 0.75:
			cv2.rectangle(imgcv,(x1,y1),(x2,y2),(0,255,0),1)
			centers.append([0.5*(x1+x2),0.5*(y1+y2)])
			print('=============================================')
			# img_to_array = np.asarray(imgcv)
			# print('img_to_array shape = ',img_to_array.shape)
			# print('img_to_array shape = ',img_to_array[:,:,0].shape)
			# np.savetxt('npB.csv', imgcv[:,:,0], delimiter=',')
			np.savetxt('npG.csv', imgcv[:,:,1], delimiter=',')
			# np.savetxt('npR.csv', imgcv[:,:,2], delimiter=',')
			print('Image shape = ',imgcv.shape)
			# print('=================================================')
			# for i in range [y1:y2]:
			# 	for j in range [x1:x2]:
			# 		print('pixel values of each [i][j] = ',imgcv[i,j,1])
			theta_ij_total = 0
			phi_ij_total = 0
			length_data = 0
			i = y1
			j = x1
			while(i >= y1 and i < y2):
				while(j >= x1 and j < x2):
					if( imgcv[i,j,1]<100 ):
						# print('i = ',i)
						# print('j = ',j)
						# print('pixel values of each [i][j] = ',imgcv[i,j,1])
						theta_ij,phi_ij = pix_orientation(j,i,h,w,f_x,f_y,depth_array)
						theta_ij_total = theta_ij_total+theta_ij
						phi_ij_total = phi_ij_total+phi_ij
						length_data = length_data+1
					j = j+1
				i = i+1
				j = x1

			theta = theta_ij_total/length_data
			phi = phi_ij_total/length_data
			# theta,phi = pix_orientation(int(0.5*(y1+y2)),int(0.5*(x1+x2)),h,w,f_x,f_y,depth_array)
			r11 = cos(theta)*cos(phi)
			r21 = sin(theta)*cos(phi)
			r31 = -sin(phi)
			r32 = 0
			r33 = cos(phi)
			yaw = atan2(r21,r11)
			pitch = atan2(-r31,sqrt(r32**2+r33**2))
			roll = atan2(r32,r33)
			print('roll,yaw,pitch = ',degrees(roll),degrees(yaw),degrees(pitch))
			roll_yaw_pitch.append([roll,yaw,pitch])
			cv2.putText(imgcv,conf,(x1,y1),cv2.FONT_HERSHEY_COMPLEX,0.5,(0,0,0),1)
			cv2.imwrite(os.path.join(args.data_path, 'images_with_bbox/{}'.format(stacked[0][0])), imgcv)
	box_image = cv2.imread(os.path.join(args.data_path, 'images_with_bbox/{}'.format(stacked[0][0])))
	#print('Path = ',)
	return (h,w,centers,roll_yaw_pitch)

def main_pixel_co(args,f_x,f_y,depth_array): #_pixel_co
	num_classes = 2
	device = args.device

	# Load the model from
	print("Loading model")
	# Create the correct model type
	if args.mrcnn:
		model = get_maskrcnn_model_instance(num_classes)
	else:
		model = get_frcnn_model_instance(num_classes)

	# Load model parameters and keep on CPU
	checkpoint = torch.load(args.weight_file, map_location=device)
	# print(checkpoint)
	# for key, value in checkpoint.items() :
	# 	print(key)
	model.load_state_dict(checkpoint, strict=False)
	model.eval()

	print("Creating data loaders")
	dataset_test = AppleDataset(args.data_path, get_transform(train=False))
	# dataset_test = AppleDataset_data1(args.data_path, get_transform(train=False))
	data_loader_test = torch.utils.data.DataLoader(dataset_test, batch_size=1,
												   shuffle=False, num_workers=1,
												   collate_fn=utils.collate_fn)

	# Create output directory
	base_path = os.path.dirname(args.output_file)
	if not os.path.exists(base_path):
		os.makedirs(base_path)

	# Predict on bboxes on each image
	f = open(args.output_file, 'a')
	for image, targets in data_loader_test:    # for different images one after another
		image = list(img.to(device) for img in image)
		outputs = model(image)
		print('Output = \n',outputs)
		centers = []
		roll_yaw_pitch = []
		for ii, output in enumerate(outputs):  # bbox of one instance(apple) in one image
			# print('ii,output = ', ii, output)
			img_id = targets[ii]['image_id']
			img_name = data_loader_test.dataset.get_img_name(img_id)
			print("Predicting on image: {}".format(img_name))
			boxes = output['boxes'].detach().numpy()
			scores = output['scores'].detach().numpy()

			im_names = np.repeat(img_name, len(boxes), axis=0)
			stacked = np.hstack((im_names.reshape(len(scores), 1), boxes.astype(int), scores.reshape(len(scores), 1)))

			# File to write predictions to
			print('stacked = ',stacked)
			h,w,centers,roll_yaw_pitch = drawBoundingBox(stacked,centers,roll_yaw_pitch,args,f_x,f_y,depth_array)
			print('centers = ',centers)
			# print('h,w,centers = ',h,w,centers)
			np.savetxt(f, stacked, fmt='%s', delimiter=',', newline='\n')
	return(h,w,centers,roll_yaw_pitch)