import requests
import unittest
import json
import os
import datetime
import sys
import re
import hashlib

class A4AcceptanceTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.testURL = os.environ["url"] + "/2048"
        cls.userID = os.environ["id"]
        cls.userName = os.environ["name"]

    @classmethod
    def tearDownClass(cls):
        pass

    def microservice(self, theURL):
        '''Issue HTTP/HTTPS request and capture the JSON result'''
        try:
            theResponse = requests.get(theURL)
            theBody = theResponse.text
            theResult = {'statusCode': theResponse.status_code}
        except Exception as e:
            theResult['diagnostic1'] = str(e)
            theResult['statusCode'] = 999
            return theResult

        '''Convert JSON string to dictionary'''
        try:
            theJsonBody = theBody.replace("'", "\"")
            theDictionaryBody = json.loads(theJsonBody)
            for element in theDictionaryBody:
                if(isinstance(theDictionaryBody[element], str)):
                    theResult[str(element)] = str(theDictionaryBody[element])
                else:
                    theResult[str(element)] = theDictionaryBody[element]
        except Exception as e:
            theResult['diagnostic2'] = str(e)
        return theResult

#-------------------------------------------------------------------------------
# -- Acceptance tests for microservice deployment
#   test 010:   intent:  to ensure microservice has been deployed
#                 input: http://name-of-server.com/2048?op=create
#                 output: status code 200
    def testA4_2048_010_ShouldReturn200ResponseCode(self):
        theURL = self.testURL
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')

#-------------------------------------------------------------------------------
# -- Acceptance tests for op=create
# Interface Analysis
#    input:  dictionary consists of no parameter keys
#    output: dictionary consisting of the following keys:  grid, score, status, integrity
#        Happy path:
#            010:    ensure return of all keys
#            020:    ensure return of "ok" status value
#            030:    ensure return of accurate integrity value
#            040:    ensure return of 0 score value
#            050:    ensure grid has 2 '2' tiles, empty otherwise
#            060:    ensure randomness of '2' tiles
#            grid -> two 2 tiles places at random on otherwise empty grid
#            score -> 0
#            integrity -> SHA256 hex digest of grid + . + score
#            status -> "ok"
#        Sad path:
#            N/A
#
# Side-Effect Analysis
#    no side effects
#
# Acceptable level of risk:   BVA
# Happy Path Analysis

#   test 010:   intent:  op=create responds with dictionary with of requisite keys
#                 input: http://name-of-server.com/2048?op=create
#                 output:
#                     {'grid':'do not care',
#                      'score':'do not care'
#                      'integrity':'do not care',
#                      'status': 'do not care'}
    def testA4_create_010_ShouldReturnAllKeys(self):
        opString = '?op=create'
        theURL = self.testURL + opString
        expectedResult = {'grid':'',
                          'score':'',
                          'integrity':'',
                          'status': 0}
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')
        for key in expectedResult:
            self.assertIn(key, actualResult, f"key {key} is missing [major]")
        actualResultCount = len(actualResult) - 1  # decrement to account for statusCode
        expectedResultCount = len(expectedResult)
        self.assertEqual(expectedResultCount, actualResultCount, f'{actualResultCount} items returned, {expectedResultCount} expected')

#   test 020:   intent:  status = ok
#               input: http://name-of-server.com/2048?op=create
#               output: contains {'status':'ok')
    def testA4_create_020_ShouldReturnOkStatus(self):
        opString = '?op=create'
        theURL = self.testURL + opString
        expectedKey = 'status'
        expectedContent = 'ok'
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')
        self.assertIn(expectedKey, actualResult)
        self.assertEqual(actualResult.get(expectedKey, None), expectedContent)

#    test 030:  intent:  integrity is valid
#                input:  http://name-of-server.com/2048?op=create
#                output:  contains {'integrity':'xxx'}, where
#                    xxx = sha256(value of grid + "." + value of score)
    def testA4_create_030_ShouldReturnValidIntegrity(self):
        opString = '?op=create'
        theURL = self.testURL + opString
        print(theURL)
        expectedIntegrityKey = 'integrity'
        expectedGridKey = 'grid'
        expectedScoreKey = 'score'
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')
        actualGrid = actualResult.get(expectedGridKey, '')
        actualScore = str(actualResult.get(expectedScoreKey, ''))
        actualIntegrity = actualResult.get(expectedIntegrityKey, '')
        expectedHashString = actualGrid + "." + actualScore
        myHash = hashlib.sha256()
        myHash.update(expectedHashString.encode())
        expectedIntegrity = myHash.hexdigest().upper()
        self.assertEqual(expectedIntegrity, actualIntegrity, f'Integrity values do not match for {expectedHashString} [major]')

#    test 040:  intent:  score is an integer 0
#                input:  http://name-of-server.com/2048?op=create
#                output:  contains {'score':0}
#
    def testA4_create_040_ShouldReturnIntZeroScore(self):
        opString = '?op=create'
        theURL = self.testURL + opString
        expectedKey = 'score'
        expectedContent = '0'
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')
        self.assertIn(expectedKey, actualResult, f'score is missing')
        actualContent = str(actualResult.get(expectedKey, None))
        self.assertEqual(expectedContent, actualContent, f'Score is not set to 0')

#    test 050:  intent:  ensure grid has correct syntax
#                input:  http://name-of-server.com/2048?op=create
#                output:  'grid' consists of 14 '0' and 2 '2'
#                method:  run 16 times; the results should be consistent
#
    def testA4_create_050_ShouldReturnCorrectGridSyntax(self):
        opString = '?op=create'
        theURL = self.testURL + opString
        expectedKey = 'grid'
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')

        sampleSize = 31
        for _ in range(sampleSize):
            actualResult = self.microservice(theURL)
            actualGrid = actualResult.get(expectedKey, '')
            zeroCount = actualGrid.count('0')
            self.assertEqual(zeroCount, 14, f'{zeroCount} zero tiles discovered')
            twoCount = actualGrid.count('2')
            self.assertEqual(twoCount, 2, f'{twoCount} zero tiles discovered')

#    test 060:  intent:  ensure grid has random placement of '2' tiles
#                input:  http://name-of-server.com/2048?op=create
#                output:  'grid' consists of 14 '0' and 2 '2'
#                method:  run 16 times; the results should be consistent
#
    def testA4_create_060_ShouldReturnCorrectGridSyntax(self):
        GRID_SIZE = 16
        TWO_TILE_VALUE = 2
        TWO_TILES_ON_GRID = 2
        ZERO_TILE = 0
        SAMPLE_SIZE = 32
        P = 18.2  # Chi-Squared   df=15; alpha=0.75

        def uniformTest():
            population = [0 for _ in range(GRID_SIZE)]
            for _ in range(SAMPLE_SIZE):
                actualResult = self.microservice(theURL)
                actualStringGrid = actualResult.get(expectedKey, ZERO_TILE * GRID_SIZE)
                actualNumericGrid = [int(int(char) / TWO_TILE_VALUE) for char in actualStringGrid]
                for index in range(len(population)):
                    population[index] += actualNumericGrid[index]

            expected = TWO_TILES_ON_GRID / GRID_SIZE * SAMPLE_SIZE
            chiSquared = 0.0
            for cell in population:
                chiSquared += ((cell - expected) ** 2) / expected
            return chiSquared

        opString = '?op=create'
        theURL = self.testURL + opString
        expectedKey = 'grid'
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')

        uniformity = P ** 2
        for _ in range(5):
            try:
                chiSquared = uniformTest()
                if(P > chiSquared):
                    uniformity = chiSquared
                    break
                else:
                    uniformity = min(uniformity, chiSquared)
            except:
                uniformity = P ** 2
        self.assertGreater(P, uniformity, f'2s not uniformly distributed across grid')

#-------------------------------------------------------------------------------
# -- Acceptance tests for op=info
# Interface Analysis
#    input:  dictionary consists of no parameter keys
#    output: dictionary consisting of the userid key
#        Happy path:
#            userid -> username
#        Sad path:
#            N/A
#
# Side-Effect Analysis
#    no side effects
#
# Acceptable level of risk:   BVA
    def testA4_info_010_ShouldReturnUserid(self):
        opString = '?op=info'
        theURL = self.testURL + opString
        expectedResult = {'user': self.userID}
        actualResult = self.microservice(theURL)
        self.assertEqual(200 , actualResult['statusCode'], f'Microservice not accessible at {theURL} [major]')
        for key in expectedResult:
            self.assertIn(key, actualResult, f"key {key} is missing [major]")
        actualUserId = actualResult.get('user', None)
        self.assertEqual(actualUserId, self.userID)
        actualResultCount = len(actualResult) - 1  # decrement to account for statusCode
        expectedResultCount = len(expectedResult)
        self.assertEqual(expectedResultCount, actualResultCount, f'{actualResultCount} items returned, {expectedResultCount} expected')

if __name__ == "__main__":
    try:
        print(" ")
        print("@A4  " + os.environ["id"])
        print("      " + os.environ["name"])
        print("      " + os.environ["url"])
        print("      " + str(datetime.datetime.now()))
        print("+------------------------------------------------------------------")
    except:
        print("@A4  -- id/url not available")
        sys.exit()
    unittest.main()

COMP 5703 Software Process/rcube/Tiles2048/test/a4AcceptanceTest-1.py


import pywhatkit
import glob
from pywhatkit.core.core import copy_image
from pyautogui import hotkey, press, keyDown, keyUp
from time import sleep

numeros = []
with open('numeros.txt', 'r') as file:
    numeros = file.readlines()
    numeros = [n[:-1] for n in numeros]
with open('mensaje.txt', 'r') as file:
    mensaje = file.read()

imagenes = glob.glob('imagenes/*.jpeg')
for numero in numeros:
    pywhatkit.sendwhats_image(
        f"{numero}", imagenes.pop(0), f"{mensaje}", wait_time=45)
    for imagen in imagenes:
        copy_image(imagen)
        keyDown('ctrl')
        press('v')
        keyUp('ctrl')
        sleep(3)
    press('enter')
    print('closing tab...')
    sleep(10)
    keyDown('ctrl')
    press('w')
    keyUp('ctrl')
    sleep(2)
    press('enter')
    sleep(2)
    print('releasing keys...')


from django.conf.urls import url
from novels import views

app_name = 'novels'
urlpatterns = [
    # url(r'^variety/', include('novel.urls')),
    url(r'^category/(?P<variety>[a-zA-z]{3,8})/(?P<page>[0-9]*)',
        views.novels, name='novel_variety'),
    url(r'^info/(?P<novel_id>[0-9a-zA-Z]+)',
        views.novel_detail, name='novel_detail'),
    url(r'^catalogue/(?P<novel_id>[0-9a-zA-Z]+)/(?P<sort_by>(asc|desc)?)/(?P<chap_page>[0-9]+)',
        views.chapter_list, name='chapter_list'),
    # url(r'^users/(?P<type>login|register|[0-9a-zA-Z]+)$',
    #     views.login, name='user_login'),
    url(r'^search/$', views.search, name='search'),

]


