from __future__ import annotations
from dataclasses import dataclass
from rich.console import Console
from typing import List, Tuple, Dict

@dataclass(order=True, frozen=True)
class Coords:
    x: int
    y: int

    def __repr__(self) -> str:
        return f"<{self.x},{self.y}>"

    def get_neighbours_in_order(self) -> List[Coords]:
        return [
            Coords(self.x - 1, self.y - 1),
            Coords(self.x, self.y - 1),
            Coords(self.x + 1, self.y - 1),
            Coords(self.x - 1, self.y),
            Coords(self.x, self.y),
            Coords(self.x + 1, self.y),
            Coords(self.x - 1, self.y + 1),
            Coords(self.x, self.y + 1),
            Coords(self.x + 1, self.y + 1),
        ]

def read_input(lines: List[str]) -> Tuple[str, Dict[Coords, int], Coords, Coords]:
    mapping = lines.pop(0)
    lines.pop(0)

    image = {}
    maxX = 0
    for yIndex, line in enumerate(lines):
        for xIndex, item in enumerate(line):
            if item == "#":
                image[Coords(xIndex, yIndex)] = 1
                maxX = max(maxX, xIndex)

    return mapping, image, Coords(0, 0), Coords(maxX, yIndex)

def output_coords(coords: Dict[Coords, int], min_val: Coords, max_val: Coords):
    for y in range(min_val.y, max_val.y + 1):
        for x in range(min_val.x, max_val.x + 1):
            char = "#" if Coords(x, y) in coords else "."
            console.print(f"{char}", end="")
        console.print()
    console.print()

def isPixelLit(
    pixel: Coords,
    mapping: str,
    image: Dict[Coords, int],
    minCoord: Coords,
    maxCoord: Coords,
    iteration: int,
) -> bool:
    num = 0
    for neighbour in pixel.get_neighbours_in_order():
        num <<= 1
        if image.get(neighbour) is not None:
            num |= 1
        elif mapping[0] == "#":
            if iteration % 2 == 0 and (
                neighbour.x < minCoord.x
                or neighbour.y < minCoord.y
                or neighbour.x > maxCoord.x
                or neighbour.y > maxCoord.y
            ):
                num |= 1
    return mapping[num] == "#"

def enhance(
    mapping: str,
    image: Dict[Coords, int],
    origin_min: Coords,
    origin_max: Coords,
    iteration: int,
) -> Tuple[Dict[Coords, int], Coords, Coords]:

    new_image = {}
    minX = 1
    maxX = 0
    minY = 1
    maxY = 0

    for y in range(origin_min.y - 1, origin_max.y + 2):
        for x in range(origin_min.x - 1, origin_max.x + 2):
            loc = Coords(x, y)
            if isPixelLit(loc, mapping, image, origin_min, origin_max, iteration):
                new_image[loc] = 1
                minX = min(minX, x)
                minY = min(minY, y)
                maxX = max(maxX, x)
                maxY = max(maxY, y)

    return new_image, Coords(minX, minY), Coords(maxX, maxY)

console = Console()
with open("day20.txt", "r") as file:
    mapping, image, minCoords, maxCoords = read_input(file.readlines())
    console.print("[b yellow]Day 20[/b yellow]")

    for iteration in range(1, 51):
        image, minCoords, maxCoords = enhance(
            mapping, image, minCoords, maxCoords, iteration
        )
        if iteration == 2:
            console.print(len(image))
    console.print(len(image))


# import pymysql
import Lab1_Ex2_01_init

cursor = Lab1_Ex2_01_init.conn.cursor()

print("--- For a certain PaperID, the AuthorID in priority order will be shown.---\n")
target_paper_id = input("Please enter the target PaperID:\n")

cursor.execute("Select AuthorSequence,AuthorID \
               From paper_author_affiliation \
               where PaperID='" + target_paper_id + "'\
               Order by AuthorSequence")
sql_result = cursor.fetchall()

result = list(sql_result)
# result.sort()
print("\n-- PaperID {} --".format(target_paper_id))
for idx, content in enumerate(result):
    print("{}.\tAuthorID: {}".format(idx + 1, content[1]))


from Miscellaneous import functionReturningTrueIfEqualsString, lireFichier
from automates.StateEngine import StateEngine

class RecogniseStateEngine(StateEngine):
    def __init__(self):
        StateEngine.__init__(self)

    def run(self,string):
        for char in string:
            self.input(char)

        return self.currentState.get_isFinal()

    def build (self, params):
        for string in params:
            for char in string:
                self.inputWileBuilding(char,functionReturningTrueIfEqualsString)
            self.reset()
        self.reset()

    @staticmethod
    def creerArbreAdresses(path):
        codes = list(set(lireFichier(path)))
        arbre = RecogniseStateEngine()
        arbre.build(codes)
        arbre.reset()
        return arbre


from django.urls import path

from .views import (
    QuoteCreateView,
    QuoteDeleteView,
    QuoteDetailView,
    QuoteListView,
    QuoteUpdateView,
    SourceCreateView,
    SourceDeleteView,
    SourceDetailView,
    SourceGroupCreateView,
    SourceGroupDeleteView,
    SourceGroupDetailView,
    SourceGroupListView,
    SourceGroupUpdateView,
    SourceListView,
    SourceUpdateView,
)

app_name = "quotes"
urlpatterns = [
    path("groups/", view=SourceGroupListView.as_view(), name="group_list"),
    path("groups/create/", view=SourceGroupCreateView.as_view(), name="group_create"),
    path(
        "groups/<slug:group>/",
        view=SourceGroupDetailView.as_view(),
        name="group_detail",
    ),
    path(
        "groups/<slug:group>/edit/",
        view=SourceGroupUpdateView.as_view(),
        name="group_update",
    ),
    path(
        "groups/<slug:group>/delete/",
        view=SourceGroupDeleteView.as_view(),
        name="group_delete",
    ),
    path(
        "groups/<slug:group>/sources/",
        view=SourceListView.as_view(),
        name="source_list",
    ),
    path(
        "groups/<slug:group>/sources/add/",
        view=SourceCreateView.as_view(),
        name="source_create",
    ),
    path(
        "sources/<slug:source>/",
        view=SourceDetailView.as_view(),
        name="source_detail",
    ),
    path(
        "sources/<slug:source>/edit/",
        view=SourceUpdateView.as_view(),
        name="source_update",
    ),
    path(
        "sources/<slug:source>/delete/",
        view=SourceDeleteView.as_view(),
        name="source_delete",
    ),
    path(
        "sources/<slug:source>/quotes/",
        view=QuoteListView.as_view(),
        name="quote_list",
    ),
    path(
        "sources/<slug:source>/quotes/add/",
        view=QuoteCreateView.as_view(),
        name="quote_create",
    ),
    path("quotes/<int:quote>/", view=QuoteDetailView.as_view(), name="quote_detail"),
    path(
        "quotes/<int:quote>/edit/", view=QuoteUpdateView.as_view(), name="quote_update"
    ),
    path(
        "quotes/<int:quote>/delete/",
        view=QuoteDeleteView.as_view(),
        name="quote_delete",
    ),
]


#!/usr/bin/python3
# -*- coding: utf-8 -*-

############# Isidro Rivera Monjaras ############
#############       28/02/2018       ############

from src.widgets import widgetsUse
#from src.inicio import ventanaInicio