# -*- coding: gbk -*-

# 默认生成文件路径
PATH = "./data/"
with open("config.ini", "r") as f:
	for s in f.readlines():
		lst = s.split("=")
		if lst[0] == "data_path":
			PATH = lst[1].strip()
	f.close()


from bs4 import BeautifulSoup
from asyncio.windows_events import NULL
from unicodedata import name
from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
import time
import requests

driver = webdriver.Firefox()

driver.get('https://www.premierleague.com/')
time.sleep(6)
accept_cookies = driver.find_element(By.XPATH,'/html/body/div[2]/div/div/div[1]/div[5]/button[1]')
accept_cookies.click()

# Seasons with their links
seasons_list = [{"season" : "2021/22", "url" : "https://www.premierleague.com/players?se=418&cl=-1"},
                {"season" : "2020/21", "url" : "https://www.premierleague.com/players?se=363&cl=-1"},
                {"season" : "2019/20", "url" : "https://www.premierleague.com/players?se=274&cl=-1"},
                {"season" : "2018/19", "url" : "https://www.premierleague.com/players?se=210&cl=-1"}]

season_format = ["2021/2022", "2020/2021", "2019/2020", "2018/2019"]

players_links = set()
for season in seasons_list:
    count = 0
    driver.get(season['url'])

    # Scroll down
    current_height = driver.execute_script("return document.body.scrollHeight")
    while True:
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") 	# Scroll step
        time.sleep(8) 	# Wait to load page
        try:
            new_height = driver.execute_script("return document.body.scrollHeight") # Calculate new scroll height
        except:
            print("Failed: ", new_height)
        if new_height == current_height: # Compare with last scroll height
            break
        current_height = new_height

    print("scorlled till",current_height)

    players = driver.find_element(By.CLASS_NAME, 'dataContainer').find_elements(By.TAG_NAME, 'tr')
    for player in players:
        [player_name, _, nationality] = player.find_elements(By.TAG_NAME, 'td')
        player_link = player_name.find_element(By.TAG_NAME,'a').get_attribute('href')
        players_links.add((player_name.text, nationality.text, player_link))
        count += 1
    print(season['season'], count)

print(len(players_links))

player_table = []
plays_for_table = []

limit = 10
did_not_work = []
no_bdate = []
count = 1
tot = len(players_links)
for player in players_links:
    print(count, '/', tot)
    count += 1
    trials = 0
    while trials < limit:
        try:
            driver.get(player[2])
            time.sleep(2)
            player_intro = driver.find_element(By.CLASS_NAME, 'playerIntro').find_elements(By.TAG_NAME, 'div')
            position = None
            for i in range(len(player_intro)):
                if player_intro[i].text.lower() == 'position':
                    position = player_intro[i+1].text
                    break
            data = driver.find_element(By.CLASS_NAME, 'personalLists')
            all_info = data.find_elements(By.TAG_NAME, 'li')
            height = weight = bdate = None
            for info in all_info:
                if len(info.text.split('\n')) < 2:
                    continue
                [label, value] = info.text.split('\n')
                if label.lower() == 'date of birth':
                    bdate = value.split(' ')[0]
                elif label.lower() == 'height':
                    height = int(value[:-2])
                elif label.lower() == 'weight':
                    weight = value
            if weight is None:
                response = requests.get(player[2])
                html_soup: BeautifulSoup = BeautifulSoup(response.content, 'html.parser')
                weightInfo = html_soup.find(class_="u-hide")
                if weightInfo is not None:
                    try:
                        weight = round(float(weightInfo.find(class_="info").text.replace('kg','')))
                    except:
                        weight = None
            if bdate is None:
                no_bdate.appned(player)
            player_dict = {
                'PlayerName' : player[0],
                'BirthDate' : bdate,
                'Weight' : weight,
                'Height' : height,
                'Position' : position,
                'Nationality' : player[1]
            }

            history = driver.find_element(By.CLASS_NAME, 'playerClubHistory').find_element(By.TAG_NAME, 'tbody')
            history_rows = history.find_elements(By.TAG_NAME, 'tr')
            for row in history_rows:
                if len(row.find_elements(By.TAG_NAME, 'td')) != 5:
                    continue
                [season_, club_, _, _, _] = row.find_elements(By.TAG_NAME, 'td')
                if season_.text in season_format:
                    plays_for_dict = {
                        'PlayerName' : player[0],
                        'BirthDate' : bdate,
                        'ClubName' : club_.text.replace(' (Loan)', '').replace('&', 'and').replace(' U21', '').replace(' (loan)', '').replace(' U18', ''),
                        'Season' : season_.text[:5] + season_.text[-2:]
                    }
                    print(plays_for_dict)
                    plays_for_table.append(plays_for_dict)

            player_table.append(player_dict)
            print(player_dict)
            break
        except:
            print('Trying', player[2], 'again.')
            trials += 1
            if trials == limit:
                did_not_work.append(player)

print('Did not work')
print(did_not_work)
print('No Birthdate')
print(no_bdate)
driver.close()

df_player = pd.DataFrame(player_table)
df_player.drop_duplicates(inplace = True, ignore_index = True)
df_player.to_csv(r'PlayerTable.csv', index = False)

df_plays_for = pd.DataFrame(plays_for_table)
df_plays_for.drop_duplicates(inplace = True, ignore_index = True)
df_plays_for.to_csv(r'PlaysForTable.csv', index = False)


#Example
# card_key = 5764801 #8
# door_key = 17807724 #11

card_key = 9232416
door_key = 14144084

value = 1
subject_number = 7
modulo=20201227

value = 1
for i in range(1,modulo):
    value = (value*subject_number) % modulo
    if value == card_key:
        card_loops = i
        break

encryption = 1
for i in range(0,card_loops):
    encryption = (encryption*door_key) % modulo
print("Answer is:",encryption)


"""Test fixtures for kernels."""

from typing import Dict

import numpy as np
import pytest

from probnum.quad.integration_measures import (
    GaussianMeasure,
    IntegrationMeasure,
    LebesgueMeasure,
)
from probnum.quad.kernel_embeddings import KernelEmbedding
from probnum.randprocs import kernels

# pylint: disable=unnecessary-lambda

@pytest.fixture(
    params=[pytest.param(seed, id=f"seed{seed}") for seed in range(1)],
    name="rng",
)
def fixture_rng(request):
    """Random state(s) used for test parameterization."""
    return np.random.default_rng(seed=request.param)

@pytest.fixture(
    params=[pytest.param(num_data, id=f"ndata{num_data}") for num_data in [1, 2, 20]],
    name="num_data",
)
def fixture_num_data(request) -> int:
    """Size of the dataset."""
    return request.param

@pytest.fixture(
    params=[
        pytest.param(input_dim, id=f"dim{input_dim}") for input_dim in [1, 2, 3, 5]
    ],
    name="input_dim",
)
def fixture_input_dim(request) -> int:
    """Input dimension of the covariance function."""
    return request.param

# Datasets
@pytest.fixture(name="x")
def fixture_x(input_dim: int, num_data: int, rng: np.random.Generator) -> np.ndarray:
    """Random data from a standard normal distribution."""
    return rng.normal(0, 1, size=(num_data, input_dim))

# Measures
@pytest.fixture(
    params=[
        pytest.param(diagonal, id="covdiag" if diagonal else "covfull")
        for diagonal in [True, False]
    ],
    name="cov_diagonal",
)
def fixture_diagonal(request) -> str:
    """Possible forms of the covariance matrix."""
    return request.param

@pytest.fixture(
    params=[pytest.param(name, id=name) for name in ["gauss", "lebesgue"]],
    name="measure_name",
)
def fixture_measure_names(request) -> str:
    """Pedestrian way to deal with integration measures."""
    return request.param

@pytest.fixture(name="measure_params")
def fixture_measure_params(
    measure_name: str,
    input_dim: int,
    cov_diagonal: bool,
    rng: np.random.Generator,
) -> Dict:
    params = {"name": measure_name}

    if measure_name == "gauss":
        # set up mean and covariance
        if input_dim == 1:
            mean = rng.normal(0, 1)
            cov = rng.uniform(0.5, 1.5)
        else:
            mean = rng.normal(0, 1, size=(input_dim, 1))
            if cov_diagonal:
                cov = np.diag(rng.uniform(0.5, 1.5, size=(input_dim,)))
            else:
                mat = rng.normal(0, 1, size=(input_dim, input_dim))
                cov = mat @ mat.T

        params["mean"] = mean
        params["cov"] = cov

    elif measure_name == "lebesgue":
        # set up bounds
        rv = rng.uniform(0, 1, size=(input_dim, 2))
        domain = (rv[:, 0] - 1.0, rv[:, 1] + 1.0)

        params["domain"] = domain
        params["normalized"] = True

    return params

@pytest.fixture(name="measure")
def fixture_measure(measure_params) -> IntegrationMeasure:
    """Measure."""
    name = measure_params.pop("name")

    if name == "gauss":
        return GaussianMeasure(**measure_params)
    elif name == "lebesgue":
        return LebesgueMeasure(**measure_params)
    raise NotImplementedError

# Kernels
@pytest.fixture(
    params=[
        pytest.param(kerndef, id=kerndef[0].__name__)
        for kerndef in [
            (kernels.ExpQuad, {"lengthscales": 1.25}),
        ]
    ],
    name="kernel",
)
def fixture_kernel(request, input_dim: int) -> kernels.Kernel:
    """Kernel / covariance function."""
    return request.param[0](**request.param[1], input_shape=(input_dim,))

# Kernel Embeddings
@pytest.fixture(name="kernel_embedding")
def fixture_kernel_embedding(
    request, kernel: kernels.Kernel, measure: IntegrationMeasure
) -> KernelEmbedding:
    """Set up kernel embedding."""
    return KernelEmbedding(kernel, measure)

# Test functions
@pytest.fixture(
    params=[
        pytest.param(fun, id=f"f={key}")
        for key, fun in {
            "x": lambda x: x,
            "x**2": lambda x: x**2,
            "sin(x)": lambda x: np.sin(x),
        }.items()
    ],
    name="f1d",
)
def fixture_f1d(request):
    """1D test function for BQ."""
    return request.param

# Matern kernels
@pytest.fixture(
    params=[
        pytest.param(matern_nu, id=f"nu={matern_nu}")
        for matern_nu in [0.5, 1.5, 2.5, 3.5]
    ],
    name="matern_nu",
)
def fixture_matern_nu(request) -> int:
    """Input dimension of the covariance function."""
    return request.param

@pytest.fixture(
    params=[
        pytest.param(matern_lengthscale, id=f"lengthscales={matern_lengthscale}")
        for matern_lengthscale in [0.8, 1.0, 1.25]
    ],
    name="matern_lengthscale",
)
def fixture_matern_lengthscale(request) -> int:
    """Input dimension of the covariance function."""
    return request.param