class modCajas(widgetsUse):
  """docstring for cajas"""
  def __init__(self, db, widgetWinIni):
    super().__init__(gld="./gld/ventas.glade")
    self.db = db
    self.windowIni = widgetWinIni
    self.window = self.windows(nombre="window1")
    self.window.show_all()
    btSalirDat = {"nombre" : 'bt_salir',
                  "evento" : {"tipo" : 'clicked', "funcion" : self.salirCaja}}
    self.botonSalir = self.button(**btSalirDat)
    dicEntry = {"nombre":'e_precio', "tipo"  :'numerico', "set"   :'0.00'}
    dicEntry["nombre"] = 'e_precio'
    self.precio        = self.entry(**dicEntry)
    dicEntry["nombre"] = 'e_total'
    self.total         = self.entry(**dicEntry)
    dicEntry["nombre"] = 'e_pago'
    self.total         = self.entry(**dicEntry)
    dicEntry["nombre"] = 'e_cambio'
    self.total         = self.entry(**dicEntry)
    dicEntry = {"nombre":'e_cantidad', "tipo"  :'integer', "set"   :'0'}
    self.cantidad      = self.entry(**dicEntry)
    dicEntry["nombre"] = 'e_producto'
    self.idproducto    = self.entry(**dicEntry)
    self.window.set_focus(self.idproducto)

  def salirCaja(self, button, widgets):
    self.windowIni.show_now()
    self.window.destroy()


# coding: utf-8

"""
    DocuSign REST API

    The DocuSign REST API provides you with a powerful, convenient, and simple Web services API for interacting with DocuSign.  # noqa: E501

    OpenAPI spec version: v2.1
    Contact: devcenter@docusign.com
    Generated by: https://github.com/swagger-api/swagger-codegen.git
"""

import pprint
import re  # noqa: F401

import six

from docusign_esign.client.configuration import Configuration

class EnvelopePurgeConfiguration(object):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """

    """
    Attributes:
      swagger_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """
    swagger_types = {
        'purge_envelopes': 'str',
        'redact_pii': 'str',
        'remove_tabs_and_envelope_attachments': 'str',
        'retention_days': 'str'
    }

    attribute_map = {
        'purge_envelopes': 'purgeEnvelopes',
        'redact_pii': 'redactPII',
        'remove_tabs_and_envelope_attachments': 'removeTabsAndEnvelopeAttachments',
        'retention_days': 'retentionDays'
    }

    def __init__(self, _configuration=None, **kwargs):  # noqa: E501
        """EnvelopePurgeConfiguration - a model defined in Swagger"""  # noqa: E501
        if _configuration is None:
            _configuration = Configuration()
        self._configuration = _configuration

        self._purge_envelopes = None
        self._redact_pii = None
        self._remove_tabs_and_envelope_attachments = None
        self._retention_days = None
        self.discriminator = None

        setattr(self, "_{}".format('purge_envelopes'), kwargs.get('purge_envelopes', None))
        setattr(self, "_{}".format('redact_pii'), kwargs.get('redact_pii', None))
        setattr(self, "_{}".format('remove_tabs_and_envelope_attachments'), kwargs.get('remove_tabs_and_envelope_attachments', None))
        setattr(self, "_{}".format('retention_days'), kwargs.get('retention_days', None))

    @property
    def purge_envelopes(self):
        """Gets the purge_envelopes of this EnvelopePurgeConfiguration.  # noqa: E501

          # noqa: E501

        :return: The purge_envelopes of this EnvelopePurgeConfiguration.  # noqa: E501
        :rtype: str
        """
        return self._purge_envelopes

    @purge_envelopes.setter
    def purge_envelopes(self, purge_envelopes):
        """Sets the purge_envelopes of this EnvelopePurgeConfiguration.

          # noqa: E501

        :param purge_envelopes: The purge_envelopes of this EnvelopePurgeConfiguration.  # noqa: E501
        :type: str
        """

        self._purge_envelopes = purge_envelopes

    @property
    def redact_pii(self):
        """Gets the redact_pii of this EnvelopePurgeConfiguration.  # noqa: E501

          # noqa: E501

        :return: The redact_pii of this EnvelopePurgeConfiguration.  # noqa: E501
        :rtype: str
        """
        return self._redact_pii

    @redact_pii.setter
    def redact_pii(self, redact_pii):
        """Sets the redact_pii of this EnvelopePurgeConfiguration.

          # noqa: E501

        :param redact_pii: The redact_pii of this EnvelopePurgeConfiguration.  # noqa: E501
        :type: str
        """

        self._redact_pii = redact_pii

    @property
    def remove_tabs_and_envelope_attachments(self):
        """Gets the remove_tabs_and_envelope_attachments of this EnvelopePurgeConfiguration.  # noqa: E501

          # noqa: E501

        :return: The remove_tabs_and_envelope_attachments of this EnvelopePurgeConfiguration.  # noqa: E501
        :rtype: str
        """
        return self._remove_tabs_and_envelope_attachments

    @remove_tabs_and_envelope_attachments.setter
    def remove_tabs_and_envelope_attachments(self, remove_tabs_and_envelope_attachments):
        """Sets the remove_tabs_and_envelope_attachments of this EnvelopePurgeConfiguration.

          # noqa: E501

        :param remove_tabs_and_envelope_attachments: The remove_tabs_and_envelope_attachments of this EnvelopePurgeConfiguration.  # noqa: E501
        :type: str
        """

        self._remove_tabs_and_envelope_attachments = remove_tabs_and_envelope_attachments

    @property
    def retention_days(self):
        """Gets the retention_days of this EnvelopePurgeConfiguration.  # noqa: E501

          # noqa: E501

        :return: The retention_days of this EnvelopePurgeConfiguration.  # noqa: E501
        :rtype: str
        """
        return self._retention_days

    @retention_days.setter
    def retention_days(self, retention_days):
        """Sets the retention_days of this EnvelopePurgeConfiguration.

          # noqa: E501

        :param retention_days: The retention_days of this EnvelopePurgeConfiguration.  # noqa: E501
        :type: str
        """

        self._retention_days = retention_days

    def to_dict(self):
        """Returns the model properties as a dict"""
        result = {}

        for attr, _ in six.iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], item[1].to_dict())
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[attr] = value
        if issubclass(EnvelopePurgeConfiguration, dict):
            for key, value in self.items():
                result[key] = value

        return result

    def to_str(self):
        """Returns the string representation of the model"""
        return pprint.pformat(self.to_dict())

    def __repr__(self):
        """For `print` and `pprint`"""
        return self.to_str()

    def __eq__(self, other):
        """Returns true if both objects are equal"""
        if not isinstance(other, EnvelopePurgeConfiguration):
            return False

        return self.to_dict() == other.to_dict()

    def __ne__(self, other):
        """Returns true if both objects are not equal"""
        if not isinstance(other, EnvelopePurgeConfiguration):
            return True

        return self.to_dict() != other.to_dict()


import json
import cchardet as chardet
from .exceptions import Error
from .reader import VectorReader
from .convert import Converter

class EncodingError(Error):
    pass

def convert_to_geojson(filepath):
    filename = 'res.geojson'
    layers = []
    vr = VectorReader(filepath)
    converter = Converter('GeoJSON')
    for layer_num in range(len(vr)):
        tmp_dir = converter.convert_ds(vr.ds, filename, layer_num)
        layers.append(open(tmp_dir.file_list()[0]).read())
    return layers

def convert_to_geojson_data(filepath, encoding=None, unicode_errors='strict'):
    layers_geojson = []
    for json_str in convert_to_geojson(filepath):
        if encoding:
            try:
                json_str = unicode(json_str, encoding=encoding)
            except UnicodeDecodeError:
                raise EncodingError('could not decode file via specified encoding')
        else:
            try:
                json_str = unicode(json_str)
            except UnicodeDecodeError:
                detect = chardet.detect(json_str)
                if detect:
                    try:
                        json_str = unicode(json_str, encoding=detect.get('encoding'), errors=unicode_errors)
                    except UnicodeDecodeError:
                        raise EncodingError('file has unknown encoding')

        try:
            '''
            Decode one more time if we have double encoded utf-8 string. This may produced by utf-8 encoded shapefile w/o .cpg file.
            OGR default encoding for shapefile is ascii, so output geojson-file contains double utf-8 encoded string
            '''
            ascii = json_str.encode('latin1')
            detect = chardet.detect(ascii)
            if detect and detect.get('encoding').lower() == 'utf-8':
                json_str = ascii.decode('utf-8')
        except UnicodeEncodeError:
            pass

        layers_geojson.append(json.loads(json_str))
    return layers_geojson

def convert_to_merged_geojson_data(filepath):
    layers = convert_to_geojson_data(filepath)
    result = layers[0]
    for layer in layers[1:]:
        result['features'] = result['features'] + layer['features']
    return result


import numpy as np
import pygame

from common import window, colors
from simulation_box import SimulationBox, NODE_RADIUS

class NNSim(SimulationBox):
    def __init__(self, center=[460, 550], size=[800, 800]):
        super(NNSim, self).__init__(center, size)
        self.current_city = 0
        self.path = [0]
        self.search_radius = NODE_RADIUS

    def resetSimulation(self):
        self.current_city = 0
        self.path = [0]
        self.search_radius = NODE_RADIUS

    def performSimulationStep(self):
        if len(self.path) == self.cities.shape[0]:
            self.path.append(0)
            self.toggleSimulation(False, True)

        for i in range(len(self.path)):
            pygame.draw.circle(window, colors['Red'], self.cities[self.path[i]] + self.center, NODE_RADIUS)
            if i > 0:
                pygame.draw.line(window, colors['Red'], self.cities[self.path[i]] + self.center,
                                 self.cities[self.path[i - 1]] + self.center, 8)

        pygame.draw.circle(window, colors['Red'], self.cities[self.path[i]] + self.center, self.search_radius, 2)
        self.search_radius += self.simulation_speed_obj[0]

        for i in range(self.cities.shape[0]):
            if i not in self.path and np.linalg.norm(
                    self.cities[i] - self.cities[self.current_city]) < self.search_radius:
                self.path.append(i)
                self.current_city = i
                self.search_radius = NODE_RADIUS


import apprise
import yaml
import shutil
import os
import schedule
import time
import re
from os import path
from loguru import logger
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.common.exceptions import InvalidSessionIdException
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options

SCHEDULES=os.getenv("SCHEDULES")

class Crawler:
    def __init__(self):
        self.kids = []
        self.delay = 5
        self.ofek_url = "https://myofek.cet.ac.il/he"
        self.user_field = '//*[@id="HIN_USERID"]'
        self.password_field = '//*[@id="Ecom_Password"]'
        self.edu_login_btn = '//*[@id="loginButton2"]'
        self.todo = ""
        self.tofix = ""
        self.wating = ""
        self.checked = ""
        self.apobj = apprise.Apprise()
        self.notifires = os.getenv("NOTIFIERS")
        self.config_path = 'config/config.yaml'
        self.get_kids()

    #### Setting ChromeOptions ####
    def init_browser(self):
        logger.info("Initializing browser")
        self.options = webdriver.ChromeOptions()
        self.options.add_argument("-incognito")
        self.options.add_argument("--headless")
        self.options.add_argument("disable-gpu")
        self.options.add_argument("--no-sandbox")
        self.options.add_argument('--start-maximized')
        self.options.add_argument("--disable-dev-shm-usage")
        self.browser = webdriver.Chrome(executable_path=ChromeDriverManager(version='106.0.5249.61').install(), options=self.options)

    def init_notifires(self):
            if len(self.notifires)!=0:
                logger.debug("Setting Apprise notification channels")
                jobs=self.notifires.split()
                for job in jobs:
                    logger.debug("Adding: " + job)
                    self.apobj.add(job)

    def send_notification(self, title, message):
        if len(self.notifires)!=0:
            self.apobj.notify(
                body=message,
                title=title,
            )

    def get_kids(self):
        try:
            logger.info("Loading kids list")
            if not path.exists(self.config_path):
                shutil.copy('config.yaml', self.config_path)
            with open("config/config.yaml",'r',encoding='utf-8') as stream:
                try:
                    self.kids = yaml.safe_load(stream)
                except yaml.YAMLError as exc:
                    logger.error(exc)
        except Exception as e:
            logger.error(str(e))

    def crowl(self, username, password):
        logger.info("Crowling")
        try:

            # Open Ofek website
            self.browser.get(self.ofek_url)

            # Click the login button
            WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath",'//*[@id="header-toolbar_login-button"]'))).click()

            # Click edu.gov.il SSO buttin
            WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath",'/html/body/div[2]/div/div/div[1]/div[3]/div[2]/div/div/div/div[2]/div/div[1]/div'))).click()

            # Change to User/Pass auth type
            self.browser.get(self.browser.current_url.replace('EduCombinedAuthSms','EduCombinedAuthUidPwd'))

            # Enter Username
            WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath", self.user_field))).send_keys(username)

            # Enter Password
            WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath", self.password_field))).send_keys(password)

            # Click the login button
            self.browser.find_element("xpath",self.edu_login_btn).click()

            # Scrap tasks status
            logger.info("Scrapping...")
            self.todo = WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath",'/html/body/div[2]/div/div/div[3]/div[2]/div[1]/div[1]/div[1]/span'))).text
            self.tofix = WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath",'/html/body/div[2]/div/div/div[3]/div[2]/div[1]/div[2]/div/span'))).text
            self.checked = WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath",'/html/body/div[2]/div/div/div[3]/div[2]/div[1]/div[3]/div/span'))).text
            self.wating = WebDriverWait(self.browser, self.delay).until(EC.presence_of_element_located(("xpath",'/html/body/div[2]/div/div/div[3]/div[2]/div[1]/div[4]/div/span'))).text

        except Exception as e:
            logger.error(e)

def main():
    try:

        for kid in crawler.kids['kids']:
            if not kid['username'] or not kid['password'] or not kid['name']:
                logger.warning("Kids list is empty or not configured")
                break
            logger.info("Getting tasks for: " + kid["name"])
            crawler.init_browser()
            crawler.crowl(str(kid['username']),str(kid['password']))
            title = "מצב משימות אופק של " + kid['name']
            message = crawler.todo + "\n" + crawler.tofix + "\n" + crawler.checked + "\n" + crawler.wating
            if has_tasks(crawler.todo,crawler.tofix):
                crawler.send_notification(title,message)
            logger.debug("Closing browser")
            crawler.browser.quit()
    except Exception as e:
        logger.error(str(e))

def has_tasks(todo,tofix):
    todo_tasks = re.findall(r'\d+', todo)
    tofix_tasks = re.findall(r'\d+', tofix)
    return (int(todo_tasks[0]) > 0 or int(tofix_tasks[0]) > 0)

if __name__ == "__main__":
    try:
        crawler = Crawler()
        crawler.init_notifires()
        if not SCHEDULES:
            logger.debug("Setting default schedule to 16:00")
            schedule.every().day.at("16:00").do(main)
        else:
            for _schedule in SCHEDULES.split(','):
                logger.debug("Setting schedule to everyday at " + _schedule)
                schedule.every().day.at(_schedule).do(main)
        while True:
            schedule.run_pending()
            time.sleep(1)
    except Exception as e:
        logger.error(str(e))


from jsondiff import diff
import json

def assert_json(expected_json, current_json, allow_unexpected_fields=True, allow_missing_fields=False):

    if isinstance(expected_json, str):
        expected_json = json.loads(expected_json)

    if isinstance(current_json, str):
        current_json = json.loads(current_json)

    differences = json.loads(diff(expected_json, current_json, syntax='symmetric', dump=True))

    reserved_keynames = ["$delete", "$insert"]

    if not allow_missing_fields:
        if '$delete' in differences:
            raise ValueError('Some fields are missing')

    if not allow_unexpected_fields:
        if '$insert' in differences:
            raise ValueError('There are fields not expected')

    copied_differencies = differences.copy()

    for keyword in reserved_keynames:
        if keyword in copied_differencies:
            del copied_differencies[keyword]

    if len(copied_differencies) > 0:
        raise ValueError('Json documents doesn\'t match')


#!/usr/bin/env python

import argparse
import json
import sys

import matplotlib
import matplotlib.pyplot as plt

import numpy as np
import numpy.random as npr

#matplotlib.use('TkAgg')

parser = argparse.ArgumentParser(
    description="Run simulation of congestion under queue")
parser.add_argument(
    '--input', default=sys.stdin, type=argparse.FileType('r'),
    help="File to read JSON client measurements from")
args = parser.parse_args()

data = json.load(args.input)

params = data['SIM_PARAMS']

print(f"Base RTT: {params['BASE_RTT']}")
#print(f"Target RTT: {params['TARGET_RTT']}")
print(f"MU: {params['MU']}")

print()

delivered = []
losses = 0
mrtts = []
IQRs = []
rtt99 = []
avgTargets = []

for client in data['CLIENT_DATA']:
    if len(client['delivered']) > 0:
        delivered.append(client['delivered'][-1])
    else:
        delivered.append(0)

    if len(client['losses']) > 0:
        losses += client['losses'][-1]

    if len(client['rtt']) > 0:
        q1, q2, q3, q4 = np.quantile(client['rtt'], [1/4, 1/2, 3/4, 0.99])
        mrtts.append(q2)
        IQRs.append(q3 - q1)
        rtt99.append(q4)

    if len(client['targetRTT']) > 0:
        avgTargets.append(np.mean(client['targetRTT']))

delivered = np.array(delivered)
total = sum(delivered)*params['MSS']/data['RUNTIME']
fairness = sum(delivered)**2/(len(delivered)*sum(delivered**2))
print(f"Goodput: {total} = {100*total/params['MU']:.2f}% MU")
print(f"Jain Fairness: {fairness}")

print()

lossRate = np.sum(losses)*params['MSS']/data['RUNTIME']
print(f"Total Losses: {losses:.3e}")
print(f"Total Loss Rate: {lossRate:.3e} = {100*lossRate/params['MU']:.2f}% MU")

print()

print(f"Median of Client Median RTT: {np.median(mrtts)}")
print(f"Max of Client Median RTT: {np.max(mrtts)}")
print(f"Median of Client RTT IQRs: {np.median(IQRs)}")
print(f"Max of Client RTT IQRs: {np.max(IQRs)}")
print(f"Median of Client RTT 99th: {np.median(rtt99)}")
print(f"Max of Client RTT 99th: {np.max(rtt99)}")

print()

print(f"Median of Client Average Target RTT: {np.median(avgTargets)}")


import pygame
import pygame_widgets

#init GUI
pygame.init()
screen = pygame.display.set_mode((1000,600))
done = False

#light
labelLight = pygame_widgets.TextBox(
    screen,
    470, 20,
    200, 50,
    fontSize = 30,
    textColour = (255,255,255),
    colour = (0,0,0))
sliderLight = pygame_widgets.Slider(
    screen,
    100,100,
    800, 20,
    min = 0, max = 100,
    step = 1,
    handleRadius = 30,
    handleColour = ((252,244,3)) )
labelValueLight = pygame_widgets.TextBox(
    screen,
    475, 150,
    80, 50,
    fontSize = 30,
    textColour = (255,255,255),
    colour = (0,0,0))
labelLED = pygame_widgets.TextBox(
    screen,
    455, 200,
    100, 50,
    fontSize = 30,
    textColour = (207,206,194),
    colour = (0,0,0) )

#moisture
labelMoisture = pygame_widgets.TextBox(
    screen,
    450, 320,
    200, 50,
    fontSize = 30,
    textColour = (255,255,255),
    colour = (0,0,0))
sliderMoisture = pygame_widgets.Slider(
    screen,
    100,400,
    800, 20,
    min = 0, max = 100,
    step = 1,
    handleRadius = 30,
    handleColour = ((0,238,242)) )
labelValueMoisture = pygame_widgets.TextBox(
    screen,
    475, 450,
    80, 50,
    fontSize = 30,
    textColour = (255,255,255),
    colour = (0,0,0))
labelPump = pygame_widgets.TextBox(
    screen,
    455, 500,
    100, 50,
    fontSize = 30,
    textColour = (207,206,194),
    colour = (0,0,0) )

#setting
setting = {
    "light" : 50,
    "moisture" : 80
    }

while not done:
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            done = True
    #light
    labelLight.setText("Light")
    labelLight.draw()

    sliderLight.listen(events)
    lightValue = sliderLight.getValue()
    sliderLight.draw()

    labelValueLight.setText(lightValue)
    labelValueLight.draw()

    if(lightValue < setting["light"]):
        labelLED.setText("LED ON")
        labelLED.textColour = ((252,244,3))
    else:
        labelLED.setText("LED OFF")
        labelLED.textColour = ((207,206,194))
    labelLED.draw()

    #moisture
    labelMoisture.setText("Moisture")
    labelMoisture.draw()

    sliderMoisture.listen(events)
    moistureValue = sliderMoisture.getValue()
    sliderMoisture.draw()

    labelValueMoisture.setText(moistureValue)
    labelValueMoisture.draw()

    if(moistureValue < setting["moisture"]):
        labelPump.setText("Pump ON")
        labelPump.textColour = ((0,38,242))
    else:
        labelPump.setText("Pump OFF")
        labelPump.textColour = ((207,206,194))
    labelPump.draw()

    pygame.display.update()
    screen.fill((0,0,0))


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sumRootToLeaf(self, root: TreeNode) -> int:

        if not root:
            return 0

        numbers = []
        def traverse(root,num):
            nonlocal numbers
            if not root:
                return

            if not root.left and not root.right:
                numbers.append(num + str(root.val))
                return

            traverse(root.left,num + str(root.val))
            traverse(root.right,num + str(root.val))

        def func(num):
            return int(num,2)

        traverse(root,"")

        return sum(list(map(func,numbers)))


import tensorflow as tf
from tensorflow.python.keras.layers import Layer, Embedding

class TokenAndPositionEmbedding(Layer):
    """
    From: https://keras.io/examples/nlp/text_classification_with_transformer/
    """

    def __init__(self, input_max_len, embed_dim, vocab_size: int or None = None):
        super(TokenAndPositionEmbedding, self).__init__()
        self.input_max_len = input_max_len
        self.embed_dim = embed_dim
        self.vocab_size = vocab_size
        if vocab_size:
            self.token_emb = Embedding(input_dim=vocab_size, output_dim=embed_dim)
        self.pos_emb = Embedding(input_dim=input_max_len, output_dim=embed_dim)

    def call(self, inputs, **kwargs):
        positions = tf.range(start=0, limit=self.input_max_len, delta=1)
        positions = self.pos_emb(positions)
        if self.vocab_size:
            x = self.token_emb(inputs)
        else:
            x = inputs
        return x + positions


from engine import Engine, random_behaivor
from fed_object import MyObject
from sam_duel import brain_foo as sam_foo
from collections import Counter

def get_fed_foo():
    obj = MyObject(fullhp=3, nrays=10)
    def fed_foo(data: dict) -> dict:
        obj.update_info(data)
        behaivor = obj.get_behaivor()
        if not obj.rollback:
            obj.build_traj(behaivor)
        return behaivor
    return fed_foo

def main():
    from tqdm import tqdm
    score = Counter()
    for i in tqdm(range(1000)):
        im = Engine.get_sam_vs_fed(sam_brain_foo=sam_foo, fed_brain_foo=get_fed_foo())
        while not im.done:
            info = im.step(render=False)
        result = im.get_result()
        # print(result)
        score[result] += 1
    print(score)

def main2():
    im = Engine.get_sam_vs_fed(sam_brain_foo=sam_foo, fed_brain_foo=get_fed_foo())
    while not im.done:
        info = im.step(render=True)
    result = im.get_result()
    print(result)

if __name__ == '__main__':
    main2()


from rclpy.qos import QoSProfile
from rclpy.node import Node
from rclpy.action import ActionClient

from nav2_msgs.action import NavigateToPose

from sensor_msgs.msg import Joy
from geometry_msgs.msg import Twist, PoseStamped, Pose

from action_msgs.msg import GoalStatus

from rcl_interfaces.srv import SetParameters

import rclpy
import threading
import time

CONTROLLER_MSG = '''
---------------------------------------
               increase               -----------
               linear_x               |RB button| is emergency stop.
                 +---+                -----------
                 | △ |                |LB button| is Safety_button
   increase  +---+---+---+ decrease   -----------
   angular_z | ◁ |   | ▷ | agular_x   ----------------------
             +---+---+---+            |FollowWaypoints 1 button Y
                 | ▽ |                |FollowWaypoints 2 button X
                 -----                |FollowWaypoints 3 button B
                decrease              |FollowWaypoints 4 button A
                linear_x              ----------------------
---------------------------------------
Remote_joy Controller
Enjoy your Robot Control
---------------------------------------
'''

class JoyNav2Commander(Node, threading.Thread):
    def __init__(self, area_setting_path=None):
        rclpy.init()
        super().__init__('joy_nav2_commander')
        threading.Thread.__init__(self)

        qos_profile = QoSProfile(depth=10)
        self._joy_sub = self.create_subscription(Joy,     # joy 메세지 섭스크라이브
                                                 'joy',
                                                 self.joy_callback,
                                                 qos_profile)

        self._twist_pub = self.create_publisher(Twist,    # wist_mgs 퍼블리셔
                                                'turtle1/cmd_vel',   # 'turtle1/cmd_vel' 터틀심test
                                                qos_profile)

        self.button_move_pub_ = self.create_publisher(PoseStamped,   # PoseStamped 퍼블리셔 목표로 보내기 위한 퍼블리셔
                                                      '/goal_pose',
                                                      qos_profile)

        self.__qos_profile = QoSProfile(depth=10)
        self.srv_param = self.create_client(srv_type=SetParameters, # 클라이언트 생성
                                            srv_name='/controller_server/set_parameters',
                                            qos_profile=self.__qos_profile)

        self.action_client = ActionClient(self, action_type=NavigateToPose,  #네이게이션을 위한 포즈 메세지 생성
                                            action_name='/navigate_to_pose')

        self.sub_example_member_var = None

        self.setDaemon(True)
        self.tw = Twist

        self.__STATE_PUSHED = 1
        self.selected_command = None

        # nav2 action
        self.action_goal_handle = None
        self.action_result_future = None
        self.action_feedback = None
        self.action_status = None

        # joy stick 버튼 인덱스
        self.BUTTON_A = 0
        self.BUTTON_B = 1
        self.BUTTON_UNKWON_1 = 2
        self.BUTTON_X = 3
        self.BUTTON_Y = 4
        self.BUTTON_UNKWON_2 = 5
        self.BUTTON_LB = 6
        self.BUTTON_RB = 7
        self.BUTTON_LT = 8
        self.BUTTON_RT = 9
        self.BUTTON_BACK = 10
        self.BUTTON_START = 11
        self.BUTTON_XBOX = 12
        self.BUTTON_L3 = 13
        self.BUTTON_R3 = 14

        self.axes_value_list = [-0.0, -0.0, -0.0, -0.0, 1.0, 1.0, 0.0, 0.0]  # 버튼 입력상태 전의 초기값 정의

        self.__BUTTON_INDEX_LAST = self.BUTTON_R3

        self.button_a_status = False  # 버튼 초기화
        self.button_b_status = False
        self.button_unkwon_1_status = False
        self.button_x_status = False
        self.button_y_status = False
        self.button_unkwon_2_status = False
        self.button_lb_status = False
        self.button_rb_status = False
        self.button_lt_status = False
        self.button_rt_status = False
        self.button_back_status = False
        self.button_start_status = False
        self.button_xbox_status = False
        self.button_l3_status = False
        self.button_r3_status = False

        self.button_status_list = [self.button_a_status, #버튼 리스트 정의
                                   self.button_b_status,
                                   self.button_unkwon_1_status,
                                   self.button_x_status,
                                   self.button_y_status,
                                   self.button_unkwon_2_status,
                                   self.button_lb_status,
                                   self.button_rb_status,
                                   self.button_lt_status,
                                   self.button_rt_status,
                                   self.button_back_status,
                                   self.button_start_status,
                                   self.button_xbox_status,
                                   self.button_l3_status,
                                   self.button_r3_status]

        self.__button_name_list = ["BUTTON A", # 각 버튼의 이름 정의
                                   "BUTTON B",
                                   "BUTTON UNKWON 1",
                                   "BUTTON X",
                                   "BUTTON Y",
                                   "BUTTON UNKWON 2",
                                   "BUTTON LB",
                                   "BUTTON RB",
                                   "BUTTON LT",
                                   "BUTTON RT",
                                   "BUTTON BACK",
                                   "BUTTON START",
                                   "BUTTON XBOX",
                                   "BUTTON L3",
                                   "BUTTON R3"]

    def __del__(self):

        self.destroy_node()
        rclpy.shutdown()

    def joy_callback(self, joy_msg): # 버튼과 "joy"의 메세지를 받아서 인덱스에 있는 버튼값을 불러 옴

        axes_index = 0 # 조이스틱의 컨트롤 메세지
        for axes_value in joy_msg.axes:
            self.axes_value_list[axes_index] = axes_value
            axes_index += 1

        button_index = 0
        for button_status in joy_msg.buttons: # 반복문을 사용해서 버튼 값을 계속 받아옴
            if button_status is self.__STATE_PUSHED:
                print(self.__button_name_list[button_index] + " pushed!!")
                self.button_status_list[button_index] = True
            else:
                self.button_status_list[button_index] = False
            button_index += 1

    def example_sub_callback(self, msg):
        print(msg)
        print(msg.data)
        self.sub_example_member_var = msg.data

    def go_to_goal(self, goal_pose: list, orientation: list): #좌표값을 저장해두는 리스트
        # while self.action_client.wait_for_server(timeout_sec=1.0):
        #     print("wait navigate to pose action server...")
        #     time.sleep(1)

        print("목표로 이동을 시작합니다")
        goal_msg = NavigateToPose.Goal()
        to_pose_msg = PoseStamped()
        to_pose_msg.pose.position.x = goal_pose[0] # 리스트에 저장된 좌표(포즈 정보)를 가져옴
        to_pose_msg.pose.position.y = goal_pose[1]
        to_pose_msg.pose.position.z = goal_pose[2]
        to_pose_msg.pose.orientation.x = orientation[0]
        to_pose_msg.pose.orientation.y = orientation[1]
        to_pose_msg.pose.orientation.z = orientation[2]
        to_pose_msg.pose.orientation.w = orientation[3]
        goal_msg.pose = to_pose_msg

        future = self.action_client.send_goal_async(goal_msg, self.__navi_action_feedback_callback) # 클라이언트를 통해서 콜백으로 액션을 불러옴
        print("자리를 잡기 위하여 회전중")
        rclpy.spin_until_future_complete(self, future)
        print("회전중")
        self.action_goal_handle = future.result()
        if not self.action_goal_handle.accepted:
            print('목표도착에 실패 했습니다!')
            return False
        self.action_result_future = self.action_goal_handle.get_result_async()
        return True

    def cancel_move_to_goal(self): #목표로 이동중 목표를 취소하고자 할때
        try:
            print('현재 목표를 취소했습니다 ')
            if self.action_result_future:
                future = self.action_goal_handle.cancel_goal_async()
                rclpy.spin_until_future_complete(self, future=future, timeout_sec=3.0)
            return True
        except Exception as e:
            print(str(e))
            return False

    def is_move_to_goal_complete(self): # 목표 지점에 도착 하면 실행됨
        if not self.action_result_future:
            # task was cancelled or completed
            return True
        rclpy.spin_until_future_complete(self, self.action_result_future, timeout_sec=0.10)
        if self.action_result_future.result():
            self.action_status = self.action_result_future.result().status
            if self.action_status != GoalStatus.STATUS_SUCCEEDED:
                print('목표 도착에 실패했습니다.!!!: {0}'.format(self.action_status))
                return True
        else:
            # Timed out, still processing, not complete yet
            return False

        print(' 목표도착 성공!!! ')
        return True

    def __navi_action_feedback_callback(self, msg): # 액션 콜백 메세지
        self.feedback = msg.feedback
        return

    def get_go_to_goal_result(self):
        return self.action_status

    def run(self) -> None:
        self.node_main()
        # self.__is_alive = self.is_alive()
        # while self.__is_alive:

    def node_main(self):
        while True:
            time.sleep(1)

    def ros_spin_once(self):
        rclpy.spin_once(self)

if __name__ == '__main__':
    node_instance = JoyNav2Commander()
    node_instance.start()
    while True:
        node_instance.ros_spin_once()


# Questions 7 - 10 Multi-paradigm programming in Python

# 7a
import datetime
import math

import numpy as np

def sumImperative(list):
    sum = 0
    for number in list:
        sum = sum+number
    return sum

numLst = [1, 2, 3, 4, 5]
print(sumImperative(numLst))

# 7b
def evenNumbers():
    while (1):
        num = input("Give an input(number): ")

        if (int(num) % 2 == 0):
            print(num)
        elif (int(num) == 123):
            quit()
        else:
            print("Bye for now!")

# evenNumbers()

# Question 8

# 8a
data = [1, 2, 3, 4, 5]
add10 = lambda list: map(lambda num: num + 10, list)

print(list(add10(data)))

#8b
naturalNumbers = [0,1,2,3,4,5,6,7,8,9]
def getEvenNumbers(list):
    return filter(lambda x: x % 2 == 0, list)

print(list(getEvenNumbers(naturalNumbers)))

# Question 9

# 9a
def groupList(list, gLength):

    numOfLists = int(math.ceil(len(list) / gLength))
    resList = np.empty((numOfLists, gLength))
    counter = 0

    for i in range(numOfLists):
        for j in range(gLength):
            if len(list) > counter:
                resList[i][j] = list[counter]
                counter = counter+1

    return resList

list1 = [1,2,3,4,5,6]
res1 = groupList(list1, 2) # gives [ [1, 2], [3, 4], [5,6] ]
list2 = [1,2,3,4,5]
res2 = groupList(list2, 3) # gives [ [1, 2], [3, 4], [5,6] ]
print(res1)
print(res2)

# 9b
dkCities = ["Copenhagen", "Aarhus", "Aalborg", "Horsens", "Odense"]

def filterCities(cities: list): return filter(lambda city: city[:2] == "Aa", cities)

print(list(filterCities(dkCities)))

# Question 10

# 10a

class CourseNote():

    @property
    def jotting(self):
        return self.__jotting

    @jotting.setter
    def jotting(self, value):
        self.__jotting = value

    @property
    def creationDate(self):
        return self.__creationDate

    @creationDate.setter
    def creationDate(self, value: datetime.date):
        self.__creationDate = value

    @property
    def keywords(self):
        return self.__keywords

    @keywords.setter
    def keywords(self, value):
        self.__keywords = value

    def __init__(self, jotting, keywords):
        self.__jotting = jotting
        self.__keywords = keywords
        self.__creationDate = datetime.date.today()

    def isAmatch(self, searchFilter: str):
        return searchFilter in self.keywords or searchFilter in self.jotting

class Notebook():
    @property
    def courseNotes(self):
        return self.__courseNotes

    @courseNotes.setter
    def courseNotes(self, value: list[CourseNote]):
        self.__courseNotes = value

    def __init__(self):
        self.__courseNotes = []

    def search(self, strFilter: str):
        return filter(lambda note: note.isAmatch(strFilter) , self.courseNotes)

    def addNote(self, jotting: str, keywords: str):
        self.courseNotes.append(CourseNote(jotting, keywords))

course_note = CourseNote("This is a test jotting", "test")
print("Jotting:", course_note.jotting)
print("Keywords:", course_note.keywords)
print("Creation Date:", course_note.creationDate)

notebook = Notebook()
notebook.addNote("Another test jotting", "example")
notebook.addNote("This is a test jotting", "test")

search_results = notebook.search("test")
print("Search Results:")
for note in search_results:
    print("----------")
    print("Jotting:", note.jotting)
    print("Keywords:", note.keywords)
    print("Creation Date:", note.creationDate)
    print("----------")

# 10b
class Singer():
    def sing(self):
        print("kokot pica u holica chlpata ric a smradlava midza")

class SongWriter():
    def compose(self):
        print("pupu c pupu c, pupu c pupu c")

class SingerSongWriter(Singer, SongWriter):
    def strum(self):
        print("I'm so strumming wow")

    def actSensitive(self):
        print("Ah cmon man to co za picoviny trepes ty chod dopice skaredy si")

    def sing(self):
        Singer().sing()
        print("im singing some sensitive bullshit right now lalllalalala")

    def compose(self):
        SongWriter().compose()
        print("Maaan composing some sensitive stuff you know the blues and shit")

singer = Singer()
print("Singer is singing:")
singer.sing()

song_writer = SongWriter()
print("\nSongWriter is composing:")
song_writer.compose()

singer_song_writer = SingerSongWriter()
print("\nSingerSongWriter is singing:")
singer_song_writer.sing()
print("SingerSongWriter is composing:")
singer_song_writer.compose()
print("SingerSongWriter is strumming:")
singer_song_writer.strum()
print("SingerSongWriter is acting sensitive:")
singer_song_writer.actSensitive()


import sys

mymap = list(map(lambda s: s.strip(), sys.stdin.readlines()))

height = len(mymap)
width = len(mymap[0])

totals = []

def get_at(mymap, posx, posy):
    line = mymap[posy]
    return line[posx % width]

pats = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]
(patx, paty) = (3, 1)

for (patx, paty) in pats:
    total = 0
    (posx, posy) = (patx, paty)
    while posy < height:
        if get_at(mymap, posx, posy) == '#':
            total += 1
        posx += patx
        posy += paty

    totals.append(total)

product = 1

for total in totals:
    product *= total

print(totals)
print(product)


'''
Descripttion:
version:
Author: Yueyang
email: 1700695611@qq.com
Date: 2021-05-11 18:50:04
LastEditors: Yueyang
LastEditTime: 2021-05-11 19:11:07
'''
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
import glob
import matplotlib.pyplot as plt

#使用tf.data来读取数据集
#使用tf.keras来搭建网络

image_filenames=glob.glob("F:/SDK/TensorFlow/dogcat/img/*.jpg")  #读取train的所有图片，获取的图片的路径
#对路径进行乱序
image_filenames=np.random.permutation(image_filenames)

#此处lambda与map合用相当于：lambda函数用于指定对列表image_filenames中每一个元素的共同操作若==成立，表示当前标签为cat，label=1； 若当前标签为dog，则label=0。
train_labels = list(map(lambda x: float(x.split('\\')[1].split('.')[0] == 'cat'), image_filenames))
#这里的x其实就是后面的image_filenames(参考map函数和lambda函数的用法)

train_dataset=tf.data.Dataset.from_tensor_slices((image_filenames,train_labels)) #创建dataset

def _pre_read(image_filename,label):
    #读取图片
    image=tf.io.read_file(image_filename)
    #解码图片
    image=tf.image.decode_jpeg(image,channels=3)
    #转换图片的大小
    image=tf.image.resize(image,(200,200))
    image=tf.reshape(image,[200,200,3])
    #图片归一化
    image=image//255
    return image,label

train_dataset=train_dataset.map(_pre_read)   #对数据集进行图片预处理
train_dataset=train_dataset.shuffle(300)   #乱序
train_dataset=train_dataset.repeat()
train_dataset=train_dataset.batch(32)
#建立好网络之后，直接从dataset中取读取
#<BatchDataset shapes: ((None, 200, 200, 3), (None,)), types: (tf.float32, tf.float32)>
#创建模型
model=keras.Sequential()
model.add(layers.Conv2D(64,(3,3),activation="relu",input_shape=(200,200,3)))
model.add(layers.MaxPool2D(2,2))

model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPool2D(2,2))
model.add(layers.Dropout(0.5))

model.add(layers.GlobalAveragePooling2D())
model.add(layers.Dense(32,activation="relu"))
model.add(layers.Dense(1,activation="sigmoid"))

model.summary()

model.compile(optimizer="adam",loss="binary_crossentropy",metrics=["acc"])

#经过多少个step完成一个epoch，因为之前的数据集repeat()为无限次
train_step_per_epoch=len(image_filenames)//32
history=model.fit(train_dataset,epochs=30,steps_per_epoch=train_step_per_epoch)
history.history.keys()
plt.plot(history.epoch,history.history.get("loss"))
plt.plot(history.epoch,history.history.get("acc"))
print('SAVE MODEL!!!')
model.save('F:/SDK/TensorFlow/dogcat/train/model.h5')
print('SAVE MODEL SUCCESS!!!')


from cannlytics.traceability import metrc

# Initialize a Metrc API client.
track = metrc.authorize('your-vendor-api-key', 'your-user-api-key')

# Get a plant by it's ID.
plant = track.get_plants(uid='123')

# Change the growth phase from vegetative to flowering.
plant.flower(tag='your-plant-tag')

# Move the flowering plant to a new room.
plant.move(location_name='The Flower Room')

# Manicure useable cannabis from the flowering plant.
plant.manicure(harvest_name='Old-Time Moonshine', weight=4.20)

# Harvest the flowering plant.
plant.harvest(harvest_name='Old-Time Moonshine', weight=420)


#!/usr/bin/env python3

import hashlib
import json
import subprocess

from os import environ
from types import SimpleNamespace
from typing import List, Dict, Optional

class AppLifecycle(SimpleNamespace):
    """
    type: str
    buildpacks: List[str]
    stack: str
    """

    def as_dict(self) -> Dict:
        """Define how app lifecycles will be rendered as JSON."""
        return self.__dict__

class Droplet(SimpleNamespace):
    """
    buildpacks: List[Dict[str, str]]
    """

    def as_dict(self) -> Dict:
        """Define how droplets will be rendered as JSON."""
        return self.__dict__

class Service(SimpleNamespace):
    """
    label: str
    tags: List[str]
    name: str
    """

    def as_dict(self) -> Dict:
        """Define how services will be rendered as JSON."""
        return self.__dict__

class Env(SimpleNamespace):
    """
    vcap_services: List[Service]
    staging_env: List[str]
    running_env: List[str]
    """

    def as_dict(self) -> Dict:
        """Define how environment variables will be rendered as JSON."""
        return {
                "vcap_services": [service.as_dict() for service in self.vcap_services],
                "staging_env": self.staging_env,
                "running_env": self.running_env,
                }

class Process(SimpleNamespace):
    """
    command_fragments: List(str)
    """

    def as_dict(self) -> Dict:
        """Define how processes will be rendered as JSON."""
        return self.__dict__

class App(SimpleNamespace):
    """
    guid: str
    lifecycle: AppLifecycle
    current_droplet: Optional[Droplet] = None
    env: Optional[Env] = None
    process: Optional[Process] = None
    """

    def as_dict(self) -> Dict:
        """Define how Apps will be rendered as JSON."""
        return {
                "guid": _anonymize(self.guid),
                "lifecycle": self.lifecycle.as_dict(),
                "current_droplet": self.current_droplet.as_dict() if self.current_droplet else None,
                "env": self.env.as_dict() if self.env else None,
                "process": self.process.as_dict() if self.process else None,
                }

ALERT = """
====================================================================
 ALERT: You must target the desired environment with 'cf' CLI,
        logged in as an admin or admin_read_only user.