@pytest.fixture(name="matern_kernel")
def fixture_matern_kernel(
    request, input_dim: int, matern_nu: float, matern_lengthscale: float
) -> kernels.Kernel:
    """Set up Matern kernel."""
    return kernels.ProductMatern(
        input_shape=(input_dim,), nus=matern_nu, lengthscales=matern_lengthscale
    )


import ctypes, httpx, os, sys, time, urllib3
from colorama import Fore as F, init; init()
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from yaml import safe_load
ctypes.windll.kernel32.SetConsoleTitleW(f'aurora invite scraper v0.1')

if httpx.get("https://intuitiveen.github.io/invite-scraper/").text[3:-5] != "true":
    print(f'{F.RED}This application is globally disabled')
    time.sleep(5)
    sys.exit()

# invite file check & config initialization
invites_exists = os.path.isfile('invites.txt')
config_exist = os.path.isfile('config.yml')
if not invites_exists:
    file = open('invites.txt', 'x')
    file.close()
try:
    config = safe_load(open('config.yml', 'r', encoding='utf-8', errors='ignore'))
    auth_key = str(config['auth_key'])
    server_amount = int(config['server_amount'])
    website = str(config['website'])
    use_search_query = bool(config['use_search_query'])
    search_queries = list(config['search_queries'])
except Exception as e:
    print(f'{F.RED}Error: {e}')
    time.sleep(5)
    sys.exit()

# importing methods
from util.scrape import scrape

# checking auth key
# from util.auth import login

# if not login(auth_key):
#     print(f'{F.RED}Invalid authentication key!{F.RESET}')
#     time.sleep(5)
#     sys.exit()

if not use_search_query and website == "discordio":
    print(f'{F.RED}You must use queries with https://discord.io!{F.RESET}')
    time.sleep(5)
    sys.exit()

print(F.GREEN + """
 █████╗ ██╗   ██╗██████╗  ██████╗ ██████╗  █████╗
██╔══██╗██║   ██║██╔══██╗██╔═══██╗██╔══██╗██╔══██╗
███████║██║   ██║██████╔╝██║   ██║██████╔╝███████║
██╔══██║██║   ██║██╔══██╗██║   ██║██╔══██╗██╔══██║
██║  ██║╚██████╔╝██║  ██║╚██████╔╝██║  ██║██║  ██║
╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝""" + F.LIGHTMAGENTA_EX + """\n
            Discord Invite Scraper""" + F.BLUE + """
         https://discord.gg/4rHg2pyHjF""" + "\n" + F.RESET)
final_servers = []
print("Scraping...")
scrape(website, server_amount, use_search_query, search_queries)
print(F.GREEN + "Finished" + F.RESET)


import logging
import re
from pathlib import Path

import utils  # type: ignore

def run_gocover(path: Path) -> None:
    """Run gocover."""
    utils.execute_cmd("""""")

def extract_total_coverage(raw: str) -> int:
    """Extract total coverage."""
    tail_line = raw.splitlines()[-1]
    return int(float(tail_line.split("\t")[-1][:-1]))

def generate_url(coverage_pct: float) -> str:
    """Generate badge source URL."""
    color = "yellow"
    if coverage_pct == 100:
        color = "brightgreen"
    elif coverage_pct > 90:
        color = "green"
    elif coverage_pct > 70:
        color = "yellowgreen"
    elif coverage_pct > 50:
        color = "yellow"
    else:
        color = "orange"

    return f"https://img.shields.io/badge/coverage-{coverage_pct}%25-{color}"

def main() -> None:
    """Run."""
    root = Path(__file__).absolute().parents[1]
    path_readme = root / "README.md"
    path_coverage = root / "COVERAGE"
    placeholder_tag = "Code Coverage"
    regexp_pattern = rf"\[\!\[{placeholder_tag}\]\(.*\)\]\(.*\)"

    run_gocover(path_coverage)

    coverage = utils.read(path_coverage)

    coverage_pct = extract_total_coverage(coverage)

    badge_url = generate_url(coverage_pct)

    inpt = utils.read(path_readme)

    search = re.findall(regexp_pattern, inpt)

    if not search:
        raise Exception(f"No placeholder found in README.md. Add '[![{placeholder_tag}]()]()'.")

    placeholder_inject = f"[![{placeholder_tag}]({badge_url})]({badge_url})"

    out = re.sub(regexp_pattern, placeholder_inject, inpt)

    utils.write(out, path_readme)

if __name__ == "__main__":
    log = logging.getLogger("coverage-bump")

    try:
        main()
    except Exception as ex:  # pylint: disable=broad-except
        log.error(ex)


from replit import clear
#HINT: You can call clear() to clear the output in the console.
from art import logo
print(logo)
biding = {}
bidding_finished = False
def add_name_bid(bidding_record):
	hegest_bid = 0
	winner = ""
	for bidder in bidding_record:
		bid_amount = bidding_record[bidder]
		if bid_amount > hegest_bid:
			hegest_bid = bid_amount
			winner = bidder
	print(f"The winner is {winner} with a bid of ${hegest_bid}")

while not bidding_finished:
		name = input("What is your name? ")
		bid_price = int(input("what is your bit price $"))
		biding[name] = bid_price
		sould_continue = input("Are there are any other bidders? type yes or no")
		if sould_continue == "no":
			bidding_finished = True
			add_name_bid(biding)
		elif sould_continue == "yes":
			pass# clear()


import random
import copy
from abc import ABC, abstractmethod
from typing import Dict

class Solution(ABC):
    @abstractmethod
    def mutate(self):
        pass

    @abstractmethod
    def crossover(self, solution: 'Solution'):
        pass

    # @abstractmethod
    # def print_solution(self):
    #     pass

    @abstractmethod
    def fitness(self, constraints, seeded_solution):
        pass

    @abstractmethod
    def optimize(self, greater_constraints, seeded_solution):
        pass

    @abstractmethod
    def get_sol(self):
        pass

class MatrixSolution(Solution):
    def __init__(self, N):
        self.__N = N
        self.__solution = []
        base_permutation = list(range(1, N + 1))  # create list of [1,2,..,N]
        for i in range(N):
            base_permutation_copy = copy.deepcopy(base_permutation)
            random.shuffle(base_permutation_copy)
            self.__solution.append(base_permutation_copy)

    def optimize(self, greater_constraints, seeded_solution):
        """
         optimization -
         1. greater constraints in Row are met
         2. greater constraints in Col are met
         2. seeded solution constraints are met
         """
        sol_copy = copy.deepcopy(self)
        i = 0
        it = iter(greater_constraints)
        try:
            while i < sol_copy.__N:  # allowed up-to N optimization operations
                constraint = next(it)
                if not sol_copy.__greater_sign(constraint):
                    big, small = constraint
                    # make greater sign conform with row
                    if big[0] == small[0]:
                        temp = sol_copy.__solution[big[0] - 1][big[1] - 1]
                        sol_copy.__solution[big[0] - 1][big[1] - 1] = sol_copy.__solution[small[0] - 1][small[1] - 1]
                        sol_copy.__solution[small[0] - 1][small[1] - 1] = temp
                        i += 1
                    else:  # make greater sign conform with col  must swap 4 elements this time
                        swappable1 = sol_copy.__solution[big[0] - 1][big[1] - 1]
                        swappable2 = sol_copy.__solution[small[0] - 1][small[1] - 1]
                        # swap in the first row
                        swap2_idx = sol_copy.__solution[big[0] - 1].index(swappable2)
                        sol_copy.__solution[big[0] - 1][big[1] - 1] = swappable2
                        sol_copy.__solution[big[0] - 1][swap2_idx] = swappable1
                        # swap in the second row
                        swap1_idx = sol_copy.__solution[small[0] - 1].index(swappable1)
                        sol_copy.__solution[small[0] - 1][small[1] - 1] = swappable1
                        sol_copy.__solution[small[0] - 1][swap1_idx] = swappable2
                        i += 1

        except StopIteration:
            for k in range(sol_copy.__N):
                for j in range(sol_copy.__N):
                    if i >= sol_copy.__N:
                        break
                    seed = seeded_solution.__solution[k][j]
                    if seed != 0 and sol_copy.__solution[k][j] != seed:
                        # swap places with where seed is supposed to be
                        idx = sol_copy.__solution[k].index(seed)
                        temp = sol_copy.__solution[k][j]
                        sol_copy.__solution[k][j] = sol_copy.__solution[k][idx]
                        sol_copy.__solution[k][idx] = temp
                        i += 1
                if i >= sol_copy.__N:
                    break
        return sol_copy

    def mutate(self):
        """
        picks a random row to mutate and swap two random elements
        :return copy of current Solution after swapping
        """
        sol_copy = copy.deepcopy(self)
        N = len(self.__solution)
        row = random.choice(range(N))
        cols = random.sample(range(N), 2)  # pick two indexes from that row to be swapped
        temp = sol_copy.__solution[row][cols[0]]
        sol_copy.__solution[row][cols[0]] = sol_copy.__solution[row][cols[1]]
        sol_copy.__solution[row][cols[1]] = temp
        # sol_copy._conform_seed()
        return sol_copy

    def crossover(self, solution: 'MatrixSolution'):
        """
        picks a random row - R.
        Append to grid3 all rows from grid1 until R and all rows from grid2 from R until the end
        :return copy of current Solution after swapping
        """
        sol_copy = copy.deepcopy(self)
        N = len(self.__solution)
        row = random.randint(0, N - 1)
        new_sol = self.__solution[:row]
        new_sol += solution.__solution[row:]
        sol_copy.__solution = new_sol
        # sol_copy._conform_seed()
        return sol_copy

    def __consistent(self, solution):
        """ returns num of diff elements in each row. Best case is 0 when each row is a permutation """
        return sum(self.__N - len(set(row)) for row in solution)

    def __compare_to_seed(self, seeded_solution: 'MatrixSolution'):
        """ count number of mismatches between initial seeded solution with current solution """
        count = 0
        for seed_row, row in zip(seeded_solution.__solution, self.__solution):
            for x_sr, x_r in zip(seed_row, row):
                if x_sr:  # when x_sr == 0 -> no seed
                    if x_sr != x_r:  # mismatch
                        count += 1
        return count

    def fitness(self, greater_constraints, seeded_solution):
        """ our fitness func sums up all miss matches in a given solution """
        # calc diff elements in each ROW
        fit = self.__consistent(self.__solution)
        # calc diff elements in each COL
        fit += self.__consistent(zip(*self.__solution))
        # calc diff from seed (given digits)
        fit += self.__compare_to_seed(seeded_solution)
        # calc diff greater sign
        fit += self._eval_greater_constraints(greater_constraints)
        return fit

    def _eval_greater_constraints(self, constraints):
        """ returns number of satisfied constraints """
        count = 0
        for constraint in constraints:
            if not self.__greater_sign(constraint):
                count += 1
        return count

    def __greater_sign(self, constraint):
        big, small = constraint
        return self.__solution[big[0] - 1][big[1] - 1] > self.__solution[small[0] - 1][small[1] - 1]

    def get_sol(self):
        return self.__solution

    @classmethod
    def get_seeded_solution(cls, N, seeds):
        sol = cls(N)
        sol.__solution = [[0 for j in range(N)] for i in range(N)]
        for seed in seeds:
            i, j, num = seed
            sol.__solution[i - 1][j - 1] = num
        return sol

class SolutionFactory(ABC):
    @abstractmethod
    def generate_random_solution(self, N) -> Solution:
        pass
    @abstractmethod
    def generate_seeded_solution(self, N, seeds) -> Solution:
        pass

class MatrixSolutionFactory(SolutionFactory):

    def generate_random_solution(self, N) -> MatrixSolution:
        return MatrixSolution(N)

    def generate_seeded_solution(self, N, seeds) -> MatrixSolution:
        return MatrixSolution.get_seeded_solution(N, seeds)

class FutoshikiPuzzle:
    def __init__(self, N, greater_constraints, seed_constraints, factory: SolutionFactory):
        self.__board_size = N
        self.__greater_constraints = greater_constraints
        self.__seed_constraints = seed_constraints
        self.__factory = factory
        self.__seeded_solution = factory.generate_seeded_solution(self.__board_size, self.__seed_constraints)

    def get_max_constraints(self):
        """ :returns num of constraints to be met.
         i.e each row and column is a permutation + initial board values + greater signs """
        return self.__board_size * (self.__board_size - 1) * 2 \
               + len(self.__greater_constraints) + len(self.__seed_constraints)

    def fitness_func(self, solution: Solution):
        return solution.fitness(self.__greater_constraints, self.__seeded_solution)

    def optimization_func(self, solution: Solution):
        return solution.optimize(self.__greater_constraints, self.__seeded_solution)

    def is_terminal_state(self, score):
        return score == 0

    def get_random_solution(self) -> Solution:
        return self.__factory.generate_random_solution(self.__board_size)

    def get_best_worst_avg_score(self, population_to_score: Dict[Solution, int]):
        """ simple util func to save data for plotting """
        best_score = self.get_max_constraints()  # being best means close to 0
        worst_score = 0  # being worst means close to num constraints
        sum = 0
        for score in population_to_score.values():
            if score < best_score:
                best_score = score
            if score > worst_score:
                worst_score = score
            sum += score
        return best_score, worst_score, sum / len(population_to_score)

    def print_solution(self, solution: Solution):
        N = len(solution.get_sol())
        # create the extra rows for pretty printing
        new_rows = [['     ' for j in range(N)] for i in range(N-1)]
        for big, small in self.__greater_constraints:
            if big[1] == small[1]:  # same column
                if big[0] < small[0]:  # sign should be V
                    new_rows[big[0] - 1][big[1] - 1] = '  v  '
                else:
                    new_rows[small[0] - 1][small[1] - 1] = '  ˄  '

        solution_to_print = solution.get_sol()

        print(7 * N * "*" + "*")
        for i in range(N):
            print("|", end=' ')
            for j in range(N):
                if j == N - 1:
                    print(str(solution_to_print[i][j]) + " ", end='|\n')
                else:
                    if ((i+1,j+2),(i+1,j+1)) in self.__greater_constraints:
                        print(str(solution_to_print[i][j]) + " | < |", end=' ')
                    elif ((i+1,j+1),(i+1,j+2)) in self.__greater_constraints:
                        print(str(solution_to_print[i][j]) + " | > |", end=' ')
                    else:
                        print(str(solution_to_print[i][j]) + " |   |", end=' ')
            if not i == N-1:
                for k in range(N):
                    if k == N - 1:
                        print(new_rows[i][k], end='\n')
                    else:
                        print(new_rows[i][k], end='   ')

        print(7 * N * "*" + "*")


#!/usr/bin/env python3

#####################################################################
# This script presents how to play a deathmatch game with built-in bots.
#####################################################################

import itertools as it
import os
import random
from collections import deque
from time import sleep, time

import numpy as np
import skimage.transform
import torch
import torch.nn as nn
import torch.optim as optim
import vizdoom as vzd
from tqdm import trange

from Agents.DQN import DQNAgent
import rewards

# Q-learning settings
learning_rate = 0.00025
discount_factor = 0.99
train_epochs = 1
learning_steps_per_epoch = 2000
replay_memory_size = 10000

# NN learning settings
batch_size = 64

# Training regime
test_episodes_per_epoch = 100

# Other parameters
frame_repeat = 4
resolution = (30, 45)
episodes_to_watch = 10

model_savefile = "./model-doom.pth"
save_model = True
load_model = False
skip_learning = False

if torch.cuda.is_available():
    DEVICE = torch.device("cuda")
    torch.backends.cudnn.benchmark = True
else:
    DEVICE = torch.device("cpu")

def preprocess(img):
    """Down samples image to resolution"""
    img = skimage.transform.resize(img, resolution)
    img = img.astype(np.float32)
    img = np.expand_dims(img, axis=0)
    return img

# class DuelQNet(nn.Module):
#     """
#     This is Duel DQN architecture.
#     see https://arxiv.org/abs/1511.06581 for more information.
#     """

#     def __init__(self, available_actions_count):
#         super().__init__()
#         self.conv1 = nn.Sequential(
#             nn.Conv2d(1, 8, kernel_size=3, stride=2, bias=False),
#             nn.BatchNorm2d(8),
#             nn.ReLU(),
#         )

#         self.conv2 = nn.Sequential(
#             nn.Conv2d(8, 8, kernel_size=3, stride=2, bias=False),
#             nn.BatchNorm2d(8),
#             nn.ReLU(),
#         )

#         self.conv3 = nn.Sequential(
#             nn.Conv2d(8, 8, kernel_size=3, stride=1, bias=False),
#             nn.BatchNorm2d(8),
#             nn.ReLU(),
#         )

#         self.conv4 = nn.Sequential(
#             nn.Conv2d(8, 16, kernel_size=3, stride=1, bias=False),
#             nn.BatchNorm2d(16),
#             nn.ReLU(),
#         )

#         self.state_fc = nn.Sequential(nn.Linear(96, 64), nn.ReLU(), nn.Linear(64, 1))

#         self.advantage_fc = nn.Sequential(
#             nn.Linear(96, 64), nn.ReLU(), nn.Linear(64, available_actions_count)
#         )

#     def forward(self, x):
#         x = self.conv1(x)
#         x = self.conv2(x)
#         x = self.conv3(x)
#         x = self.conv4(x)
#         x = x.view(-1, 192)
#         x1 = x[:, :96]  # input for the net to calculate the state value
#         x2 = x[:, 96:]  # relative advantage of actions in the state
#         state_value = self.state_fc(x1).reshape(-1, 1)
#         advantage_values = self.advantage_fc(x2)
#         x = state_value + (
#             advantage_values - advantage_values.mean(dim=1).reshape(-1, 1)
#         )

#         return x

# class DQNAgent:
#     def __init__(
#         self,
#         action_size,
#         memory_size,
#         batch_size,
#         discount_factor,
#         lr,
#         load_model,
#         epsilon=1,
#         epsilon_decay=0.9996,
#         epsilon_min=0.1,
#     ):
#         self.action_size = action_size
#         self.epsilon = epsilon
#         self.epsilon_decay = epsilon_decay
#         self.epsilon_min = epsilon_min
#         self.batch_size = batch_size
#         self.discount = discount_factor
#         self.lr = lr
#         self.memory = deque(maxlen=memory_size)
#         self.criterion = nn.MSELoss()

#         if load_model:
#             print("Loading model from: ", model_savefile)
#             self.q_net = torch.load(model_savefile)
#             self.target_net = torch.load(model_savefile)
#             self.epsilon = self.epsilon_min

#         else:
#             print("Initializing new model")
#             self.q_net = DuelQNet(action_size).to(DEVICE)
#             self.target_net = DuelQNet(action_size).to(DEVICE)

#         self.opt = optim.SGD(self.q_net.parameters(), lr=self.lr)

#     def get_action(self, state):
#         if np.random.uniform() < self.epsilon:
#             return random.choice(range(self.action_size))
#         else:
#             state = np.expand_dims(state, axis=0)
#             state = torch.from_numpy(state).float().to(DEVICE)
#             action = torch.argmax(self.q_net(state)).item()
#             return action

#     def update_target_net(self):
#         self.target_net.load_state_dict(self.q_net.state_dict())

#     def append_memory(self, state, action, reward, next_state, done):
#         self.memory.append((state, action, reward, next_state, done))

#     def train(self):
#         batch = random.sample(self.memory, self.batch_size)
#         batch = np.array(batch, dtype=object)

#         states = np.stack(batch[:, 0]).astype(float)
#         actions = batch[:, 1].astype(int)
#         rewards = batch[:, 2].astype(float)
#         next_states = np.stack(batch[:, 3]).astype(float)
#         dones = batch[:, 4].astype(bool)
#         not_dones = ~dones

#         row_idx = np.arange(self.batch_size)  # used for indexing the batch

#         # value of the next states with double q learning
#         # see https://arxiv.org/abs/1509.06461 for more information on double q learning
#         with torch.no_grad():
#             next_states = torch.from_numpy(next_states).float().to(DEVICE)
#             idx = row_idx, np.argmax(self.q_net(next_states).cpu().data.numpy(), 1)
#             next_state_values = self.target_net(next_states).cpu().data.numpy()[idx]
#             next_state_values = next_state_values[not_dones]

#         # this defines y = r + discount * max_a q(s', a)
#         q_targets = rewards.copy()
#         q_targets[not_dones] += self.discount * next_state_values
#         q_targets = torch.from_numpy(q_targets).float().to(DEVICE)

#         # this selects only the q values of the actions taken
#         idx = row_idx, actions
#         states = torch.from_numpy(states).float().to(DEVICE)
#         action_values = self.q_net(states)[idx].float().to(DEVICE)

#         self.opt.zero_grad()
#         td_error = self.criterion(q_targets, action_values)
#         td_error.backward()
#         self.opt.step()

#         if self.epsilon > self.epsilon_min:
#             self.epsilon *= self.epsilon_decay
#         else:
#             self.epsilon = self.epsilon_min