====================================================================
"""

# Number of resources to fetch per page on the API
PAGE_SIZE = 5000

# Environment variables to not anonymize (see below)
NO_ANON_VARS = [
        "BP_PIP_VERSION",  # used by Python Buildpack
        "CACHE_NUGET_PACKAGES",  # used by .NET Core Buildpack
        "EXTENSIONS",  # used by PHP Buildpack
        "GOVERSION",  # used by Go Buildpack
        "JBP_CONFIG_COMPONENTS",  # used by Java Buildpack
        "JBP_CONFIG_SPRING_AUTO_RECONFIGURATION",  # used by Java Buildpack
        "JBP_DEFAULT_COMPONENTS",  # used by Java Buildpack
        "NODE_ENV",  # used by Node.js Buildpack
        "WEBDIR",  # used by PHP Buildpack
        "WEB_CONCURRENCY",  # used by Node.js Buildpack
        "WEB_MEMORY",  # used by Node.js Buildpack
        "WEB_SERVER",  # used by PHP Buildpack
        ]

# Start command fragments to collect (see below)
COMMAND_FRAGMENTS = [
        "open_jdk_jre/bin/java ",
        "springframework.boot.loader.JarLauncher",
        "groovy/bin/groovy ",
        "spring_boot_cli/bin/spring run",
        "tomcat/bin/catalina.sh run",
        ]

# If set, anonymize environment variables from NO_ANON_VARS
ANON_BP_VARS = environ.get("ANON_BP_VARS")

# If set, anonymize nothing
BYPASS_ANON = environ.get("BYPASS_ANON")

def main():
    """Collect all visible STARTED apps, then fetch the current droplet,
    environment variables, and web process for each app. Render the resulting
    data as JSON and write to an output file in the current directory.
    """
    print(ALERT)
    all_apps = []
    try:
        all_apps = _fetch_apps(all_apps)
        if all_apps:
            all_apps = _fetch_droplets(all_apps)
            all_apps = _fetch_env(all_apps)
            all_apps = _fetch_processes(all_apps)
    except Exception as err:
        print("\n\n[Error] Encountered exception when collecting data:\n" + str(err) + "\nWriting partial output...\n")

    print("Generating output...")
    app_json = json.dumps([app.as_dict() for app in all_apps])

    print("Writing output...")
    with open("output.json", "w", encoding="utf-8") as output_file:
        output_file.writelines(app_json)

    print("Done!")

def _fetch_apps(all_apps: List[App]) -> List[App]:
    """Fetch the first page of apps from the API (via 'cf curl') and build a
    list of STARTED App objects containing guid and lifecycle. Then repeat for
    each page of apps, until there are no additional pages of apps.
    """
    print("[Step 1/4] Fetching started apps...")

    current_app_page = 1
    total_app_pages = "1"
    while True:
        print("Fetching apps page " + str(current_app_page) + "/" + str(total_app_pages), end="\r")
        parsed_apps_response = _cf_curl(
                "/v3/apps?per_page=" + str(PAGE_SIZE) + ";page=" + str(current_app_page),
                )

        _handle_errors(parsed_apps_response)
        apps_pagination = parsed_apps_response.get("pagination", {})
        total_app_pages = apps_pagination.get("total_pages", "?")

        apps = parsed_apps_response.get("resources", [])
        parsed_apps = [
            App(
                guid=app.get("guid", ""),
                lifecycle=_construct_lifecycle(app)
            )
            for app in apps
            if app.get("state", "") == "STARTED"
        ]
        all_apps = all_apps + parsed_apps

        current_app_page += 1

        if not apps_pagination.get("next", None):
            break

    print("\nFetched " + str(len(all_apps)) + " apps.\n")
    return all_apps

def _construct_lifecycle(app: Dict) -> AppLifecycle:
    """Convert API app dict into AppLifecycle object, containing lifecycle
    type, configured buildpacks, and stack.
    """
    lifecycle = app.get("lifecycle", {})
    return AppLifecycle(
            type=lifecycle.get("type", ""),
            buildpacks=lifecycle.get("data", {}).get("buildpacks", []),
            stack=lifecycle.get("data", {}).get("stack", ""),
            )

def _fetch_droplets(all_apps: List[App]) -> List[App]:
    """For each app, fetch that app's current droplet via
    '/v3/apps/:guid/droplets/current'. Use the resulting JSON to construct a
    Droplet object, containing the buildpacks detected during staging. Add the
    constructed Droplet object to the corresponding App object.
    """
    print("[Step 2/4] Fetching droplets...")
    for index, app in enumerate(all_apps):
        print("Fetching droplet " + str(index + 1) + "/" + str(len(all_apps)), end="\r")
        parsed_droplet_response = _cf_curl("/v3/apps/" + str(app.guid) + "/droplets/current")
        app.current_droplet = Droplet(buildpacks=parsed_droplet_response.get("buildpacks", []))
    print("\n")
    return all_apps

def _fetch_env(all_apps: List[App]) -> List[App]:
    """For each app, fetch that app's environment variables via
    '/v3/apps/:guid/env'. This will include app-level environment variables, in
    addition to environment variable groups and VCAP_SERVICES. Use the
    resulting JSON to construct an Env object containing these environment
    variables. Add the constructed Env object to the corresponding App object.
    """
    print("[Step 3/4] Fetching environment variables...")
    for index, app in enumerate(all_apps):
        print("Fetching env " + str(index + 1) + "/" + str(len(all_apps)), end="\r")
        parsed_env_response = _cf_curl("/v3/apps/" + str(app.guid) + "/env")
        app.env = _construct_env(parsed_env_response)
    print("\n")
    return all_apps

def _construct_env(env: Dict) -> Env:
    """Convert API env dict into Env object, containing environment variables
    from VCAP_SERVICES, staging environment variable groups, running
    environment variable groups, and environment variables configured directly
    on the app. Environment variables are merged by whether they are present at
    staging or running time. Most environment variables are anonymized, as
    described below.
    """
    vcap_services = env.get('system_env_json', {}).get('VCAP_SERVICES', {})
    staging_env_json = env.get('staging_env_json', {}) or {}
    running_env_json = env.get('running_env_json', {}) or {}
    environment_variables = env.get('environment_variables', {}) or {}
    staging_env = _flatten_variables(_merge(staging_env_json, environment_variables))
    running_env = _flatten_variables(_merge(running_env_json, environment_variables))
    return Env(
            vcap_services=_construct_services(vcap_services),
            staging_env=staging_env,
            running_env=running_env,
            )

def _construct_services(vcap_services: Optional[Dict]) -> List[Service]:
    """Collect name, label, and tags for each service binding in VCAP_SERVICES.
    All service fields are sha256-anonymized.
    """
    if vcap_services:
        all_services = []
        for bindings in vcap_services.values():
            for binding in bindings:
                all_services.append(
                    Service(
                        name=_anonymize(binding.get("name", "")),
                        label=_anonymize(binding.get("label", "")),
                        tags=_anonymize_list(binding.get("tags", [])),
                        )
                )
        return all_services
    else:
        return []

def _merge(base: dict, override: dict) -> dict:
    """Merge two dicts, overriding values from the first dict."""
    return {**base, **override}

def _flatten_variables(variables: Optional[Dict]) -> List[str]:
    """Convert environment variable dict into a list of strings.

    For most environment variables, only environment variable keys
    (NOT values) are collected in an sha256-anonymized list.

    A selection of buildpack-configuration environment variables
    (defined in NO_ANON_VARS, above) are NOT anonymized AND
    values are collected in addition to keys.

    The buildpack-configuration environment variables can be anonymized by
    setting the ANON_BP_VARS environment variable in the execution shell when
    running this script.
    """
    flattened_vars = []
    if variables:
        for key, val in variables.items():
            if ((not ANON_BP_VARS) and (key in NO_ANON_VARS)):
                flattened_vars.append(key + "=" + val)
            else:
                flattened_vars.append(_anonymize(key))
    return flattened_vars

def _anonymize_list(list_of_str: List[str]) -> List[str]:
    """Anonymize all strings in a list."""
    return [_anonymize(string) for string in list_of_str]

def _anonymize(string: str) -> str:
    """Anonymize a string by taking a sha256 digest of the string. The
    resulting anonymized string can NOT be converted back to the original
    string. However, known strings can be identified, because the digest will
    be the same.

    For example, the string "foo" always anonymizes into
    "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", so someone
    looking for "foo" could identify it by searching for the known digest.
    However, someone could NOT recover the string "foo" from the digest alone.

    If the BYPASS_ANON environment variable is set in the execution shell when
    running this script, then values will not be anonymized.
    """
    if BYPASS_ANON:
        return string
    return hashlib.sha256(bytes(string, "utf-8")).hexdigest()

def _fetch_processes(all_apps: List[App]) -> List[App]:
    """For each app, fetch that app's web process via
    '/v3/apps/:guid/processes/web'. Use the resulting JSON to construct a
    Process object, containing matching start command fragments. Add the
    constructed Process object to the corresponding App object.
    """
    print("[Step 4/4] Fetching processes...")
    for index, app in enumerate(all_apps):
        print("Fetching process " + str(index + 1) + "/" + str(len(all_apps)), end="\r")
        parsed_process_response = _cf_curl("/v3/apps/" + str(app.guid) + "/processes/web")
        app.process = _construct_process(parsed_process_response)
    print("\n")
    return all_apps

def _construct_process(process: Dict) -> Process:
    """Convert API process dict into Process object, containing matching start
    command fragments from COMMAND_FRAGMENTS, defined above. Only the matching
    start command fragments are recorded; the rest of the start command is NOT
    recorded.
    """
    command = process.get('command', "")
    matching_command_fragments = [fragment for fragment in COMMAND_FRAGMENTS if fragment in command]
    return Process(
            command_fragments=matching_command_fragments
            )

def _cf_curl(endpoint: str) -> dict:
    """Curl the API by shelling out to the cf CLI."""
    response_raw = subprocess.run(
        ["cf", "curl", endpoint],
        check=True,
        stdout=subprocess.PIPE,
        universal_newlines=True
    ).stdout
    return _parse_json(response_raw)

def _parse_json(raw_response: str) -> dict:
    """Parse API response JSON and return the resulting dict."""
    try:
        parsed_response = json.loads(raw_response)
        return parsed_response
    except Exception as err:
        print("\n[Error] Failed to parse:\n" + str(raw_response) + "\nas JSON.")
        raise err

def _handle_errors(parsed_response: dict) -> None:
    """Surface any errors returned from the API."""
    errors = parsed_response.get("errors", None)
    if errors:
        print("\nEncountered API errors: ")
        print(errors)

if __name__ == "__main__":
    main()


import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('./images/giraffe.jpg', cv2.IMREAD_GRAYSCALE)

# salt and pepper noise
noise = np.zeros(img.shape, np.uint8)
cv2.randu(noise, 0, 255)
black = noise < 10
white = noise > 245
img[black] = 0
img[white] = 255

# median filter
filtered = cv2.medianBlur(img, 5)

# Plot images
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))
ax1.imshow(img, cmap='gray', interpolation='nearest')
ax1.set_title('Salt and Pepper Noise')
ax1.set_xticks([])
ax1.set_yticks([])

ax2.imshow(filtered, cmap='gray', interpolation='nearest')
ax2.set_title('Median Filter')
ax2.set_xticks([])
ax2.set_yticks([])

plt.show()