def run(game, agent, actions, episodes, bots, num_epochs, frame_repeat, steps_per_epoch):

    last_frags = 0
    prev_item = 0
    train_scores = []

    for i in range(episodes):

        print("Episode #" + str(i + 1))

        # Add specific number of bots
        # (file examples/bots.cfg must be placed in the same directory as the Doom executable file,
        # edit this file to adjust bots).
        game.send_game_command("removebots")
        for i in range(bots):
            game.send_game_command("addbot")

        # Play until the game (episode) is over.

        # Initialize new reward
        reward = 0
        while not game.is_episode_finished():

            # Get the state.
            state = game.get_state()

            # Analyze the state.

            # Make your action.
            #game.make_action(choice(actions))
            state = preprocess(game.get_state().screen_buffer)
            best_action_index = agent.get_action(state)

            reward = game.make_action(actions[best_action_index], frame_repeat)

            reward += rewards.frag_reward(game, 100, last_frags)
            prev_frag = game.get_game_variable(vzd.GameVariable.FRAGCOUNT)

            reward += rewards.item_reward(game, 20, prev_item)
            prev_item  = game.get_game_variable(vzd.GameVariable.ITEMCOUNT)

            next_state = preprocess(game.get_state().screen_buffer)
            # Update agent rewards
            agent.append_memory(state, actions, reward, next_state, game.is_episode_finished())

            frags = game.get_game_variable(vzd.GameVariable.FRAGCOUNT)
            if frags != last_frags:
                last_frags = frags
                print("Player has " + str(frags) + " frags.")

            items = game.get_game_variable(vzd.GameVariable.ITEMCOUNT)
            if items != prev_item:
                prev_item = items
                print("Player has " + str(items) + " items.")

            # Check if player is dead
            if game.is_player_dead():
                print("Player died.")
                # Use this to respawn immediately after death, new state will be available.
                game.respawn_player()

        print("Episode finished.")
        print("************************")

        print("Results:")
        server_state = game.get_server_state()
        for i in range(len(server_state.players_in_game)):
            if server_state.players_in_game[i]:
                print(
                    server_state.players_names[i]
                    + ": "
                    + str(server_state.players_frags[i])
                )
        print("************************")

        # Starts a new episode. All players have to call new_episode() in multiplayer mode.
        train_scores.append(game.get_total_reward() + reward)
        game.new_episode()

        agent.update_target_net()

        train_scores = np.array(train_scores)

        print(
            "Results: mean: {:.1f} +/- {:.1f},".format(
                train_scores.mean(), train_scores.std()
            ),
            "min: %.1f," % train_scores.min(),
            "max: %.1f," % train_scores.max(),
        )

    if save_model:
        print("Saving the network weights to:", model_savefile)
        torch.save(agent.q_net, model_savefile)

    return agent, game

if __name__ == "__main__":
    game = vzd.DoomGame()

    # Use CIG example config or your own.
    game.load_config(os.path.join(vzd.scenarios_path, "multiplayer_with_bots.cfg"))

    game.set_doom_map("map01")  # Limited deathmatch.
    #game.set_doom_map("map02")  # Full deathmatch.

    # Start multiplayer game only with your AI
    # (with options that will be used in the competition, details in cig_mutliplayer_host.py example).
    game.add_game_args(
        "-host 1 -deathmatch +timelimit 10.0 "
        "+sv_forcerespawn 1 +sv_noautoaim 1 +sv_respawnprotect 1 +sv_spawnfarthest 1 +sv_nocrouch 1 "
        "+viz_respawn_delay 10 +viz_nocheat 1"
    )

    # Bots are loaded from file, that by default is bots.cfg located in the same dir as ViZDoom exe
    # Other location of bots configuration can be specified by passing this argument
    game.add_game_args("+viz_bots_path ../../scenarios/perfect_bots.cfg")

    # Name your agent and select color
    # colors: 0 - green, 1 - gray, 2 - brown, 3 - red, 4 - light gray, 5 - light brown, 6 - light red, 7 - light blue
    game.add_game_args("+name AI +colorset 0")

    game.set_mode(vzd.Mode.PLAYER)
    game.set_console_enabled(True)

    # game.set_window_visible(False)

    game.init()

    # Three example sample actions
    actions = [
        [1, 0, 0, 0, 0, 0, 0, 0],
        [0, 1, 0, 0, 0, 0, 0, 0],
        [0, 0, 1, 0, 0, 0, 0, 0],
        [0, 0, 0, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0, 0, 1, 0],
        [0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 1, 0, 0, 0, 0, 0],
        [1, 0, 0, 1, 0, 0, 0, 0]
    ]
    last_frags = 0

    # Play with this many bots
    bots = 7

    # Run this many episodes
    episodes = 10

    # Instantiate DQNAgent
    agent = DQNAgent(
        len(actions),
        lr=learning_rate,
        batch_size=batch_size,
        memory_size=replay_memory_size,
        discount_factor=discount_factor,
        load_model=load_model,
    )

    agent, game = run(
        game,
        agent,
        actions,
        episodes,
        bots,
        5,
        frame_repeat,
        25200
    )

    game.close()


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

"""Test Logger class."""

import logging
import pytest

from frambo.logger import Logger

logger = logging.getLogger(__name__)

class TestLogger(object):
    """Test Logger class."""

    @pytest.mark.parametrize(
        "msg, args, fmsg",
        [
            ("hello %s", ("beautiful",), "hello beautiful"),
            (u"čau", tuple(), u"čau"),
            (b"\xc4\x8dau", tuple(), u"čau"),
            (123, None, 123),
        ],
    )
    def test_format(self, msg, args, fmsg):
        assert Logger.format(msg, args) == fmsg


from __future__ import print_function

import io
import itertools
import mimetypes
import os
import shutil
import subprocess
import uuid
import zipfile

from genshi.template import TemplateLoader

try:
    from lxml import etree
except ImportError as e:
    # no xpath support!
    import xml.etree.ElementTree as etree

COVER_ORDER = -300
TITLE_ORDER = -200
TOC_ORDER = -100
OPF_NS = "http://www.idpf.org/2007/opf"

class TocMapNode:
    def __init__(self):
        self.play_order = 0
        self.title = ""
        self.href = ""
        self.children = []
        self.depth = 0

    def assign_play_order(self):
        next_play_order = [0]
        self._assign_play_order(next_play_order)

    def _assign_play_order(self, next_play_order):
        self.play_order = next_play_order[0]
        next_play_order[0] = self.play_order + 1
        for child in self.children:
            child._assign_play_order(next_play_order)

class EpubItem:
    def __init__(self):
        self.id = ""
        self.src_path = ""
        self.dest_path = ""
        self.mime_type = ""
        self.html = ""

class EpubBook:
    def __init__(self):
        temp_dir = os.path.dirname(os.path.abspath(__file__))
        self.loader = TemplateLoader(os.path.join(temp_dir, "templates"))

        self.root_dir = ""
        self.UUID = uuid.uuid1()

        self.lang = "en-US"
        self.title = ""
        self.creators = []
        self.meta_info = []

        self.image_items = {}
        self.html_items = {}
        self.css_items = {}
        self.js_items = {}
        self.font_items = {}

        self.cover_image = None
        self.title_page = None
        self.toc_page = None

        self.spine = []
        self.guide = {}
        self.toc_map_root = TocMapNode()
        print("ROOT", self.toc_map_root)
        self.last_node_at_depth = {0: self.toc_map_root}

    def set_title(self, title):
        self.title = title

    def set_lang(self, lang):
        self.lang = lang

    def add_creator(self, name, role="aut"):
        self.creators.append((name, role))

    def add_meta(self, meta_name, meta_value, **meta_attrs):
        self.meta_info.append((meta_name, meta_value, meta_attrs))

    def get_meta_tags(self):
        l = []
        for meta_name, meta_value, meta_attr in self.meta_info:
            meta_name = to_valid_tag_name(meta_name)
            begin_tag = "<dc:%s" % meta_name
            if meta_attr:
                for attr_name, attr_value in meta_attr.iteritems():
                    begin_tag += ' opf:%s="%s"' % (attr_name, attr_value)
            begin_tag += ">"
            end_tag = "</dc:%s>" % meta_name
            l.append((begin_tag, meta_value, end_tag))
        return l

    def get_image_items(self):
        return sorted(self.image_items.values(), key=lambda x: x.id)

    def get_html_items(self):
        return sorted(self.html_items.values(), key=lambda x: x.id)

    def get_css_items(self):
        return sorted(self.css_items.values(), key=lambda x: x.id)

    def get_js_items(self):
        return sorted(self.js_items.values(), key=lambda x: x.id)

    def get_all_items(self):
        return sorted(
            itertools.chain(
                self.image_items.values(),
                self.html_items.values(),
                self.css_items.values(),
                self.js_items.values(),
                self.font_items.values(),
            ),
            key=lambda x: x.id,
        )

    def add_image(self, src_path, dest_path, id=None):
        if dest_path in self.image_items:
            return
        item = EpubItem()
        item.id = id or "image_{0}".format(len(self.image_items) + 1)
        item.src_path = src_path
        item.dest_path = dest_path
        item.mime_type = mimetypes.guess_type(dest_path)[0]
        # assert item.dest_path not in self.image_items
        self.image_items[dest_path] = item
        return item

    def add_html(self, src_path, dest_path, html, id=None):
        # assert src_path or html
        item = EpubItem()
        item.id = id or "html_%04d" % (len(self.html_items) + 1)
        item.src_path = src_path
        item.dest_path = dest_path
        item.html = html
        item.mime_type = "application/xhtml+xml"
        assert item.dest_path not in self.html_items
        self.html_items[item.dest_path] = item
        return item

    def add_font(self, src_path, dest_path):
        if dest_path in self.font_items:
            return
        item = EpubItem()
        item.id = "font_%d" % (len(self.font_items) + 1)
        item.src_path = src_path
        item.dest_path = dest_path
        if src_path.endswith("otf"):
            item.mime_type = "application/opentype"
        elif src_path.endswith("ttf"):
            item.mime_type = "application/truetype"
        else:
            raise KeyError

        self.font_items[item.dest_path] = item
        return item

    def add_js(self, src_path, dest_path):
        if dest_path in self.js_items:
            return
        item = EpubItem()
        item.id = "js_%d" % (len(self.css_items) + 1)
        item.src_path = src_path
        item.dest_path = dest_path
        item.mime_type = "text/javascript"

        self.js_items[item.dest_path] = item
        return item

    def add_css(self, src_path, dest_path):
        if dest_path in self.css_items:
            return
        item = EpubItem()
        item.id = "css_%d" % (len(self.css_items) + 1)
        item.src_path = src_path
        item.dest_path = dest_path
        item.mime_type = "text/css"

        self.css_items[item.dest_path] = item
        return item

    def add_cover(self, src_path, title="_cover"):
        assert not self.cover_image
        _, ext = os.path.splitext(src_path)
        dest_path = "cover%s" % ext
        self.cover_image = self.add_image(src_path, dest_path, id="cover-image")
        cover_page = self.add_cover_html_for_image(self.cover_image, title)
        self.add_spine_item(cover_page, False, COVER_ORDER)
        self.add_guide_item(cover_page.dest_path, title, "cover")

    def add_cover_html_for_image(self, image_item, title):
        tmpl = self.loader.load("image.html")
        image_item.title = title
        stream = tmpl.generate(book=self, item=image_item)
        html = stream.render("xhtml", doctype="xhtml11", drop_xml_decl=False)
        return self.add_html("", "cover.html", html, id="cover")

    def _make_title_page(self):
        assert self.title_page
        if self.title_page.html:
            return
        tmpl = self.loader.load("title-page.html")
        stream = tmpl.generate(book=self)
        self.title_page.html = stream.render(
            "xhtml", doctype="xhtml11", drop_xml_decl=False
        )

    def add_title_page(self, html=""):
        assert not self.title_page
        self.title_page = self.add_html("", "title-page.html", html)
        self.add_spine_item(self.title_page, True, TITLE_ORDER)
        self.add_guide_item("title-page.html", "Title Page", "title-page")

    def _make_toc_page(self):
        assert self.toc_page
        tmpl = self.loader.load("toc.html")
        stream = tmpl.generate(book=self)
        self.toc_page.html = stream.render(
            "xhtml", doctype="xhtml11", drop_xml_decl=False
        )

    def add_toc_page(self, order=TOC_ORDER):
        assert not self.toc_page
        self.toc_page = self.add_html("", "toc.html", "")
        self.add_spine_item(self.toc_page, False, order)
        self.add_guide_item("toc.html", "Table of Contents", "toc")

    def get_spine(self):
        results = sorted(self.spine)
        return results

    def next_order(self):
        if self.spine:
            order = max(order for order, _, _ in self.spine)
        else:
            order = 0
        return order + 1

    def add_spine_item(self, item, linear=True, order=None):
        assert item.dest_path in self.html_items
        if order is None:
            order = self.next_order()
        self.spine.append((order, item, linear))

    def get_guide(self):
        return sorted(self.guide.values(), key=lambda x: x[2])

    def add_guide_item(self, href, title, type):
        assert type not in self.guide, "TYPE %s NOT IN GUIDE %s" % (type, self.guide)
        self.guide[type] = (href, title, type)

    def get_toc_map_root(self):
        return self.toc_map_root

    def get_toc_map_height(self):
        return max(self.last_node_at_depth.keys())

    def add_toc_map_node(self, href, title, depth=None, parent=None):
        if not title:
            import pdb

            pdb.set_trace()
        print("TITLE", title)
        node = TocMapNode()
        node.href = href
        node.title = title
        if parent is None:
            if depth is None:
                parent = self.toc_map_root
            else:
                parent = self.last_node_at_depth[depth - 1]
        parent.children.append(node)
        node.depth = parent.depth + 1
        self.last_node_at_depth[node.depth] = node
        return node

    def make_dirs(self):
        try:
            os.makedirs(os.path.join(self.root_dir, "META-INF"))
        except OSError:
            pass
        try:
            os.makedirs(os.path.join(self.root_dir, "OEBPS"))
        except OSError:
            pass

    def _write_container_xml(self):
        cont_file = os.path.join(self.root_dir, "META-INF", "container.xml")
        with io.open(cont_file, mode="w", encoding="utf8") as fout:
            tmpl = self.loader.load("container.xml")
            stream = tmpl.generate()
            fout.write(stream.render("xml"))

    def _write_toc_ncx(self):
        self.toc_map_root.assign_play_order()
        toc_file = os.path.join(self.root_dir, "OEBPS", "toc.ncx")
        with io.open(toc_file, mode="w", encoding="utf8") as fout:
            tmpl = self.loader.load("toc.ncx")
            stream = tmpl.generate(book=self)
            fout.write(stream.render("xml"))

    def _write_content_opf(self):
        content_file = os.path.join(self.root_dir, "OEBPS", "content.opf")
        with io.open(content_file, mode="w", encoding="utf8") as fout:
            tmpl = self.loader.load("content.opf")
            stream = tmpl.generate(book=self)
            data = stream.render("xml")
            fout.write(data)

    def _write_items(self):
        for item in self.get_all_items():
            if item.html:
                item_file = os.path.join(self.root_dir, "OEBPS", item.dest_path)
                with io.open(item_file, mode="w", encoding="utf8") as fout:
                    # XXX perhaps check whether it is unicode or str and
                    # .encode() apporpriately.
                    fout.write(item.html)
            else:
                put_file(
                    item.src_path, os.path.join(self.root_dir, "OEBPS", item.dest_path)
                )

    def _write_mime_type(self):
        with open(os.path.join(self.root_dir, "mimetype"), "w") as fout:
            fout.write("application/epub+zip")

    @staticmethod
    def _list_manifest_items(content_opf_path):
        tree = etree.parse(content_opf_path)
        # return tree.xpath("//opf:manifest/opf:item/@href",
        #     namespaces = {'opf': 'http://www.idpf.org/2007/opf'})
        return [
            foo.attrib["href"]
            for foo in tree.findall("{%s}manifest/{%s}item" % (OPF_NS, OPF_NS))
        ]

    @staticmethod
    def create_archive(root_dir, output_path):
        with zipfile.ZipFile(output_path, "w") as fout:
            cwd = os.getcwd()
            os.chdir(root_dir)
            fout.writestr(
                "mimetype", "application/epub+zip", compress_type=zipfile.ZIP_STORED
            )
            file_list = []
            file_list.append(os.path.join("META-INF", "container.xml"))
            file_list.append(os.path.join("OEBPS", "content.opf"))
            opf_file = os.path.join("OEBPS", "content.opf")
            for item_path in EpubBook._list_manifest_items(opf_file):
                file_list.append(os.path.join("OEBPS", item_path))
            for file_path in file_list:
                fout.write(file_path, compress_type=zipfile.ZIP_DEFLATED)
        os.chdir(cwd)

    @staticmethod
    def check_epub(checker_path, epub_path):
        subprocess.call(["java", "-jar", checker_path, epub_path], shell=True)

    def create_book(self, root_dir):
        if self.title_page:
            self._make_title_page()
        if self.toc_page:
            self._make_toc_page()
        self.root_dir = root_dir
        self.make_dirs()
        self._write_mime_type()
        self._write_items()
        self._write_container_xml()
        self._write_content_opf()
        self._write_toc_ncx()

def to_valid_tag_name(txt):
    res = []
    for char in txt:
        if char.isalpha() or char == "_":
            res.append(char)
    return "".join(res)

def put_file(abs_path, rel_path):
    """
    given a file put it in the rel_path creating necessary dirs
    """
    if abs_path == rel_path:
        rel_path = os.path.join("img", os.path.basename(abs_path))
    parents = os.path.dirname(rel_path)
    try:
        os.makedirs(parents)

    except OSError as e:
        import errno

        if e.errno != errno.EEXIST or not os.path.isdir(parents):
            raise
    shutil.copyfile(abs_path, rel_path)

def test():
    def get_minimal_html(text):
        return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHtml 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<title>%s</title>

%s

""" % (
            text,
            text,
        )

    book = EpubBook()
    book.set_title("Most Wanted Tips for Aspiring Young Pirates")
    book.add_creator("Monkey D Luffy")
    book.add_creator("Guybrush Threepwood")
    book.add_meta("contributor", "Smalltalk80", role="bkp")
    book.add_meta("date", "2010", event="publication")

    book.add_title_page()
    book.add_toc_page()
    book.add_cover(r"D:\epub\blank.png")

    book.add_css(r"main.css", "main.css")

    n1 = book.add_html("", "1.html", get_minimal_html("Chapter 1"))
    n11 = book.add_html("", "2.html", get_minimal_html("Section 1.1"))
    n111 = book.add_html("", "3.html", get_minimal_html("Subsection 1.1.1"))
    n12 = book.add_html("", "4.html", get_minimal_html("Section 1.2"))
    n2 = book.add_html("", "5.html", get_minimal_html("Chapter 2"))

    book.add_spine_item(n1)
    book.add_spine_item(n11)
    book.add_spine_item(n111)
    book.add_spine_item(n12)
    book.add_spine_item(n2)

    # You can use both forms to add TOC map
    # t1 = book.add_toc_map_node(n1.dest_path, '1')
    # t11 = book.add_toc_map_node(n11.dest_path, '1.1', parent = t1)
    # t111 = book.add_toc_map_node(n111.dest_path, '1.1.1', parent = t11)
    # t12 = book.add_toc_map_node(n12.dest_path, '1.2', parent = t1)
    # t2 = book.add_toc_map_node(n2.dest_path, '2')

    book.add_toc_map_node(n1.dest_path, "1")
    book.add_toc_map_node(n11.dest_path, "1.1", 2)
    book.add_toc_map_node(n111.dest_path, "1.1.1", 3)
    book.add_toc_map_node(n12.dest_path, "1.2", 2)
    book.add_toc_map_node(n2.dest_path, "2")

    root_dir = r"d:\epub\test"
    book.create_book(root_dir)
    EpubBook.create_archive(root_dir, root_dir + ".epub")
    EpubBook.check_epub("epubcheck-1.0.5.jar", root_dir + ".epub")

if __name__ == "__main__":
    test()


"""128. Longest Consecutive Sequence
Medium
17.5K
766
Companies
Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.

You must write an algorithm that runs in O(n) time.

Example 1:

Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
Example 2:

Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9"""

from typing import List

def longestConsecutive(nums: List[int]) -> int:
    numsSet = set(nums)

    maxx = 0
    for idx in range(len(nums)):

        if not (nums[idx] - 1) in numsSet:
            count = 1
            while (nums[idx] + count) in numsSet:
                count += 1
            maxx = max(count, maxx)
    return maxx

nums = [100, 4, 200, 1, 3, 2]
print(longestConsecutive(nums))

nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
print(longestConsecutive(nums))


import rclpy
import rclpy.node
from rclpy.duration import Duration

from rclpy.qos import QoSProfile
from rclpy.qos import QoSHistoryPolicy as History
from rclpy.qos import QoSDurabilityPolicy as Durability
from rclpy.qos import QoSReliabilityPolicy as Reliability
from rclpy.qos import qos_profile_system_default

import rmf_adapter as adpt
import rmf_adapter.plan as plan
import rmf_adapter.schedule as schedule

from rmf_fleet_msgs.msg import DockSummary, ModeRequest

import numpy as np

import threading
import math
import enum
import time

from datetime import timedelta

# States for RobotCommandHandle's state machine used when guiding robot along
# a new path
class RobotState(enum.IntEnum):
    IDLE = 0
    MOVING = 1

# Custom wrapper for Plan::Waypoint. We use this to modify position of
# waypoints to prevent backtracking
class PlanWaypoint:
    def __init__(self, index, wp: plan.Waypoint):
        # the index of the Plan::Waypoint in the waypoints in follow_new_path
        self.index = index
        self.position = wp.position
        self.time = wp.time
        self.graph_index = wp.graph_index
        self.approach_lanes = wp.approach_lanes

class RobotCommandHandle(adpt.RobotCommandHandle):
    def __init__(self,
                 name,
                 fleet_name,
                 config,
                 node,
                 graph,
                 vehicle_traits,
                 transforms,
                 map_name,
                 start,
                 position,
                 charger_waypoint,
                 update_frequency,
                 lane_merge_distance,
                 adapter,
                 api):
        adpt.RobotCommandHandle.__init__(self)
        self.debug = False
        self.name = name
        self.fleet_name = fleet_name
        self.config = config
        self.node = node
        self.graph = graph
        self.vehicle_traits = vehicle_traits
        self.transforms = transforms
        self.map_name = map_name
        # Get the index of the charger waypoint
        waypoint = self.graph.find_waypoint(charger_waypoint)
        assert waypoint, f"Charger waypoint {charger_waypoint} \
          does not exist in the navigation graph"
        self.charger_waypoint_index = waypoint.index
        self.update_frequency = update_frequency
        self.lane_merge_distance = lane_merge_distance
        self.update_handle = None  # RobotUpdateHandle
        self.battery_soc = 1.0
        self.api = api
        self.position = position  # (x,y,theta) in RMF crs (meters,radians)
        self.initialized = False
        self.state = RobotState.IDLE
        self.dock_name = ""
        # TODO(YV): Remove self.adapter. This is only being used for time point
        # comparison with Plan::Waypoint::time
        self.adapter = adapter
        self.action_execution = None

        self.requested_waypoints = []  # RMF Plan waypoints
        self.remaining_waypoints = []
        self.docks = {}

        # RMF location trackers
        self.last_known_lane_index = None
        self.last_known_waypoint_index = None
        self.last_replan_time = None
        # if robot is waiting at a waypoint. This is a Graph::Waypoint index
        self.on_waypoint = None
        # if robot is travelling on a lane. This is a Graph::Lane index
        self.on_lane = None
        self.target_waypoint = None  # this is a Plan::Waypoint
        # The graph index of the waypoint the robot is currently docking into
        self.dock_waypoint_index = None
        # The graph index of the waypoint the robot starts or ends an action
        self.action_waypoint_index = None
        self.jobheader = "rmf"
        self.current_cmd_id = 0
        self.started_action = False

        # Threading variables
        self._lock = threading.Lock()
        self._follow_path_thread = None
        self._quit_path_event = threading.Event()
        self._dock_thread = None
        self._quit_dock_event = threading.Event()
        self._stopping_thread = None
        self._quit_stopping_event = threading.Event()

        self.node.get_logger().info(
            f"The robot is starting at: [{self.position[0]:.2f}, "
            f"{self.position[1]:.2f}, {self.position[2]:.2f}]")

        # Update tracking variables
        if start.lane is not None:  # If the robot is on a lane
            self.last_known_lane_index = start.lane
            self.on_lane = start.lane
            self.last_known_waypoint_index = start.waypoint
        else:  # Otherwise, the robot is on a waypoint
            self.last_known_waypoint_index = start.waypoint
            self.on_waypoint = start.waypoint

        transient_qos = QoSProfile(
            history=History.KEEP_LAST,
            depth=1,
            reliability=Reliability.RELIABLE,
            durability=Durability.TRANSIENT_LOCAL)

        self.node.create_subscription(
            DockSummary,
            'dock_summary',
            self.dock_summary_cb,
            qos_profile=transient_qos)

        self.node.create_subscription(
            ModeRequest,
            'action_execution_notice',
            self.mode_request_cb,
            qos_profile=qos_profile_system_default)

        self.update_thread = threading.Thread(target=self.update)
        self.update_thread.start()

        self.initialized = True

    def next_cmd_id(self):
        self.current_cmd_id = self.current_cmd_id + 1
        if self.debug:
            print(f'Issuing cmd_id for {self.name}: {self.current_cmd_id}')
        return self.current_cmd_id

    def sleep_for(self, seconds):
        goal_time =\
          self.node.get_clock().now() + Duration(nanoseconds=1e9*seconds)
        while (self.node.get_clock().now() <= goal_time):
            time.sleep(0.001)

    def wait_on(self, event: threading.Event, seconds):
        goal_time = (
            self.node.get_clock().now() + Duration(nanoseconds=1e9*seconds)
        )
        while self.node.get_clock().now() <= goal_time:
            if event.wait(0.001):
                return True
        return False

    def clear(self):
        self.requested_waypoints = []
        self.remaining_waypoints = []
        self.state = RobotState.IDLE

    def interrupt(self):
        if self.debug:
            print(
                f'Interrupting {self.name} '
                f'(latest cmd_id is {self.current_cmd_id})'
            )
        self._quit_dock_event.set()
        self._quit_path_event.set()
        self._quit_stopping_event.set()

        if self._follow_path_thread is not None:
            if self._follow_path_thread.is_alive():
                self._follow_path_thread.join()

        if self._dock_thread is not None:
            if self._dock_thread.is_alive():
                self._dock_thread.join()

        if self._stopping_thread is not None:
            if self._stopping_thread.is_alive():
                self._stopping_thread.join()

    def stop(self):
        if self.debug:
            plan_id = self.update_handle.unstable_current_plan_id()
            print(f'stop for {self.name} with PlanId {plan_id}')

        self.interrupt()
        # Stop the robot. Tracking variables should remain unchanged.
        with self._lock:
            self._quit_stopping_event.clear()

            def _stop():
                while not self._quit_stopping_event.is_set():
                    self.node.get_logger().info(
                        f"Requesting {self.name} to stop..."
                    )
                    if self.api.stop(self.name, self.next_cmd_id()):
                        break
                    self._quit_stopping_event.wait(0.1)

            self._stopping_thread = threading.Thread(target=_stop)
            self._stopping_thread.start()

    def replan(self):
        if self.update_handle is not None:
            now = self.adapter.now()
            if self.last_replan_time is not None:
                # TODO(MXG): Make the 15s replan cooldown configurable
                if now - self.last_replan_time < timedelta(seconds=15.0):
                    return
            self.last_replan_time = now
            self.update_handle.replan()
            self.node.get_logger().info(
                f'Requesting replan for {self.name} because of an obstacle'
            )

    def follow_new_path(
            self,
            waypoints,
            next_arrival_estimator,
            path_finished_callback):
        if self.debug:
            plan_id = self.update_handle.unstable_current_plan_id()
            print(f'follow_new_path for {self.name} with PlanId {plan_id}')
        self.interrupt()
        with self._lock:
            self._follow_path_thread = None
            self._quit_path_event.clear()
            self.clear()

            self.node.get_logger().info(f"Received new path for {self.name}")

            self.remaining_waypoints = self.filter_waypoints(waypoints)

            assert next_arrival_estimator is not None
            assert path_finished_callback is not None

            def _follow_path():
                target_pose = None
                path_index = 0
                while self.remaining_waypoints \
                        or self.state == RobotState.MOVING:
                    # Save the current_cmd_id before checking if we need to
                    # abort. We should always be told to abort before the
                    # current_cmd_id gets modified, so whatever the value of
                    # current_cmd_id is before being told to abort will be the
                    # value that we want. If we are saving the wrong value
                    # here, then the next thing we will be told to do is abort.
                    cmd_id = self.current_cmd_id
                    # Check if we need to abort
                    if self._quit_path_event.is_set():
                        self.node.get_logger().info(
                            f"[{self.name}] aborting path request"
                        )
                        return
                    # State machine
                    if self.state == RobotState.IDLE or target_pose is None:
                        # Assign the next waypoint
                        self.target_waypoint = self.remaining_waypoints[0]
                        path_index = self.remaining_waypoints[0].index
                        # Move robot to next waypoint
                        target_pose = self.target_waypoint.position
                        #target_pose = self.target_waypoint.position[x, y] = self.transforms["rmf_to_robot"].transform(target_pose[:2])
                        #theta = target_pose[2] + \
                        #    self.transforms['orientation_offset']

                        [x, y] = self.transforms["rmf_to_robot"].transform(target_pose[:2])
                        theta = target_pose[2]+ \
                            self.transforms['orientation_offset']
                        speed_limit = \
                            self.get_speed_limit(self.target_waypoint)

                        print(f"Requesting robot to navigate to "
                        f"[{x:.0f},{y:.0f}, {theta:.0f}] grid coordinates and "
                        f"[{target_pose[0]:.2f}, {target_pose[1]:.2f}, {target_pose[2]:.2f}] RMF coordinates...")

                        self.node.get_logger().info(f"Requesting robot to navigate to "
                        f"[{x:.0f},{y:.0f}, {theta:.0f}] grid coordinates and "
                        f"[{target_pose[0]:.2f}, {target_pose[1]:.2f}, {target_pose[2]:.2f}] RMF coordinates...")
                        response = self.api.navigate(
                            self.name,
                            self.next_cmd_id(),
                            [x, y, theta],
                            self.map_name,
                            speed_limit
                        )

                        if response:
                            self.remaining_waypoints = \
                                self.remaining_waypoints[1:]
                            self.state = RobotState.MOVING
                        else:
                            self.node.get_logger().info(
                                f"Robot {self.name} failed to request "
                                f"navigation to "
                                f"[{x:.0f}, {y:.0f}, {theta:.0f}]."
                                f"Retrying...")
                            self._quit_path_event.wait(0.1)

                    elif self.state == RobotState.MOVING:
                        if self.api.requires_replan(self.name):
                            self.replan()

                        if self._quit_path_event.wait(0.1):
                            return
                        # Check if we have reached the target
                        with self._lock:
                            if self.api.navigation_completed(
                                    self.name, cmd_id):
                                self.node.get_logger().info(
                                    f"Robot [{self.name}] has reached the "
                                    f"destination for cmd_id {cmd_id}"
                                )
                                self.state = RobotState.IDLE
                                graph_index = self.target_waypoint.graph_index
                                if graph_index is not None:
                                    self.on_waypoint = graph_index
                                    self.last_known_waypoint_index = \
                                        graph_index
                                else:
                                    self.on_waypoint = None  # still on a lane
                            else:
                                # Update the lane the robot is on
                                lane = self.get_current_lane()
                                if lane is not None:
                                    self.on_waypoint = None
                                    self.on_lane = lane
                                else:
                                    # The robot may either be on the previous
                                    # waypoint or the target one
                                    if self.target_waypoint.graph_index is \
                                        not None \
                                        and self.dist(
                                            self.position, target_pose) < 0.5:
                                        self.on_waypoint =\
                                            self.target_waypoint.graph_index
                                    elif self.last_known_waypoint_index is \
                                            not None and self.dist(
                                            self.position,
                                            self.graph.get_waypoint(
                                                self.last_known_waypoint_index
                                            ).location) < 0.5:
                                        self.on_waypoint =\
                                            self.last_known_waypoint_index
                                    else:
                                        # update_off_grid()
                                        self.on_lane = None
                                        self.on_waypoint = None
                            duration = self.api.navigation_remaining_duration(
                                self.name, cmd_id
                            )

                            if path_index is not None and duration is not None:
                                next_arrival_estimator(
                                    path_index,
                                    timedelta(seconds=duration)
                                )

                if (not self.remaining_waypoints) \
                        and self.state == RobotState.IDLE:
                    self.clear()
                    path_finished_callback()
                    self.node.get_logger().info(
                        f"Robot {self.name} has successfully navigated along "
                        f"requested path."
                    )

            self._follow_path_thread = threading.Thread(
                target=_follow_path)
            self._follow_path_thread.start()

    def dock(
            self,
            dock_name,
            docking_finished_callback):
        ''' Docking is very specific to each application. Hence, the user will
            need to customize this function accordingly. In this example, we
            assume the dock_name is the same as the name of the waypoints that
            the robot is trying to dock into. We then call api.start_process()
            to initiate the robot specific process. This could be to start a
            cleaning process or load/unload a cart for delivery.
        '''
        self.interrupt()
        with self._lock:
            self._quit_dock_event.clear()
            self.dock_name = dock_name
            assert docking_finished_callback is not None

            # Get the waypoint that the robot is trying to dock into
            dock_waypoint = self.graph.find_waypoint(self.dock_name)
            assert(dock_waypoint)
            self.dock_waypoint_index = dock_waypoint.index

            def _dock():
                # Request the robot to start the relevant process
                cmd_id = self.next_cmd_id()
                while not self.api.start_process(
                    self.name, cmd_id, self.dock_name, self.map_name
                ):
                    self.node.get_logger().info(
                        f"Requesting robot {self.name} to dock at "
                        f"{self.dock_name}"
                    )
                    if self._quit_dock_event.wait(1.0):
                        break

                with self._lock:
                    self.on_waypoint = None
                    self.on_lane = None

                if self.dock_name not in self.docks:
                    self.node.get_logger().info(
                        f"Requested dock {self.dock_name} not found, "
                        "ignoring docking request"
                    )
                    # TODO(MXG): This should open an issue ticket for the robot
                    # to tell the operator that the robot cannot proceed
                    return

                positions = []
                for wp in self.docks[self.dock_name]:
                    positions.append([wp.x, wp.y, wp.yaw])
                self.node.get_logger().info(
                    f"Robot {self.name} is docking at {self.dock_name}..."
                )

                while not self.api.process_completed(self.name, cmd_id):
                    if len(positions) < 1:
                        break

                    traj = schedule.make_trajectory(
                        self.vehicle_traits,
                        self.adapter.now(),
                        positions
                    )
                    itinerary = schedule.Route(self.map_name, traj)
                    if self.update_handle is not None:
                        participant = \
                            self.update_handle.get_unstable_participant()
                        participant.set_itinerary([itinerary])

                    # Check if we need to abort
                    if self._quit_dock_event.wait(0.1):
                        self.node.get_logger().info("Aborting docking")
                        return

                with self._lock:
                    self.on_waypoint = self.dock_waypoint_index
                    self.dock_waypoint_index = None
                    docking_finished_callback()
                    self.node.get_logger().info(
                        f"Robot {self.name} has completed docking"
                    )

            self._dock_thread = threading.Thread(target=_dock)
            self._dock_thread.start()

    def get_position(self):
        ''' This helper function returns the live position of the robot in the
        RMF coordinate frame'''
        position = self.api.position(self.name)
        if position is not None:
            x, y = [position[0], position[1]]
            theta = position[2]
            # Wrap theta between [-pi, pi]. Else arrival estimate will
            # assume robot has to do full rotations and delay the schedule
            if theta > np.pi:
                theta = theta - (2 * np.pi)
            if theta < -np.pi:
                theta = (2 * np.pi) + theta
            return [x, y, theta]
        else:
            self.node.get_logger().error(
                "Unable to retrieve position from robot.")
            return self.position

    def get_battery_soc(self):
        battery_soc = self.api.battery_soc(self.name)
        if battery_soc is not None:
            return battery_soc
        else:
            self.node.get_logger().error(
                "Unable to retrieve battery data from robot.")
            return self.battery_soc

    def update(self):
        while rclpy.ok():
            self.position = self.get_position()
            self.battery_soc = self.get_battery_soc()
            if self.update_handle is not None:
                self.update_state()
            sleep_duration = float(1.0/self.update_frequency)
            self.sleep_for(sleep_duration)

    def update_state(self):
        self.update_handle.update_battery_soc(self.battery_soc)
        # Update position
        with self._lock:
            if (self.on_waypoint is not None):  # if robot is on a waypoint
                self.update_handle.update_current_waypoint(
                    self.on_waypoint, self.position[2])
            elif (self.on_lane is not None):  # if robot is on a lane
                # We only keep track of the forward lane of the robot.
                # However, when calling this update it is recommended to also
                # pass in the reverse lane so that the planner does not assume
                # the robot can only head forwards. This would be helpful when
                # the robot is still rotating on a waypoint.
                forward_lane = self.graph.get_lane(self.on_lane)
                entry_index = forward_lane.entry.waypoint_index
                exit_index = forward_lane.exit.waypoint_index
                reverse_lane = self.graph.lane_from(exit_index, entry_index)
                lane_indices = [self.on_lane]
                if reverse_lane is not None:  # Unidirectional graph
                    lane_indices.append(reverse_lane.index)
                self.update_handle.update_current_lanes(
                    self.position, lane_indices)
            elif (self.dock_waypoint_index is not None):
                self.update_handle.update_off_grid_position(
                    self.position, self.dock_waypoint_index)
            # if robot is performing an action
            elif (self.action_execution is not None):
                if not self.started_action:
                    self.started_action = True
                    self.api.toggle_action(self.name, self.started_action)
                self.update_handle.update_off_grid_position(
                    self.position, self.action_waypoint_index)
            # if robot is merging into a waypoint
            elif (self.target_waypoint is not None and
                    self.target_waypoint.graph_index is not None):
                self.update_handle.update_off_grid_position(
                    self.position, self.target_waypoint.graph_index)
            else:  # if robot is lost
                self.update_handle.update_lost_position(
                    self.map_name,
                    self.position,
                    max_merge_lane_distance=self.lane_merge_distance
                )

    def get_current_lane(self):
        def projection(current_position,
                       target_position,
                       lane_entry,
                       lane_exit):
            px, py, _ = current_position
            p = np.array([px, py])
            t = np.array(target_position)
            entry = np.array(lane_entry)
            exit = np.array(lane_exit)
            return np.dot(p - t, exit - entry)

        if self.target_waypoint is None:
            return None
        approach_lanes = self.target_waypoint.approach_lanes
        # Spin on the spot
        if approach_lanes is None or len(approach_lanes) == 0:
            return None
        # Determine which lane the robot is currently on
        for lane_index in approach_lanes:
            lane = self.graph.get_lane(lane_index)
            p0 = self.graph.get_waypoint(lane.entry.waypoint_index).location
            p1 = self.graph.get_waypoint(lane.exit.waypoint_index).location
            p = self.position
            before_lane = projection(p, p0, p0, p1) < 0.0
            after_lane = projection(p, p1, p0, p1) >= 0.0
            if not before_lane and not after_lane:  # The robot is on this lane
                return lane_index
        return None

    def dist(self, A, B):
        ''' Euclidian distance between A(x,y) and B(x,y)'''
        assert(len(A) > 1)
        assert(len(B) > 1)
        return math.sqrt((A[0] - B[0])**2 + (A[1] - B[1])**2)

    def get_speed_limit(self, target_waypoint):
        approach_lane_limit = np.inf
        approach_lanes = target_waypoint.approach_lanes
        for lane_index in approach_lanes:
            lane = self.graph.get_lane(lane_index)
            lane_limit = lane.properties.speed_limit
            if lane_limit is not None:
                if lane_limit < approach_lane_limit:
                    approach_lane_limit = lane_limit
        return approach_lane_limit if approach_lane_limit != np.inf else 0.0

    def filter_waypoints(self, wps: list):
        ''' Return filtered PlanWaypoints'''

        assert(len(wps) > 0)
        p = np.array([self.position[0], self.position[1]])
        self.node.get_logger().info(f"[{len(wps)}] remaining waypointtttttt")
        waypoints = []
        for i in range(len(wps)):
            waypoints.append(PlanWaypoint(i, wps[i]))

        # If the robot is already in the middle of two waypoints, then we can
        # truncate all the waypoints that come before it.
        begin_at_index = 0
        for i in reversed(range(len(waypoints)-1)):
            i0 = i
            i1 = i+1
            p0 = waypoints[i0].position
            p0 = np.array([p0[0], p0[1]])
            p1 = waypoints[i1].position
            p1 = np.array([p1[0], p1[1]])
            dp_lane = p1 - p0
            lane_length = np.linalg.norm(dp_lane)
            if lane_length < 1e-3:
                continue

            n_lane = dp_lane/lane_length
            p_l = p - p0
            p_l_proj = np.dot(p_l, n_lane)
            if lane_length < p_l_proj:
                # Check if the robot's position is close enough to the lane
                # endpoint to merge it
                if np.linalg.norm(p - p1) <= self.lane_merge_distance:
                    begin_at_index = i1
                    break
                # Otherwise, continue to the next lane because the robot is not
                # between the lane endpoints
                continue
            if p_l_proj < 0.0:
                # Check if the robot's position is close enough to the lane
                # start point to merge it
                if np.linalg.norm(p - p0) <= self.lane_merge_distance:
                    begin_at_index = i0
                    break
                # Otherwise, continue to the next lane because the robot is not
                # between the lane endpoints
                continue

            lane_dist = np.linalg.norm(p_l - p_l_proj*n_lane)
            if lane_dist <= self.lane_merge_distance:
                begin_at_index = i1
                break

        if begin_at_index > 0:
            del waypoints[:begin_at_index]

        return waypoints

    def complete_robot_action(self):
        with self._lock:
            if self.action_execution is None:
                return
            self.action_execution.finished()
            self.action_execution = None
            self.started_action = False
            self.api.toggle_action(self.name, self.started_action)
            self.node.get_logger().info(f"Robot {self.name} has completed the"
                                        f" action it was performing")

    def newly_closed_lanes(self, closed_lanes):
        need_to_replan = False
        current_lane = self.get_current_lane()

        if self.target_waypoint is not None and \
                self.target_waypoint.approach_lanes is not None:
            for lane_idx in self.target_waypoint.approach_lanes:
                if lane_idx in closed_lanes:
                    need_to_replan = True
                    # The robot is currently on a lane that has been closed.
                    # We take this to mean that the robot needs to reverse.
                    if lane_idx == current_lane:
                        lane = self.graph.get_lane(current_lane)

                        return_waypoint = lane.entry.waypoint_index
                        reverse_lane = \
                            self.graph.lane_from(lane.entry.waypoint_index,
                                                 lane.exit.waypoint_index)

                        with self._lock:
                            if reverse_lane:
                                # Update current lane to reverse back to
                                # start of the lane
                                self.on_lane = reverse_lane.index
                            else:
                                # Update current position and waypoint index
                                # to return to
                                self.target_waypoint = return_waypoint

        if not need_to_replan and self.target_waypoint is not None:
            # Check if the remainder of the current plan has been invalidated
            # by the lane closure
            for wp in self.remaining_waypoints:
                for lane in wp.approach_lanes:
                    if lane in closed_lanes:
                        need_to_replan = True
                        break
                if need_to_replan:
                    break

        if need_to_replan:
            self.update_handle.replan()

    def dock_summary_cb(self, msg):
        for fleet in msg.docks:
            if(fleet.fleet_name == self.fleet_name):
                for dock in fleet.params:
                    self.docks[dock.start] = dock.path

    def mode_request_cb(self, msg):
        if msg.fleet_name is None or msg.fleet_name != self.fleet_name or\
                msg.robot_name is None:
            return
        if msg.mode.mode == RobotState.IDLE:
            self.complete_robot_action()