from bs4 import BeautifulSoup
from decimal import Decimal

from storescraper.store import Store
from storescraper.product import Product
from storescraper.utils import session_with_proxy, html_to_markdown

class EVision(Store):
    @classmethod
    def categories(cls):
        return [
            'Television',
            'StereoSystem',
            'Cell',
            'AirConditioner',
            'Refrigerator',
            'WashingMachine',
            'Oven',
            'Stove',
            'Monitor'
        ]

    @classmethod
    def discover_urls_for_category(cls, category, extra_args=None):
        category_filters = [
            ('410', 'Television'),
            ('321', 'StereoSystem'),
            ('340', 'StereoSystem'),
            ('810', 'Cell'),
            ('911', 'AirConditioner'),
            ('912', 'AirConditioner'),
            # "Para empezar la decada", contains other categories too
            # ('1400', 'AirConditioner'),
            ('913', 'AirConditioner'),
            ('921', 'Refrigerator'),
            ('922', 'Refrigerator'),
            ('923', 'Refrigerator'),
            ('931', 'WashingMachine'),
            ('932', 'WashingMachine'),
            ('933', 'WashingMachine'),
            ('934', 'WashingMachine'),
            ('935', 'WashingMachine'),
            ('970', 'Oven'),
            # ('980', 'Oven'),
            ('990', 'Oven'),
            ('950', 'Stove'),
            ('620', 'Monitor'),
        ]

        session = session_with_proxy(extra_args)
        session.headers['User-Agent'] = \
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, ' \
            'like Gecko) Chrome/66.0.3359.117 Safari/537.36'
        product_urls = []

        for section_id, local_category in category_filters:
            if local_category != category:
                continue

            url = 'https://www.evisionstore.com/?ipp=All' \
                  '&categoria=catalogo&codfamilia={}'.format(section_id)

            soup = BeautifulSoup(session.get(url, timeout=30).text,
                                 'html.parser')

            product_containers = soup.findAll('div', 'product-items')

            if not product_containers:
                raise Exception('Empty section {}'.format(section_id))

            for container in product_containers:
                if 'LG' not in container.find('h4').text.upper():
                    continue
                product_url = 'https://www.evisionstore.com/{}'\
                    .format(container.find('a')['href'])
                product_urls.append(product_url)

        return product_urls

    @classmethod
    def products_for_url(cls, url, category=None, extra_args=None):
        print(url)
        session = session_with_proxy(extra_args)
        session.headers['User-Agent'] = \
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, ' \
            'like Gecko) Chrome/66.0.3359.117 Safari/537.36'
        response = session.get(url, timeout=30)

        soup = BeautifulSoup(response.text, 'html5lib')

        if not soup.find('section', 'product-details'):
            return []

        name = soup.find('meta', {'itemprop': 'name'})['content']
        sku = soup.find('input', {'id': 'productId'})['value']

        if soup.find('a', {'id': 'addtocart'}):
            stock = -1
        else:
            stock = 0

        price = Decimal(
            soup.find('meta', {'property': 'product:price:amount'})['content']
                .replace('$', '').replace(',', '').strip())

        picture_urls = [soup.find('meta', {'itemprop': 'image'})['content']]

        description = html_to_markdown(
            str(soup.find('div', 'pro-description')))

        p = Product(
            name,
            cls.__name__,
            category,
            url,
            url,
            sku,
            stock,
            price,
            price,
            'USD',
            sku=sku,
            picture_urls=picture_urls,
            description=description
        )

        return [p]


import os
import selenium
from selenium import webdriver
import time
currentDirectory = os.path.dirname(__file__)
soundDirectory = currentDirectory + r"/sounds//"
chromedriverPath = currentDirectory + "/setup/chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)

driver.get("https://youtube.com")
input("enter")
num = 0
scroll = str(270)
while True:
    input("enter")
    try:
        print("window.scrollTo(0, " + scroll + ");")
        driver.execute_script("window.scrollTo(0, " + scroll + ");")
    except Exception as e:
        print(e)
    num += 270
    scroll = str(num)


import cv2
import numpy as np
import click
import time

from yolov3 import Detector

import ai2thor.controller

controller = ai2thor.controller.Controller()
controller.start(player_screen_width=500, player_screen_height=400)

# Kitchens: FloorPlan1 - FloorPlan30
# Living rooms: FloorPlan201 - FloorPlan230
# Bedrooms: FloorPlan301 - FloorPlan330
# Bathrooms: FloorPLan401 - FloorPlan430

controller.reset('FloorPlan1')
event = controller.step(dict(action='Initialize', gridSize=0.25, rotation=0, horizon=0))

moves = {'Q': 'MoveLeft', 'R': 'MoveAhead', 'S': 'MoveRight', 'T': 'MoveBack'}
rotates = {'a': -10, 'd': 10}
looks = {'w': -10, 's': 10}

rotate = 0
horizon = 0

detect = Detector()

while True:

    img = event.cv2img

    # Detect edge
    # gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # blur = cv2.GaussianBlur(gray, (5,5), 0)
    # edges = cv2.Canny(blur, 50,30)
    # cv2.imshow('Detect Edge', edges)

    st = time.time()
    # object detection
    dst = detect.detect(img)
    print("Time:", time.time() - st)
    cv2.imshow('Detect Object', dst)

    key = cv2.waitKey(0)
    key = chr(key)

    if key == 'q':
        break
    elif key in moves:
        event = controller.step(dict(action=moves[key]))
    elif key in rotates:
        rotate += rotates[key]
        event = controller.step(action=dict(action='Rotate', rotation=rotate))

    elif key in looks:
        horizon += looks[key]
        event = controller.step(action=dict(action='Look', horizon=horizon))

cv2.destroyAllWindows()


#! /usr/bin/python
import cv2
import time
'''
def diffinframes(x,y,z):
	img1=cv2.absdiff(x,y)
	img2=cv2.absdiff(y,z)
	comm_diff=cv2.bitwise_and(img1,img2)
	return comm_diff
'''
#enabling camera
cap=cv2.VideoCapture(0)

#capturing 3 consistent frames
frame1=cap.read()[1]
frame2=cap.read()[1]
frame3=cap.read()[1]

#converting to grayscale
gray1=cv2.cvtColor(frame1,0)
gray2=cv2.cvtColor(frame2,0)
gray3=cv2.cvtColor(frame3,0)

while cap.isOpened():
	img1=cv2.absdiff(gray1,gray2)
	img2=cv2.absdiff(gray2,gray3)
	comm_diff=cv2.bitwise_and(img1,img2)
	#show motion detected frames
	cv2.imshow("camera",comm_diff)
	#capture more frames for further processing
	status,frame=cap.read()
	gray1=gray2
	gray2=gray3
	gray3=cv2.cvtColor(frame,0)
	if cv2.waitKey(1) & 0xFF==ord('q'):
		break

cv2.destroyAllWindows()
cap.release()


"""
https://en.wikipedia.org/wiki/Naming_convention_(programming)

Per-file:
  Dominant and outlier casing styles for:
    variables
    functions
    classes

Aggregation:
  aggregated casing style (dominant, outlier) for each naming type
"""

from enum import Enum
from collections import Counter
from functools import lru_cache

from cadistributor import log
from .base import CafpModule
from ..utils import get_safe_file_ext as get_file_ext
from ..lexing.pygments_proxy import token, get_tokens_for_file

# https://stackoverflow.com/a/51976841/2375851
class CasingScheme(str, Enum):
    other = "other"
    invalid = "invalid"
    camel = "CamelCase"
    lowercamel = "lowerCamelCase"
    snake = "snake_case"
    tallsnake = "TALL_SNAKE_CASE"
    kebab = "kebab-case"
    tallkebab = "KEBAB-CASE"
    flat = "flatcase"
    upper = "UPPERCASE"

# (has_upper, has_lower, has_dash, has_underscore, first_upper)
_case_id_map = {
    (True,  True,  False, False, True  ): CasingScheme.camel,
    (True,  True,  False, False, False ): CasingScheme.lowercamel,
    (False, True,  False, True,  False ): CasingScheme.snake,
    (True,  False, False, True,  True  ): CasingScheme.tallsnake,
    (False, True,  True,  False, False ): CasingScheme.kebab,
    (True,  False, True,  False, True  ): CasingScheme.tallkebab,
    (False, True,  False, False, False ): CasingScheme.flat,
    (True,  False, False, False, False ): CasingScheme.upper,
    (False, False, False, False, False ): CasingScheme.invalid,
}

## Why use a cache here?
# Files are very likely to contain the same name many times, and these string
# operations are relatively expensive to identify the casing of the name.
## Why this maxsize?
# no idea, just a random guess
# but it works: CacheInfo(hits=4466185, misses=693405, maxsize=4000, currsize=4000
# 4.4 million vs 0.7 million
@lru_cache(maxsize=4000)
def classify_casing_scheme(token_text):
    """Given a string, return the casing type"""
    if not token_text.isprintable():
        return CasingScheme.invalid
    has_upper = not token_text.islower()
    has_lower = not token_text.isupper()
    has_dash = '-' in token_text
    has_underscore = '_' in token_text
    first_upper = token_text[0].isupper() if len(token_text) > 0 else False
    case_id = (has_upper, has_lower, has_dash, has_underscore, first_upper)
    if case_id in _case_id_map:
        return _case_id_map[case_id]
    return CasingScheme.other

# https://pygments.org/docs/tokens/#module-pygments.token
target_token_types = [
    token.Name,
]
# subtypes of target_token_types we want to exclude
exclude_token_types = [
    token.Name.Function.Magic,
    token.Name.Variable.Magic,
    token.Name.Entity, # (e.g.   in HTML)
    token.Name.Builtin,
]

def _is_token_targetable(tokentype):
    if tokentype in exclude_token_types:
        return False
    if tokentype in target_token_types:
        return True
    for exclude_type in exclude_token_types:
        if tokentype in exclude_type:
            return False
    for target_type in target_token_types:
        if tokentype in target_type:
            return True
    return False

# reducing within the _foreach_gitfile step to avoid massive memory requirements
# the size of tokens for a file is multiples larger than the file itself
def _tokenize_and_reduce_file(filename):
    raw_tokens = get_tokens_for_file(filename)
    if raw_tokens is None:
        # log.debug(f"File {filename} failed to lex.")
        return None
    target_tokens = []
    for (idx, tokentype, value) in raw_tokens:
        if _is_token_targetable(tokentype):
            target_tokens.append((idx, tokentype, value))
    return target_tokens

class CafpCasingAnalyzer(CafpModule):
    def _run_file_analysis(self):
        tokenized = self._foreach_gitfile(_tokenize_and_reduce_file)
        # ignore non-lexable files:
        for k in list(tokenized.keys()):
            if tokenized[k] is None:
                del tokenized[k]

        casings = {}
        self.tmp.counters = {}
        for filename, tokens in tokenized.items():
            casings[filename] = {}
            self.tmp.counters[filename] = {}
            tokens_with_cases = []
            for (idx, tokentype, value) in tokens:
                case = classify_casing_scheme(value)
                tokens_with_cases.append((tokentype, case))
            self.tmp.counters[filename] = Counter(tokens_with_cases)
            for (tokentype,casing),v in self.tmp.counters[filename].items():
                tokenname = str(tokentype).replace('.', '_')
                # log.debug(f"{filename} {(tokentype,)}/{tokenname} with {casing}")
                if tokenname not in casings[filename]:
                    casings[filename][tokenname] = {}
                if casing.name not in casings[filename][tokenname]:
                    casings[filename][tokenname][casing.name] = 0
                casings[filename][tokenname][casing.name] += v
            # casings[filename] = {str(k): v for k,v in dict(self.tmp.counters[filename]).items()}
        return casings

    def _run_repo_analysis(self):
        by_ext = {}
        total = {}
        for f_k, f_v in self.file_results.items():
            f_ext = get_file_ext(f_k)
            if f_ext not in by_ext:
                by_ext[f_ext] = {}
            for tokentype,casecounts in f_v.items():
                if tokentype not in total:
                    total[tokentype] = {}
                for casing,count in casecounts.items():
                    if casing not in total[tokentype]:
                        total[tokentype][casing] = 0
                    total[tokentype][casing] += count
                    if tokentype not in by_ext[f_ext]:
                        by_ext[f_ext][tokentype] = {}
                    if casing not in by_ext[f_ext][tokentype]:
                        by_ext[f_ext][tokentype][casing] = 0
                    by_ext[f_ext][tokentype][casing] += count
        return {
            "total": total,
            "by_ext": by_ext,
        }

    def exit_cleanup(self):
        log.debug(f"classify_casing_scheme cache: {classify_casing_scheme.cache_info()}")


import requests
import json
import os
from dotenv import load_dotenv
from bs4 import BeautifulSoup, SoupStrainer
from datetime import datetime as dt
from datetime import timedelta

load_dotenv()
SLACK_URL = 'https://slack.com/api/chat.postMessage'
CHANNEL = os.getenv('SLACK_CHANNEL')
print(str(CHANNEL))
TOKEN = os.getenv('SLACK_TOKEN')
HEADERS = {
    'content-type': 'application/json',
    'authorization': f'Bearer {TOKEN}'
}

URLS = {
    'Knitter': "https://www.lounaat.info/lounas/knitter/espoo",
    'Bluebell': "https://www.lounaat.info/lounas/bluebell/espoo",
    'Happy Friends': "https://www.lounaat.info/lounas/happy-friends/espoo",
    'Sodexo Täyttymys': "https://www.lounaat.info/lounas/sodexo-tyttymys/espoo",
    'Amica Sinitähti': "https://www.lounaat.info/lounas/amica-ravintola-sinitahti/espoo"
}

WEEKDAYS = [
    "maanantai",
    "tiistai",
    "keskiviikko",
    "torstai",
    "perjantai",
    "lauantai",
    "sunnuntai"
]

def weekday_str():
    return WEEKDAYS[dt.today().weekday()]

def weekday_int():
    return dt.today().weekday()

def parse(html_txt, weekday, restaurant):
    try:
        amica_tags = SoupStrainer(id='menu')
        tag = amica_tags        # Default to lounaat.info
        if (restaurant == 'Factory'):
            # Load whole page since Factory has no good ids to parse into
            soup = BeautifulSoup(html_txt, 'html.parser')
            # Find parent of lounaslista text, which holds whole week in
            # multiple <p>'s (*sigh :( )
            s = soup.find(lambda tag: tag.name == "h2" and tag.text.lower(
            ).startswith("lounaslista")).parent.text
            # Find today and tomorrow from the huge string which has whole week
            # lunch and some bloat text
            s = (s[s.lower().find(weekday) +
                   len(weekday):s.lower().find(WEEKDAYS[(dt.today() +
                                                         timedelta(days=1)).weekday()])])
            # Get rid of date text that is following the weekday and return the
            # text
            s = (s[s.find("\n") + len("\n"):])
            return s
        else:       # lounaat.info parse
            soup = BeautifulSoup(html_txt, 'html.parser', parse_only=tag)
            raw_html = soup.find(lambda tag: tag.name == "h3" and tag.text.lower(
            ).startswith(weekday)).parent.parent
            lst = []
            for elem in raw_html.find_all("p"):
                if not elem.text.startswith("Mixed lunch:")\
                        and not elem.text.startswith("Kaikki lounaspakettimme sisältävät")\
                        and not elem.text.startswith("All of our lunch options"):
                    lst.append(" ".join(elem.text.split()))
            return '\n'.join(lst)
    except Exception:
        return ""       # Default failed parse

def main():
    wd = weekday_str()
    ret = json.loads(requests.post(SLACK_URL, data=json.dumps(
        {
            'token': TOKEN,
            'channel': CHANNEL,
            'text': f'Lounaat {wd}',
            'charset': 'utf8'
        }
    ), headers=HEADERS).text)
    print(str(ret))
    thread_id = ret['ts']
    for (restaurant, url) in URLS.items():
        try:
            resp = requests.get(url)
            print("{0}: {1}".format(restaurant, resp.status_code))
            text = parse(resp.text, wd, restaurant)
            bolded_header = "*{0}:*\n".format(restaurant)
            data = {
                'text': bolded_header + text,
                'channel': CHANNEL,
                'thread_ts': thread_id,
            }
            ret = json.loads(
                requests.post(
                    SLACK_URL,
                    data=json.dumps(data),
                    headers=HEADERS).text)
        except Exception as ex:
            print(ex)
            requests.post(SLACK_URL, data=json.dumps(
                {'text': ex}), headers=HEADERS)

main()


import numpy as np
from scipy.constants import pi

from .. import njit

@njit
def steffen_3d(
    v_in,
    z_in,
    z_out,
    z_min_surface,
    z_max_surface,
    lower_extrapolation_with_gradient=False,
    upper_extrapolation_with_gradient=False,
):
    """
    Performs Steffen interpolation on each individual column.
    Steffen, M. (1990). A simple method for monotonic interpolation
    in one dimension. Astronomy and Astrophysics, 239, 443.

    `z_min_surface` and `z_max_surface` define the minimum and maximum height
    outside of which the interpolated value will be set to nan (useful for not
    interpolating pressure into solid ground for example).
    `lower_extrapolation_with_gradient` and `upper_extrapolation_with_gradient`
    enables the use of one-sided gradient when extrapolating outside the range
    of `z_in`, otherwise the limit value of `v_in` is used by default
    """
    assert v_in.shape[1:] == z_min_surface.shape
    k_max = v_in.shape[0]
    j_max = v_in.shape[1]
    i_max = v_in.shape[2]
    k_max_output = z_out.shape[0]
    k_max_minus = k_max - 1
    linear_slope = np.empty((k_max))
    v_out = np.empty((k_max_output, j_max, i_max))
    for i in range(i_max):
        for j in range(j_max):
            # first point
            delta_lower = z_in[1, j, i] - z_in[0, j, i]
            delta_upper = z_in[2, j, i] - z_in[1, j, i]
            if delta_lower < 0:
                raise Exception("Non-montonic increase in z_in")
            if delta_upper < 0:
                raise Exception("Non-montonic increase in z_in")
            slope_lower = (v_in[1, j, i] - v_in[0, j, i]) / delta_lower
            slope_upper = (v_in[2, j, i] - v_in[1, j, i]) / delta_upper

            weighted_slope = slope_lower * (
                1 + delta_lower / (delta_lower + delta_upper)
            ) - slope_upper * delta_lower / (delta_lower + delta_upper)
            if weighted_slope * slope_lower <= 0.0:
                linear_slope[0] = 0.0
            elif np.abs(weighted_slope) > 2 * np.abs(slope_lower):
                linear_slope[0] = 2.0 * slope_lower
            else:
                linear_slope[0] = weighted_slope

            # intermediate points
            for k in range(1, k_max_minus):
                delta_lower = z_in[k, j, i] - z_in[k - 1, j, i]
                delta_upper = z_in[k + 1, j, i] - z_in[k, j, i]
                slope_lower = (v_in[k, j, i] - v_in[k - 1, j, i]) / delta_lower
                slope_upper = (v_in[k + 1, j, i] - v_in[k, j, i]) / delta_upper
                weighted_slope = (
                    slope_lower * delta_upper + slope_upper * delta_lower
                ) / (delta_lower + delta_upper)

                if slope_lower * slope_upper <= 0.0:
                    linear_slope[k] = 0.0
                elif np.abs(weighted_slope) > 2.0 * np.abs(slope_lower):
                    linear_slope[k] = np.copysign(2.0, slope_lower) * min(
                        np.abs(slope_lower), np.abs(slope_upper)
                    )
                elif np.abs(weighted_slope) > 2.0 * np.abs(slope_upper):
                    linear_slope[k] = np.copysign(2.0, slope_lower) * min(
                        np.abs(slope_lower), np.abs(slope_upper)
                    )
                else:
                    linear_slope[k] = weighted_slope

            # last point
            delta_lower = z_in[k_max_minus - 1, j, i] - z_in[k_max_minus - 2, j, i]
            delta_upper = z_in[k_max_minus, j, i] - z_in[k_max_minus - 1, j, i]
            slope_lower = (
                v_in[k_max_minus - 1, j, i] - v_in[k_max_minus - 2, j, i]
            ) / delta_lower
            slope_upper = (
                v_in[k_max_minus, j, i] - v_in[k_max_minus - 1, j, i]
            ) / delta_upper
            weighted_slope = slope_upper * (
                1 + delta_upper / (delta_upper + delta_lower)
            ) - slope_lower * delta_upper / (delta_upper + delta_lower)
            if weighted_slope * slope_upper <= 0.0:
                linear_slope[k_max_minus] = 0.0
            elif np.abs(weighted_slope) > 2.0 * np.abs(slope_upper):
                linear_slope[k_max_minus] = 2.0 * slope_upper
            else:
                linear_slope[k_max_minus] = weighted_slope

            # loop over output points
            k_temp = 0
            for k_out in range(k_max_output):
                while (k_temp < k_max) and (z_in[k_temp, j, i] < z_out[k_out]):
                    k_temp = k_temp + 1
                if 0 < k_temp < k_max:
                    k_high = k_temp
                    k_low = k_high - 1
                    delta = z_in[k_high, j, i] - z_in[k_low, j, i]
                    slope = (v_in[k_high, j, i] - v_in[k_low, j, i]) / delta
                    a = (linear_slope[k_low] + linear_slope[k_high] - 2 * slope) / (
                        delta * delta
                    )
                    b = (
                        3 * slope - 2 * linear_slope[k_low] - linear_slope[k_high]
                    ) / delta
                    c = linear_slope[k_low]
                    d = v_in[k_low, j, i]
                    t_1 = z_out[k_out] - z_in[k_low, j, i]
                    t_2 = t_1 * t_1
                    t_3 = t_2 * t_1
                    v_out[k_out, j, i] = a * t_3 + b * t_2 + c * t_1 + d
                elif (k_temp == 0) and (z_out[k_out] >= z_min_surface[j, i]):
                    if lower_extrapolation_with_gradient:
                        v_out[k_out, j, i] = v_in[0, j, i] + linear_slope[0] * (
                            z_out[k_out] - z_in[0, j, i]
                        )
                    else:
                        v_out[k_out, j, i] = v_in[0, j, i]
                elif (k_temp == k_max) and (z_out[k_out] <= z_max_surface[j, i]):
                    if upper_extrapolation_with_gradient:
                        v_out[k_out, j, i] = v_in[k_max - 1, j, i] + linear_slope[
                            k_max - 1
                        ] * (z_out[k_out] - z_in[k_max - 1, j, i])
                    else:
                        v_out[k_out, j, i] = v_in[k_max - 1, j, i]
                else:
                    v_out[k_out, j, i] = np.nan
    return v_out

def cos_transition(absolute_input, transition_start, transition_end):
    """function that smoothly transitions from 1 to 0 using a
    cosine-shaped transition between start and end"""
    normalised_input = (absolute_input - transition_start) / (
        transition_end - transition_start
    )
    weight_factor = 1.0 * (normalised_input < 0.0) + (
        0.5 + 0.5 * np.cos(normalised_input * pi)
    ) * (1.0 - (normalised_input < 0.0) - (normalised_input > 1.0))
    return weight_factor


from curl.train import run_task
from softgym.registered_env import env_arg_dict
reward_scales = {
    'PassWater': 20.0,
    'PourWater': 20.0,
    'ClothFold': 50.0,
    'ClothFlatten': 50.0,
    'ClothDrop': 50.0,
    'RopeFlatten': 50.0,
}

clip_obs = {
    'PassWater': None,
    'PourWater': None,
    'ClothFold': (-3, 3),
    'ClothFlatten': (-2, 2),
    'ClothDrop': None,
    'RopeFlatten': None,
}

def get_lr_decay(env_name, obs_mode):
    if env_name == 'RopeFlatten' or (env_name == 'ClothFlatten' and obs_mode == 'cam_rgb'):
        return 0.01
    elif obs_mode == 'point_cloud':
        return 0.01
    else:
        return None

def get_actor_critic_lr(env_name, obs_mode):
    if env_name == 'ClothFold' or (env_name == 'RopeFlatten' and obs_mode == 'point_cloud'):
        if obs_mode == 'cam_rgb':
            return 1e-4
        else:
            return 5e-4
    if obs_mode == 'cam_rgb':
        return 3e-4
    else:
        return 1e-3

def get_alpha_lr(env_name, obs_mode):
    if env_name == 'ClothFold':
        return 2e-5
    else:
        return 1e-3

def main():
    import argparse
    parser = argparse.ArgumentParser()
    # Experiment
    parser.add_argument('--exp_name', default='CURL_SAC', type=str)
    parser.add_argument('--env_name', default='ClothFlatten')
    parser.add_argument('--log_dir', default='./data/curl/')
    parser.add_argument('--test_episodes', default=10, type=int)
    parser.add_argument('--seed', default=100, type=int)
    parser.add_argument('--save_tb', default=False)  # Save stats to tensorbard
    parser.add_argument('--save_video', default=True)
    parser.add_argument('--save_model', default=True)  # Save trained models

    # CURL
    parser.add_argument('--alpha_fixed', default=False, type=bool)  # Automatic tuning of alpha
    parser.add_argument('--init_temperature', default=0.1, type=float)
    parser.add_argument('--replay_buffer_capacity', default=100000)
    parser.add_argument('--batch_size', default=128)

    # Override environment arguments
    parser.add_argument('--env_kwargs_render', default=True, type=bool)  # Turn off rendering can speed up training
    parser.add_argument('--env_kwargs_camera_name', default='default_camera', type=str)
    parser.add_argument('--env_kwargs_observation_mode', default='key_point', type=str)  # Should be in ['key_point', 'cam_rgb', 'point_cloud']
    parser.add_argument('--env_kwargs_num_variations', default=1, type=int)

    args = parser.parse_args()

    args.algorithm = 'CURL'

    # Set env_specific parameters

    env_name = args.env_name
    obs_mode = args.env_kwargs_observation_mode
    args.actor_lr = args.critic_lr = get_actor_critic_lr(env_name, obs_mode)
    args.lr_decay = get_lr_decay(env_name, obs_mode)
    args.scale_reward = reward_scales[env_name]
    args.clip_obs = clip_obs[env_name] if obs_mode == 'key_point' else None
    args.env_kwargs = env_arg_dict[env_name]

    run_task(args.__dict__, args.log_dir, args.exp_name)

if __name__ == '__main__':
    main()


import logging
import sys
import os
import socket
import logging.handlers
import subprocess
import logging.config as lc

from autohdl.lib.decorator import decorator

LOGGING = {
  'version': 1,
  'disable_existing_loggers': True,
  'formatters': {
    'verbose': {
      'format': '%(asctime)s:%(filename)s:%(lineno)d:%(levelname)s:%(message)s'
    },
    'simple': {
      'format': '%(levelname)s: %(message)s'
    },
    },
  'handlers': {
    'consoleDebug': {
      'level': 'DEBUG',
      'class': 'logging.StreamHandler',
      'formatter': 'verbose'
    },
    'consoleInfo': {
      'level': 'INFO',
      'class': 'logging.StreamHandler',
      'formatter': 'simple'
    },
    'socket': {
      'level': 'DEBUG',
      'class': 'logging.handlers.SocketHandler',
      'host': 'localhost',
      'port': logging.handlers.DEFAULT_TCP_LOGGING_PORT,
    },
    },
  'loggers': {
    '': {
      'handlers': ['consoleInfo', 'socket'],
      'level': 'DEBUG',
      },
    }
}

lc.dictConfig(LOGGING)

s = socket.socket()  #socket.AF_INET, socket.SOCK_STREAM
# check if logging server up, else - run
if s.connect_ex(('localhost', logging.handlers.DEFAULT_TCP_LOGGING_PORT)): #9020
  path = os.path.dirname(__file__) + '/log_server.py'
  p = subprocess.Popen('pythonw '+ path)

class MyLogger(logging._loggerClass):
  def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
    """Let the caller modify any of the parameters"""
    record = logging.LogRecord(name, level, fn, lno, msg, args, exc_info, func)
    if extra:
      for key in extra:
        record.__dict__[key] = extra[key]
    return record

logging.setLoggerClass(MyLogger)

@decorator
def log_call(fn, *args, **kw):
  """Log calls to fn, reporting caller, args, and return value"""
  logger = logging.getLogger(fn.__module__)
  try:
    frame = sys._getframe(2)
    varnames = fn.func_code.co_varnames
    arglist = ', '.join([i[1]+'='+str(i[0]) for i in zip(args, varnames)])
    if kw:
      arglist += ', '.join(['{0}={1}'.format(k, v) for k, v in kw.viewitems()])

    logger.debug("%(func)s IN (%(args)s)" % (
        {'func': fn.__name__,
         'args': arglist,
         }),
                 extra={
                   'filename': os.path.split(frame.f_code.co_filename)[-1],
                   'pathname': frame.f_code.co_filename,
                   'lineno': frame.f_lineno,
                   'module': fn.__module__,
                   'funcName': fn.__name__})

    result = fn(*args, **kw)

  except Exception as e:
    logger.exception(e)
    logger.debug('crashed')
    raise
  else:
    logger.debug("%(func)s OUT %(ret)s" % (
        {'func': fn.__name__,
         'ret': str(result),
         }),
                 extra={
                   'filename': os.path.split(frame.f_code.co_filename)[-1],
                   'pathname': frame.f_code.co_filename,
                   'lineno': frame.f_lineno,
                   'module': fn.__module__,
                   'funcName': fn.__name__})

  return result


import pyttsx3
import pyaudio
import speech_recognition as sr
import  sys, os

def takeCommand():
    #it takes microphone input from usre and returnn string output
    r=sr.Recognizer()
    with sr.Microphone() as source:
        print("listening..")
        r.pause_threshold = 1
        audio=r.listen(source)

    try:
         print("Recognizing...")
         query=r.recognize_google(audio,language='en-in')
         print("user said:",query)
    except Exception as e:
          print(e)

          print("Say that again ")
          return "None"
    return query

engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
print(voices)
engine.setProperty('voice',voices[0].id)
engine.setProperty('rate', 150)
engine.setProperty('volume', 0.9)

def speak(audio):

    engine.say(audio)

    engine.runAndWait()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import piradio.graphics as graphics
import freetype
import logging

class Bitmap(object):
    """A 2D bitmap image represented as a list of byte values.
    Each byte indicates the state of a single pixel in the bitmap.
    A value of 0 indicates that the pixel is `off` and any other value
    indicates that it is `on`.
    """
    def __init__(self, width, height, pixels=None):
        self.width = width
        self.height = height
        self.pixels = pixels or bytearray(width * height)

    def __repr__(self):
        """Return a string representation of the bitmap's pixels."""
        rows = ''
        for y in range(self.height):
            for x in range(self.width):
                rows += '*' if self.pixels[y * self.width + x] else '.'
            rows += '\n'
        return rows

    def bitblt(self, src, x, y):
        """Copy all pixels from `src` into this bitmap"""
        srcpixel = 0
        dstpixel = y * self.width + x
        row_offset = self.width - src.width

        for _ in xrange(src.height):
            for _ in xrange(src.width):
                # Perform an OR operation on the destination pixel and
                # the source pixel because glyph bitmaps may overlap if
                # character kerning is applied, e.g. in the string
                # "AVA", the "A" and "V" glyphs must be rendered with
                # overlapping bounding boxes.
                self.pixels[dstpixel] = (self.pixels[dstpixel] or
                                         src.pixels[srcpixel])
                srcpixel += 1
                dstpixel += 1
            dstpixel += row_offset

class Glyph(object):
    def __init__(self, pixels, width, height, top, advance_x):
        self.bitmap = Bitmap(width, height, pixels)

        # The glyph bitmap's top-side bearing, i.e. the vertical
        # distance from the baseline to the bitmap's top-most scanline.
        self.top = top

        self.descent = max(0, self.height - self.top)
        self.ascent = max(0, max(self.top, self.height) - self.descent)

        # The glyph's advance width in pixels.
        self.advance_x = advance_x

    @property
    def width(self):
        return self.bitmap.width

    @property
    def height(self):
        return self.bitmap.height

    @staticmethod
    def from_glyphslot(slot):
        """Construct and return a Glyph object from a FreeType GlyphSlot."""
        pixels = Glyph.unpack_mono_bitmap(slot.bitmap)
        width, height = slot.bitmap.width, slot.bitmap.rows
        top = slot.bitmap_top

        # The advance width is given in FreeType's 26.6 fixed point format,
        # which means that the pixel values are multiples of 64.
        advance_x = slot.advance.x / 64

        return Glyph(pixels, width, height, top, advance_x)

    @staticmethod
    def unpack_mono_bitmap(bitmap):
        """Unpack a freetype FT_LOAD_TARGET_MONO glyph bitmap into a
        bytearray where each pixel is represented by a single byte.
        """
        # Allocate a bytearray of sufficient size to hold the glyph bitmap.
        data = bytearray(bitmap.rows * bitmap.width)

        # Iterate over every byte in the glyph bitmap. Note that we're not
        # iterating over every pixel in the resulting unpacked bitmap --
        # we're iterating over the packed bytes in the input bitmap.
        for y in range(bitmap.rows):
            for byte_index in range(bitmap.pitch):

                # Read the byte that contains the packed pixel data.
                byte_value = bitmap.buffer[y * bitmap.pitch + byte_index]

                # We've processed this many bits (=pixels) so far.
                # This determines where we'll read the next batch
                # of pixels from.
                num_bits_done = byte_index * 8

                # Pre-compute where to write the pixels that we're going
                # to unpack from the current byte in the glyph bitmap.
                rowstart = y * bitmap.width + byte_index * 8

                # Iterate over every bit (=pixel) that's still a part
                # of the output bitmap. Sometimes we're only unpacking
                # a fraction of a byte because glyphs may not always fit
                # on a byte boundary. So we make sure to stop if we
                # unpack past the current row of pixels.
                for bit_index in range(min(8, bitmap.width - num_bits_done)):

                    # Unpack the next pixel from the current glyph byte.
                    bit = byte_value & (1 << (7 - bit_index))

                    # Write the pixel to the output bytearray. We ensure
                    # that `off` pixels have a value of 0 and `on`
                    # pixels have a value of 1.
                    data[rowstart + bit_index] = 1 if bit else 0

        return data

class Font(object):
    def __init__(self, filename, size):
        self.face = freetype.Face(filename)
        self.face.set_pixel_sizes(0, size)
        self.glyphcache = {}

    def glyph_for_character(self, char):
        # Let FreeType load the glyph for the given character and tell
        # it to render a monochromatic bitmap representation.
        if char in self.glyphcache:
            return self.glyphcache[char]

        self.face.load_char(char, freetype.FT_LOAD_RENDER |
                            freetype.FT_LOAD_TARGET_MONO)
        glyph = Glyph.from_glyphslot(self.face.glyph)
        self.glyphcache[char] = glyph

        return glyph

    def render_character(self, char):
        glyph = self.glyph_for_character(char)
        return glyph.bitmap

    def kerning_offset(self, previous_char, char):
        """Return the horizontal kerning offset in pixels when rendering
        `char` after `previous_char`.

        Use the resulting offset to adjust the glyph's drawing position
        to reduces extra diagonal whitespace, for example in the string
        "AV" the bitmaps for "A" and "V" may overlap slightly with some
        fonts. In this case the glyph for "V" has a negative horizontal
        kerning offset as it is moved slightly towards the "A".
        """
        kerning = self.face.get_kerning(previous_char, char)

        # The kerning offset is given in FreeType's 26.6 fixed point
        # format, which means that the pixel values are multiples of 64.
        return kerning.x / 64

    def text_dimensions(self, text):
        """Return (width, height, baseline) of `text` rendered in the
        current font.
        """
        width, height, baseline = 0, 0, 0
        previous_char = None

        ascent = 0
        descent = 0

        # For each character in the text string we load its glyph bitmap
        # and update TODO
        for char in text:
            glyph = self.glyph_for_character(char)

            # Update the overall height and baseline.
            ascent = max(ascent, glyph.ascent)
            descent = max(descent, glyph.descent)
            baseline = max(baseline, glyph.descent)

            kerning_x = self.kerning_offset(previous_char, char)

            # The advance width may be less than the width of the
            # glyph's bitmap. Make sure we compute the total width so
            # that all of the glyph's pixels fit into the returned
            # dimensions.
            width += max(glyph.advance_x + kerning_x, glyph.width + kerning_x)

            previous_char = char

        height = ascent + descent
        return (width, height, baseline)

    def render_text(self, text, width=None, height=None, baseline=None):
        """Render the given `text` into a Bitmap and return it.

        If `width`, `height`, and `baseline` are not specified they are
        computed using the `text_extents' function.
        """
        if None in (width, height, baseline):
            width, height, baseline = self.text_dimensions(text)

        x, y = 0, 0
        previous_char = None
        outbuffer = Bitmap(width, height)

        for char in text:
            # Adjust the glyph's drawing position if kerning information
            # in the font tells us so. This reduces extra diagonal
            # whitespace, for example in the string "AV" the bitmaps for
            # "A" and "V" overlap slightly.
            x += self.kerning_offset(previous_char, char)

            glyph = self.glyph_for_character(char)
            y = height - glyph.ascent - baseline

            outbuffer.bitblt(glyph.bitmap, x, y)

            x += glyph.advance_x

            previous_char = char

        return outbuffer

    def text_extents(self, text):
        return self.text_dimensions(text)

    def render(self, text, width=None, height=None, baseline=None):
        bmp = self.render_text(text, width, height, baseline)
        return graphics.Surface(bmp.width, bmp.height, pixels=bmp.pixels)

_registered_fonts = {}
_loaded_fonts = {}

def register(name, path):
    _registered_fonts[name] = path
    logging.info('Registered font %s --> %s', name, path)

def get(name, size):
    if not name in _registered_fonts:
        raise KeyError('Unknown font name %s' % name)

    path = _registered_fonts[name]
    hashedname = '%s-%i' % (path, size)

    if hashedname in _loaded_fonts:
        return _loaded_fonts[hashedname]

    logging.info('Loading font %s-%i', name, size)

    fnt = Font(_registered_fonts[name], size)
    _loaded_fonts[hashedname] = fnt

    return fnt


import osmnx as ox
import networkx as nx
from pprint import pprint
import numpy as np
import math
import random
import matplotlib.pyplot as plt
import osmapi as osm

#Api по id получить координаты и другую инфн
api = osm.OsmApi()
#no = api.NodeGet(6567460866)

place = {'city' : 'Saratov',
         'country' : 'Russia'}
G = ox.graph_from_place(place, network_type='drive')

#Рисуем граф дорог
fig, ax = ox.plot_graph(G)

#Словарь расстояний между смежными перекрестками
a = G.adj
dictionary = {}
dict_name = {}

for key, value in a.items():
    for key_a, value_a in value.items():
        if key in dictionary:
            dictionary[key].append({key_a : value_a[0]['length']})
        else:
            dictionary[key] = [{key_a : value_a[0]['length']}]

nodes_list = list(G.nodes())

#Достаем все здания
buildings = ox.footprints.footprints_from_place(place, footprint_type='building', retain_invalid=False, which_result=1)

#Из первых 10000 выбираем 10 больниц и 100 домов
hospital = []
apartments = []
n = 10000
build = buildings.head(n)['building'].to_dict()

for key, value in build.items():
    if value == 'hospital':
        hospital.append(key)
    elif value == 'apartments':
        apartments.append(key)

random.shuffle(hospitals)
random.shuffle(apartments)

hospitals_all = hospitals
apartments_all = apartments
hospitals = hospital[:3]
apartments = apartments[1:11]

print(hospital)
print(apartments)

#Находим ближайшие узлы до домов и больниц
a = buildings.head(n).to_dict()
hospitals_dict = {}
apartments_dict = {}

print('Больницы')
for i in hospitals:
    bounds = a['geometry'][i].bounds
    nearest_node = ox.get_nearest_node(G, ((bounds[1]+bounds[3])/2, (bounds[0]+bounds[2])/2))
    hospitals_dict[i] = nearest_node
    print(i, nearest_node)
print('------------------')
print('Апартаменты')
for i in apartments:
    bounds = a['geometry'][i].bounds
    nearest_node = ox.get_nearest_node(G, ((bounds[1]+bounds[3])/2, (bounds[0]+bounds[2])/2))
    apartments_dict[i] = nearest_node
    print(i, nearest_node)

#Матрица смежности графа
G_pd = nx.to_pandas_adjacency(G)
G_pd = G_pd.values
G_size = len(G_pd)
INF = 10**10

#Заполнение матрицы смежности с учетом условий взвешенного расстояния
for i in range(G_size):
    for j in range(G_size):
        if G_pd[i][j] == 1:
            for k in range(len(dictionary[nodes_list[i]])):
                if nodes_list[j] in dictionary[nodes_list[i]][k].keys():
                    distance = dictionary[nodes_list[i]][k][nodes_list[j]]

            weight = 1
            if nodes_list[i] in hospitals_dict.values():
                weight = random.random() + 1

            G_pd[i][j] = distance * weight

        elif G_pd[i][j] == 0:
            G_pd[i][j] = INF

#Создаем словарь {id узла}: {его index в списке узлов}
nodes_numbers = {}
for index,i in enumerate(nodes_list):
    nodes_numbers[i] = index

#Алгоритм Дейкстры
def Dijkstra(N, S, matrix):
    valid = [True]*N
    weight = [INF]*N
    p = [INF] * N
    p[S] = -1
    weight[S] = 0
    for i in range(N):
        min_weight = INF + 1
        ID_min_weight = -1
        for j in range(N):
            if valid[j] and weight[j] < min_weight:
                min_weight = weight[j]
                ID_min_weight = j
        for z in range(N):
            if weight[ID_min_weight] + matrix[ID_min_weight][z] < weight[z]:
                weight[z] = weight[ID_min_weight] + matrix[ID_min_weight][z]
                p[z] = ID_min_weight
        valid[ID_min_weight] = False
    return weight, p

#1

#Для каждого узла(дома) запускаем алгоритм Д.
from_apartments = {}
from_hospitals = {}
from_apartments_p = {}
from_hospitals_p = {}
print(apartments_dict)
for key, value in apartments_dict.items():
    start = nodes_numbers[value]
    weight, p = Dijkstra(G_size, start, G_pd)

    from_apartments[key] = weight
    from_apartments_p[key] = p

#Для каждого узла(больници) запускаем алгоритм Д.
for key, value in hospitals_dict.items():
    start = nodes_numbers[value]
    weight, p = Dijkstra(G_size, start, G_pd)

    from_hospitals[key] = weight
    from_hospitals_p[key] = p

X = 5000
object_there = {}
object_back = {}
object_there_back = {}

#Вычисляем от каждого узла(дома) расстояние до ближайшей больници
for key_from, value_from in from_apartments.items():
    min_weight = INF
    min_index = -1
    weight_size = len(value_from)

    node_from = apartments_dict[key_from]
    index_from = nodes_numbers[node_from]

    for key_to, value_to in from_hospitals.items():
        node_to = hospitals_dict[key_to]
        index_to = nodes_numbers[node_to]

        #1a
        if value_from[index_to] < min_weight:
            min_weight = value_from[index_to]
            min_index = key_to

        #1b
        if value_from[index_to] < X:
            if key_from in object_there:
                object_there[key_from].append(key_to)
            else:
                object_there[key_from] = [key_to]

    print("min lenght from ", key_from, " to ", min_index, " is ", min_weight)

#Вычисляем от каждого узла(больницы) расстояние до ближайшего дома
mi_to = INF
mi_index_to = -1
for key_from, value_from in from_hospitals.items():
    min_weight = INF
    min_index = -1
    weight_size = len(value_from)

    node_from = hospitals_dict[key_from]
    index_from = nodes_numbers[node_from]

    for key_to, value_to in from_apartments.items():
        node_to = apartments_dict[key_to]
        index_to = nodes_numbers[node_to]

        #1a
        if value_from[index_to] < min_weight:
            min_weight = value_from[index_to]
            min_index = key_to

        #1b
        if value_from[index_to] < X:
            if key_from in object_back:
                object_back[key_from].append(key_to)
            else:
                object_back[key_from] = [key_to]

    print("min lenght from ", key_from, " to ", min_index, " is ", min_weight)

#Находим больницу расстояние до которой и обратно минимально
for key_from, value_from in from_apartments.items():
    node_from = apartments_dict[key_from]
    index_from = nodes_numbers[node_from]

    min_path = INF
    min_index = -1
    for key_to, value_to in from_hospitals.items():
        node_to = hospitals_dict[key_to]
        index_to = nodes_numbers[node_to]

        w = value_from[index_to] + value_to[index_from]

        #1a
        if w < min_path:
            min_path = w
            min_index = key_to

        #1b
        if value_from[index_to] < X:
            if key_from in object_there_back:
                object_there_back[key_from].append(key_to)
            else:
                object_there_back[key_from] = [key_to]

    print("min path from ", key_from, " to ", min_index, " is ", min_path)

#2.2
#Вычисляем от каждого узла(больницы) расстояние до ближайшего дома
weight_min_there = INF
weight_min_back = INF
weight_min_there_back = INF
index_min_there = -1
index_min_back = -1
index_min_there_back = -1

for key_from, value_from in from_hospitals.items():
    node_from = hospitals_dict[key_from]
    index_from = nodes_numbers[node_from]

    weight_there = 0
    weight_back = 0
    weight_there_back = 0
    index_there = -1
    index_back = -1
    index_there_back = -1

    for key_to, value_to in from_apartments.items():
        node_to = apartments_dict[key_to]
        index_to = nodes_numbers[node_to]

        if value_to[index_from] > weight_there:
            weight_there = value_to[index_from]
            index_there = key_from

        if value_from[index_to] > weight_back:
            weight_back = value_from[index_to]
            index_back = key_from

        w = value_to[index_from] + value_from[index_to]

        if w > weight_there_back:
            weight_there_back = w
            index_there_back = key_from

    if weight_there < weight_min_there:
        weight_min_there = weight_there
        index_min_there = index_there

    if weight_back < weight_min_back:
        weight_min_back = weight_back
        index_min_back = index_back

    if weight_there_back < weight_min_there_back:
        weight_min_there_back = weight_there_back
        index_min_there_back = index_there_back

print("there: ", index_min_there, weight_min_there)
print("back: ", index_min_back, weight_min_back)
print("there and back: ", index_min_there_back, weight_there_back)

#2.3
#Больница до которой сумма расстояний до всех домов из выборки минимальна
min_s = INF
min_index = -1
for key_from, value_from in from_hospitals.items():
    node_from = hospitals_dict[key_from]
    index_from = nodes_numbers[node_from]

    s = 0

    for key_to, value_to in from_apartments.items():
        node_to = apartments_dict[key_to]
        index_to = nodes_numbers[node_to]

        s += value_from[index_to]

    if s < min_s:
        min_s = s
        min_index = key_from

print("min sum: ", key_from, min_s)

#2.4
#Дерево кратчайших путей минимально
s_min = INF
index_min = -1
for key_from, value_from in from_hospitals_p.items():
    node_from = hospitals_dict[key_from]
    index_from = nodes_numbers[node_from]

    s = 0

    used = [0] * G_size

    for key_to, value_to in from_apartments.items():
        node_to = apartments_dict[key_to]
        index_to = nodes_numbers[node_to]

        v = index_to
        start = index_from
        while v != start:
            if used[v] == 0:
                used[v] = 1
                s += G_pd[value_from[v]][v]
            v = value_from[v]

    if s < s_min:
        s_min = s
        index_min = key_from

print("min tree: ", index_min, s_min)

#3.1
#Дерево кратчайших путей
hospitals_list = list(hospitals)
KEY = hospitals_list[random.randint(0, 2)]
node_from = hospitals_dict[KEY]
index_from = nodes_numbers[node_from]

value_from = from_hospitals_p[KEY]

s_tree = 0
s_paths = 0

used = [0] * G_size

for key_to, value_to in from_apartments.items():
    node_to = apartments_dict[key_to]
    index_to = nodes_numbers[node_to]

    v = index_to
    start = index_from
    while v != start:
        if used[v] == 0:
            used[v] = 1
            s_tree += G_pd[value_from[v]][v]
        s_paths += G_pd[value_from[v]][v]

        v = value_from[v]

print("weight tree: ", KEY, s_tree)
print("weight paths: ", KEY, s_paths)

#3.2
from scipy.cluster.hierarchy import dendrogram, linkage

a = []

for key in apartments:
    node = apartments_dict[key]
    a.append([G.nodes[node]['x'], G.nodes[node]['y']])

X = np.array(a)

print(X.shape)
print(X)
#Удаляем точку по приколу - она лежит слишком далеко и график будет плохим
#X = X[1:]
plt.scatter(X[:,0], X[:,1])
plt.show()

Z = linkage(X, 'ward')

print(Z)

from scipy.cluster.hierarchy import cophenet
from scipy.spatial.distance import pdist

c, coph_dists = cophenet(Z, pdist(X))
c

# calculate full dendrogram
plt.figure(figsize=(25, 10))
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('sample index')
plt.ylabel('distance')
dendrogram(
    Z,
    leaf_rotation=90.,  # rotates the x axis labels
    leaf_font_size=8.,  # font size for the x axis labels
)
plt.show()

from scipy.cluster.hierarchy import fcluster

def get_path(start, finish, p):
    path = []
    while finish != start:
        path.append(nodes_list[finish])
        finish = p[finish]

    path.reverse()
    return path

def centr(X, Z, k, hosp_ind):
    clusters = fcluster(Z, k, criterion='maxclust')

    print(clusters)

    plt.figure()
    plt.scatter(X[:,0], X[:,1], c=clusters, cmap='prism')  # plot points with cluster dependent %colors

    clusters_us = {}
    clusters_us_id = {}
    for i in range(len(clusters)):
        j = clusters[i]
        if j in clusters_us:
            clusters_us[j].append(X[i])
            clusters_us_id[j].append(i)
        else:
            clusters_us[j] = [X[i]]
            clusters_us_id[j] = [i]

    for key, value in clusters_us.items():
        clusters_us[key] = np.array(value)
    print(clusters_us)
    print(clusters_us_id)

    #a
    centroids = {}
    centroids_node = {}
    for key, value in clusters_us.items():
        n = len(value)
        x = sum(value[:, 0]) / n
        y = sum(value[:, 1]) / n
        centroids[key] = [x, y]

        centroids_node[key] = ox.get_nearest_node(G, (y, x))
        plt.scatter(x, y)

    print(centroids)
    print(centroids_node)

    plt.show()

    #b
    node_from = hospitals_dict[hosp_ind]
    index_from = nodes_numbers[node_from]
    weight, p = Dijkstra(G_size, index_from, G_pd)

    routes = []
    for key, value in centroids_node.items():
        v = nodes_numbers[value]

        path = get_path(index_from, v, p)
        routes.append(np.array(path))

    fig, ax = ox.plot_graph_routes(G, routes,
                                   node_alpha=0, edge_color='lightgray', edge_alpha=1, edge_linewidth=0.8,
                                   route_color='#00cc66', route_linewidth=0.8, route_alpha=1,
                                   orig_dest_node_size=10, orig_dest_node_color='r', orig_dest_node_alpha=1)

    name = 'obj_to_centroids'
    ox.plot.save_and_show(fig, ax, save=True, show=False, filename=name, file_format='png', close=True,
                          dpi=500, axis_off=True)

    #c
    routes = []
    print("apart", apartments)
    print(apartments_dict)

    for key, value in clusters_us_id.items():
        cent_node = centroids_node[key]
        start = nodes_numbers[cent_node]
        weight, p = Dijkstra(G_size, start, G_pd)

        #route = nx.shortest_path(G, node_from, cent_node, weight='length')
        print(value)
        for i in value:
            print(apartments[i], apartments_dict[apartments[i]], nodes_numbers[apartments_dict[apartments[i]]])
            path = get_path(start, nodes_numbers[apartments_dict[apartments[i]]], p)
            routes.append(np.array(path))

        #rc = ['r'] * (len(route) - 1)
        #nc = ['r', 'r']
    fig, ax = ox.plot_graph_routes(G, routes,
                                   node_alpha=0, edge_color='lightgray', edge_alpha=1, edge_linewidth=0.8,
                                   route_color='#00cc66', route_linewidth=0.8, route_alpha=1,
                                   orig_dest_node_size=10, orig_dest_node_color='r', orig_dest_node_alpha=1)

    name=str(key)
    ox.plot.save_and_show(fig, ax, save=True, show=False, filename=name, file_format='png', close=True,
                          dpi=500, axis_off=True)

k = 3
#print(G.nodes[421435796]['x'], G.nodes[421435796]['y'])
centr(X, Z, k, KEY)


# -*- encoding: utf-8 -*-
from django.contrib.auth.models import AbstractUser, Permission, Group
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.core.exceptions import PermissionDenied
from django.db.models.signals import m2m_changed
from django_countries.fields import CountryField
from django.utils.safestring import mark_safe
from django.utils.text import slugify
from django.conf import settings
from django.urls import reverse
from django.db import models

from localflavor.mx.models import MXRFCField, MXZipCodeField, MXCURPField
from mptt.models import MPTTModel, TreeForeignKey
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
from simple_history.models import HistoricalRecords

import datetime

from .vars import *

def permissions(VARS):
	permissions = []
	if not 'EXC_PERM' in VARS:
		VARS['EXC_PERM'] = []
	if not 'ALL' in  VARS['EXC_PERM']:
		if not 'DETAIL' in VARS['EXC_PERM']:
			permissions.append(('Can_Detail__'+VARS['MODEL'],'Ve lista de '+VARS['VERBOSE_NAME_PLURAL'].lower()))
		if not 'CREATE' in VARS['EXC_PERM']:
			permissions.append(('Can_Create__'+VARS['MODEL'],'Crea '+VARS['VERBOSE_NAME_PLURAL'].lower()))
		if not 'UPDATE' in VARS['EXC_PERM']:
			permissions.append(('Can_Update__'+VARS['MODEL'],'Modifica '+VARS['VERBOSE_NAME_PLURAL'].lower()))
		if not 'DELETE' in VARS['EXC_PERM']:
			permissions.append(('Can_Delete__'+VARS['MODEL'],'Elimina '+VARS['VERBOSE_NAME_PLURAL'].lower()))
	if 'EXT_PERM' in VARS:
		for perm in VARS['EXT_PERM']:
			permissions.append(perm)
	return permissions

VARS = {
	'VERBOSE_NAME':'',
	'VERBOSE_NAME_PLURAL':'',
	'MODEL':'',
	'NEW':'',
	'GENDER_NEW':'',
	'GENDER_THIS':'',
	'APP':APP,
	'EXC_PERM': ['ALL'],
	'EXT_PERM': [],
	'QUERY':{
		'query':[
			(
				('pk','self.request.session.get("organization")).get_descendants(include_self=True)'),
			)
		],
	},
	'SERIALIZER': ['field'],
	'RULES': """
		email: {
			required: !0,
			email: !0,
			minlength: 10
		},
		url: {
			required: !0
		},
		digits: {
			required: !0,
			digits: !0
		},
		creditcard: {
			required: !0,
			creditcard: !0
		},
		phone: {
			required: !0,
			phoneUS: !0
		},
		option: {
			required: !0
		},
		options: {
			required: !0,
			minlength: 2,
			maxlength: 4
		},
		memo: {
			required: !0,
			minlength: 10,
			maxlength: 100
		},
		checkbox: {
			required: !0
		},
		checkboxes: {
			required: !0,
			minlength: 1,
			maxlength: 2
		},
		radio: {
			required: !0
		}
	""",
}
class Model_base(models.Model):
	slug = models.SlugField(blank=True, null=True)
	active = models.BooleanField(default=True)
	VARS = VARS
	class Meta:
		default_permissions = ()
		verbose_name = VARS['VERBOSE_NAME']
		verbose_name_plural = VARS['VERBOSE_NAME_PLURAL']
		permissions = permissions(VARS)
		abstract = True
		ordering = ['-id']
	def str_obj(self):
		return str(self)
	def str_select2(self):
		return self.str_obj()
	def add_text(self):
		return self.VARS['NEW']+" "+self.VARS['VERBOSE_NAME'].upper(),"Agregar "+self.VARS['VERBOSE_NAME'].lower(),"Agrega "+self.VARS['GENDER_NEW']+" "+self.VARS['VERBOSE_NAME'].lower()+"al sistema"
	def edit_text(self):
		return "EDITAR "+self.VARS['VERBOSE_NAME'].upper(),"Editar "+self.VARS['VERBOSE_NAME'].lower(),"Edita los datos de "+self.VARS['GENDER_THIS']+" "+self.VARS['VERBOSE_NAME'].lower()+"al sistema"
	def delete_text(self):
		return "ELIMINAR "+ self.VARS['VERBOSE_NAME'].upper(),"Eliminar "+self.VARS['VERBOSE_NAME'].lower(),"Elimina los datos de "+self.VARS['GENDER_THIS']+" "+self.VARS['VERBOSE_NAME'].lower(),"Se eliminará "+self.VARS['GENDER_THIS']+" "+self.VARS['VERBOSE_NAME'].lower()+" y todos sus datos asociados!"
	def url_list(self):
		try:
			return reverse(self.VARS['APP']+':'+self.VARS['MODEL']+'_ListView')
		except:
			return ''
	def url_add(self):
		try:
			return reverse(self.VARS['APP']+':'+self.VARS['MODEL']+'_CreateView')
		except:
			return ''
	def url_update(self):
		try:
			return reverse(self.VARS['APP']+':'+self.VARS['MODEL']+'_UpdateView',kwargs={'pk': self.pk})
		except:
			return ''
	def url_detail(self):
		try:
			return reverse(self.VARS['APP']+':'+self.VARS['MODEL']+'_DetailView',kwargs={'pk': self.pk})
		except:
			return ''
	def url_delete(self):
		try:
			return reverse(self.VARS['APP']+':'+self.VARS['MODEL']+'_DeleteView',kwargs={'pk': self.pk})
		except:
			return ''
	################################
	################################
	def render_boolean(self, field):
		if field:
			return ''
		else:
			return ''
	def render_color_boolean(self, field):
		if field:
			return 'success'
		else:
			return 'danger'
	def render_boolean_del(self, text, attr):
		if not attr:
			return '<s>{0}</s>'.format(text)
		return text
	def render_color(self, field):
		return ''
	def render_list(self, list, attr):
		string = ''
		if not list.all():
			return '-'
		for l in list.all():
			string += getattr(l, attr) + ', '
		return string[0:len(string)-2]
	def render_ifnot(self, attr):
		if not attr:
			return '-'
		return attr
	def render_ifnot_link(self, attr):
		if not attr:
			return '-'
		return str(self.attr)
	def render_date(self, attr):
		return attr.strftime('%d/%m/%Y')
	def get_select2(self):
		return self.name
	def max_string(self, field, value):
		string = getattr(self, field)[0:value]
		if len(getattr(self, field)) > value:
			string += '...'
		return string

	################################
	################################
	def my_organization(self):
		return self.organization


import torch
from utils.funcs import one_iter_joint_training_sim_fix_stoch_encoder, one_iter_rx_meta_tx_joint_sim_fix_stoch_encoder
from data_gen.data_set import channel_set_gen_AR
from utils.basic_funcs import reset_randomness

def multi_task_learning(args, tx_net,rx_net, h_list_meta, writer_meta_training, Noise, Noise_relax, Noise_feedback, PATH_before_adapt_rx_intermediate, PATH_before_adapt_tx_intermediate):
    meta_optimiser_tx = torch.optim.Adam(tx_net.parameters(), args.lr_meta_update)
    meta_optimiser_rx = torch.optim.Adam(rx_net.parameters(), args.lr_meta_update)
    h_list_train = h_list_meta[:args.num_channels_meta]

    if args.if_fix_random_seed:
        random_seed_init = args.random_seed + 99999
    else:
        pass
    previous_channel = None

    for epochs in range(args.num_epochs_meta_train):
        if epochs % 100 == 0:
            curr_path_rx = PATH_before_adapt_rx_intermediate + str(epochs)
            curr_path_tx = PATH_before_adapt_tx_intermediate + str(epochs)
            torch.save(rx_net.state_dict(), curr_path_rx)
            torch.save(tx_net.state_dict(), curr_path_tx)
            print('stochactic meta-learning epoch', epochs)
        first_loss_rx = 0
        second_loss_rx = 0
        first_loss_tx = 0
        second_loss_tx = 0
        iter_in_sampled_device = 0  # for averaging meta-devices
        for ind_meta_dev in range(args.tasks_per_metaupdate):
            if args.if_always_generate_new_meta_training_channels:
                if args.if_fix_random_seed:
                    reset_randomness(random_seed_init) # to make noise same as much as possible for joint and meta
                    random_seed_init += 1
                else:
                    pass
                if args.if_Rayleigh_channel_model_AR:
                    if epochs % args.keep_AR_period == 0:
                        h_var_dist = torch.distributions.uniform.Uniform(torch.FloatTensor([args.mul_h_var_min]), torch.FloatTensor([args.mul_h_var_max]))
                        mul_h_var = h_var_dist.sample()
                        if_reset_AR = True
                    else:
                        if_reset_AR = False
                    current_channel = channel_set_gen_AR(args.tap_num, previous_channel, args.rho, mul_h_var, if_reset_AR)  # num_channels = 1 since we are generating per channel
                    previous_channel = current_channel
                else:
                    raise NotImplementedError
            else:
                if args.if_fix_random_seed:
                    reset_randomness(random_seed_init) # to make noise same as much as possible for joint and meta
                    random_seed_init += 1
                else:
                    pass
                # during this, meta-gradients are accumulated
                channel_list_total = torch.randperm(len(h_list_train))  # sampling with replacement
                current_channel_ind = channel_list_total[
                    ind_meta_dev]  # randomly sample meta-batches (no rep. inside meta-batch)
                current_channel = h_list_train[current_channel_ind]

            if args.if_joint_training:
                iter_in_sampled_device, first_loss_curr_rx, first_loss_curr_tx, second_loss_curr_rx, second_loss_curr_tx = joint_training(args, iter_in_sampled_device,
                                                                                tx_net, rx_net,
                                                                                current_channel, Noise, Noise_relax, Noise_feedback)
            elif args.if_joint_training_tx_meta_training_rx:
                iter_in_sampled_device, first_loss_curr_rx, first_loss_curr_tx, second_loss_curr_rx, second_loss_curr_tx = maml_for_rx_joint_for_tx(
                    args, iter_in_sampled_device,
                    tx_net, rx_net,
                    current_channel, Noise, Noise_relax, Noise_feedback)
            else:  # maml
                raise NotImplementedError
            first_loss_rx = first_loss_rx + first_loss_curr_rx
            second_loss_rx = second_loss_rx + second_loss_curr_rx
            first_loss_tx = first_loss_tx + first_loss_curr_tx
            second_loss_tx = second_loss_tx + second_loss_curr_tx
        first_loss_tx = first_loss_tx / args.tasks_per_metaupdate
        second_loss_tx = second_loss_tx / args.tasks_per_metaupdate
        first_loss_rx = first_loss_rx / args.tasks_per_metaupdate
        second_loss_rx = second_loss_rx / args.tasks_per_metaupdate
        writer_meta_training.add_scalar('first rx loss', first_loss_rx, epochs)
        writer_meta_training.add_scalar('first tx loss', first_loss_tx, epochs)
        writer_meta_training.add_scalar('second rx loss', second_loss_rx, epochs)
        writer_meta_training.add_scalar('second tx loss', second_loss_tx, epochs)
        meta_optimiser_rx.zero_grad()
        meta_optimiser_tx.zero_grad()
        for f in rx_net.parameters():
            f.grad = f.total_grad.clone() / args.tasks_per_metaupdate
        for f in tx_net.parameters():
            f.grad = f.total_grad.clone() / args.tasks_per_metaupdate
        meta_optimiser_rx.step()  # Adam
        meta_optimiser_tx.step()  # Adam

def joint_training(args, iter_in_sampled_device, tx_net, rx_net, current_channel, Noise, Noise_relax, Noise_feedback):
    tx_net.zero_grad()
    rx_net.zero_grad()
    para_list_from_tx_net = list(map(lambda p: p[0], zip(tx_net.parameters())))
    para_list_from_rx_net = list(map(lambda p: p[0], zip(rx_net.parameters())))
    #### get gradients for joint training
    if_local_update = False
    remove_dependency_to_updated_para = False
    inner_loop = None # no need here, it is only for computing exact score function of tx meta-gradient

    if args.tx_rx_training_mode == 0:
        joint_grad_rx, joint_grad_tx, second_loss_curr_rx, second_loss_curr_tx = one_iter_joint_training_sim_fix_stoch_encoder(args, current_channel, Noise, Noise_relax, Noise_feedback,
                                                                              para_list_from_tx_net,
                                                                              para_list_from_rx_net,
                                                                              para_list_from_tx_net,
                                                                              para_list_from_rx_net,
                                                                              if_local_update,
                                                                              remove_dependency_to_updated_para,
                                                                              inner_loop)
    else:
        raise NotImplementedError

    ##### accumulate gradients for joint training over different channels
    ind_f_para_list = 0
    for f in rx_net.parameters():
        if iter_in_sampled_device == 0:
            f.total_grad = joint_grad_rx[ind_f_para_list].clone().detach()  # f.grad
        else:
            f.total_grad = f.total_grad + joint_grad_rx[ind_f_para_list].clone().detach()  # f.grad
        ind_f_para_list += 1

    ind_f_para_list = 0
    for f in tx_net.parameters():
        if iter_in_sampled_device == 0:
            f.total_grad = joint_grad_tx[ind_f_para_list].clone().detach()  # f.grad
        else:
            f.total_grad = f.total_grad + joint_grad_tx[ind_f_para_list].clone().detach()  # f.grad
        ind_f_para_list += 1
    iter_in_sampled_device = iter_in_sampled_device + 1

    return iter_in_sampled_device, second_loss_curr_rx, second_loss_curr_tx, second_loss_curr_rx, second_loss_curr_tx

def maml_for_rx_joint_for_tx(args, iter_in_sampled_device, tx_net, rx_net, current_channel, Noise, Noise_relax, Noise_feedback):
    tx_net.zero_grad()
    rx_net.zero_grad()
    para_list_from_tx_net = list(map(lambda p: p[0], zip(tx_net.parameters())))
    para_list_from_rx_net = list(map(lambda p: p[0], zip(rx_net.parameters())))

    ####here comes from ftn.
    if args.tx_rx_training_mode == 0:
        meta_grad_rx, joint_grad_tx, first_loss_curr_rx, first_loss_curr_tx, second_loss_curr_rx, second_loss_curr_tx = one_iter_rx_meta_tx_joint_sim_fix_stoch_encoder(args, current_channel, Noise, Noise_relax, Noise_feedback,
                                                        para_list_from_tx_net, para_list_from_rx_net)

    else:
        print('we have only 3 modes, 0, 1, 2 currently')
        raise NotImplementedError
    ##### accumulate meta-gradients over different channels (meta-training channels)
    ind_f_para_list = 0
    for f in rx_net.parameters():
        if iter_in_sampled_device == 0:
            f.total_grad = meta_grad_rx[ind_f_para_list].clone().detach()  # f.grad
        else:
            f.total_grad = f.total_grad + meta_grad_rx[ind_f_para_list].clone().detach()  # f.grad
        ind_f_para_list += 1
    ind_f_para_list = 0
    for f in tx_net.parameters():
        if iter_in_sampled_device == 0:
            f.total_grad = joint_grad_tx[ind_f_para_list].clone().detach()  # f.grad
        else:
            f.total_grad = f.total_grad + joint_grad_tx[ind_f_para_list].clone().detach()  # f.grad
        ind_f_para_list += 1
    iter_in_sampled_device = iter_in_sampled_device + 1

    return iter_in_sampled_device, first_loss_curr_rx, first_loss_curr_tx, second_loss_curr_rx, second_loss_curr_tx


"""Event model module"""
from django.db import models

class Event(models.Model):
    """Event database model"""
    gamer = models.ForeignKey("Gamer", on_delete=models.CASCADE)
    description = models.CharField(max_length=75)
    game = models.ForeignKey("Game", on_delete=models.CASCADE)
    date = models.DateField(auto_now=False, auto_now_add=False)
    time = models.TimeField(auto_now=False, auto_now_add=False)


##encoding=utf8
##version =py27, py33
##author  =sanhe
##date    =2014-10-15

from __future__ import print_function

from HSH.Data.iterable import cycle_running_windows, cycle_slice
from HSH.DataSci.stat import clear_outlier_onetime
import numpy as np, pandas as pd
import matplotlib.pyplot as plt
from collections import deque
from itertools import count

def fetch_ith(i):
    """return the i th sample
    """
    data = pd.read_csv("raw_data.csv", index_col = 0)
    return data.iloc[i]

def generator_backward_forward_running_average(array, window_size):
    """
    array = [1,2,3,4,5,6,7,8,9,10]
    for value, backward_running_average, forward_running_average in g_b_f_r_a(array, 3):
        yield 1, (8+9+10)/3, (2+3+4)/3
        yield 2, (9+10+1)/3, (3+4+5)/3
        ...
    """
    before, after = deque(array), deque(array)
    before.rotate(window_size)
    after.rotate(-1)
    for value, before_window, after_window in zip(array,
                                                  cycle_running_windows(before, window_size),
                                                  cycle_running_windows(after, window_size)):
        yield value, float(sum(before_window))/window_size, float(sum(after_window))/window_size

def backward_range(start, n, cycle_size):
    """backward generate #n integers start from #start-1.
    from cycle [0, 1, 2, ..., #cycle_size-1]
    e.g.
        backward_range(5, 2, 10) -> [3, 4]
        backward_range(3, 5, 10) -> [8, 9, 0, 1, 2]
    """
    if start >= n:
        return list(range(start - n, start))
    else:
        return list(range(cycle_size + start - n, cycle_size)) + list(range(start))

def forward_range(start, n, cycle_size):
    """forward generate #n integers start from #start+1.
    from cycle [0, 1, 2, ..., #cycle_size-1]
    e.g.
        forward_range(5, 3, 10) -> [6, 7, 8]
        forward_range(7, 5, 10) -> [8, 9, 0, 1, 2]
    """
    if start + n <= cycle_size - 1:
        return range(start + 1, start + 1 + n)
    else:
        return list(range(start + 1, cycle_size)) + list(range(start + 1 + n - cycle_size))

def merge_setpoints(array, k, size):
    """
    Because for every setpoints, it take time to taken effects.
    So we merge setpoints to the earliest one. (backward merge)
    """
    array_set = set(array) # create a set copy. make examing is in faster
    res = list()
    for i in array:
        flag = 1 # 在一开始，总认为这个setpoint是不需要merge的
        for j in backward_range(i, k, size): # 对于i之前的k个setpoint
            if j in array_set: # 只要有1个也是setpoint，那么这个就可以被merge到前面去
                flag = 0
                break
        if flag:
            res.append(i)
    return res

def produce_by_setpoint(setpoint_indices, setpoint_values, length):
    """generate rectangle wave by set points
    e.g. produce_by_setpoint([4, 7], [1.1, 3.3], 10)
    [3.3, 3.3, 3.3, 3.3, ]
    """
    res = deque()
    number_of_setpoints = len(setpoint_indices)
    for i in range(length):
        ind = (sum(np.linspace(i,i,number_of_setpoints) > setpoint_indices ) - 1) % number_of_setpoints
        res.append(setpoint_values[ind])
    res.rotate(-2)
    return list(res)

def main(window_size = 6, k = 8):
    """
    [Parameters]
    ------------
    window_size: running average window size
    k: the second parameters in merge_setpoints(array, k, size)
    """
    ### Initial dataset
    sample = fetch_ith(68).values.tolist() # fetch the ith sample
    e = abs(np.diff(sample)).std()*1 # delta_before criterion
    c = count() # sample index counter
    potential_setpoint_indices_rise = list()

    for value, mean_before, mean_after in generator_backward_forward_running_average(sample, window_size):
        counter = next(c)
        dt_before, dt_after = value - mean_before, mean_after - value

        if abs(dt_before) >= e:
            potential_setpoint_indices_rise.append(counter)

    print("e = %s" % e) # 门限
    print(potential_setpoint_indices_rise)
    setpoint_indices = merge_setpoints(potential_setpoint_indices_rise, k, 96)
    setpoint_values = list()
    for i, j in cycle_running_windows(setpoint_indices, 2): # 计算均值
        setpoint_values.append(
                               np.mean(
                                       clear_outlier_onetime(
                                                             cycle_slice(sample, i, j)
                                                             )
                                       )
                               )

    step_func = produce_by_setpoint(setpoint_indices, setpoint_values, 96)
    print(setpoint_indices, setpoint_values, 96)

    plt.plot(sample)
    plt.plot(step_func)
    plt.show()

if __name__ == "__main__":
    main(window_size = 6, k = 8)


class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def __dfs(idx, res, pre, nums):
            if not idx:
                res.append(pre[:])
                return
            temp = idx.copy()
            for i in temp:
                pre.append(nums[i])
                idx.remove(i)
                __dfs(idx, res, pre, nums)
                idx.append(i)
                pre.pop()

        idx = []
        res = []
        pre = []
        for i in range(len(nums)):
            idx.append(i)
        __dfs(idx, res, pre, nums)
        return res

from typing import List

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def dfs(nums, size, depth, path, state, res):
            if depth == size:
                res.append(path)
                return

            for i in range(size):
                if ((state >> i) & 1) == 0:
                    dfs(nums, size, depth + 1, path + [nums[i]], state ^ (1 << i), res)

        size = len(nums)
        if size == 0:
            return []

        state = 0
        res = []
        dfs(nums, size, 0, [], state, res)
        return res


"""
Plotting utilities to visualize training logs.
"""
import torch
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from pathlib import Path, PurePath

def plot_logs(logs, fields=('class_error', 'loss_bbox_unscaled', 'mAP'), ewm_col=0, log_name='log.txt'):
    '''
    Function to plot specific fields from training log(s). Plots both training and test results.

    :: Inputs - logs = list containing Path objects, each pointing to individual dir with a log file
              - fields = which results to plot from each log file - plots both training and test for each field.
              - ewm_col = optional, which column to use as the exponential weighted smoothing of the plots
              - log_name = optional, name of log file if different than default 'log.txt'.

    :: Outputs - matplotlib plots of results in fields, color coded for each log file.
               - solid lines are training results, dashed lines are test results.

    '''
    func_name = "plot_utils.py::plot_logs"

    # verify logs is a list of Paths (list[Paths]) or single Pathlib object Path,
    # convert single Path to list to avoid 'not iterable' error

    if not isinstance(logs, list):
        if isinstance(logs, PurePath):
            logs = [logs]
            print(f"{func_name} info: logs param expects a list argument, converted to list[Path].")
        else:
            raise ValueError(f"{func_name} - invalid argument for logs parameter.\n \
            Expect list[Path] or single Path obj, received {type(logs)}")

    # Quality checks - verify valid dir(s), that every item in list is Path object, and that log_name exists in each dir
    for i, dir in enumerate(logs):
        if not isinstance(dir, PurePath):
            raise ValueError(f"{func_name} - non-Path object in logs argument of {type(dir)}: \n{dir}")
        if not dir.exists():
            raise ValueError(f"{func_name} - invalid directory in logs argument:\n{dir}")
        # verify log_name exists
        fn = Path(dir / log_name)
        if not fn.exists():
            print(f"-> missing {log_name}.  Have you gotten to Epoch 1 in training?")
            print(f"--> full path of missing log file: {fn}")
            return

    # load log file(s) and plot
    dfs = [pd.read_json(Path(p) / log_name, lines=True) for p in logs]

    fig, axs = plt.subplots(ncols=len(fields), figsize=(16, 5))

    for df, color in zip(dfs, sns.color_palette(n_colors=len(logs))):
        for j, field in enumerate(fields):
            if field == 'mAP':
                coco_eval = pd.DataFrame(
                    np.stack(df.test_coco_eval_bbox.dropna().values)[:, 1]
                ).ewm(com=ewm_col).mean()
                axs[j].plot(coco_eval, c=color)
            else:
                df.interpolate().ewm(com=ewm_col).mean().plot(
                    y=[f'train_{field}', f'test_{field}'],
                    ax=axs[j],
                    color=[color] * 2,
                    style=['-', '--']
                )
    for ax, field in zip(axs, fields):
        ax.legend([Path(p).name for p in logs])
        ax.set_title(field)

def plot_precision_recall(files, naming_scheme='iter'):
    if naming_scheme == 'exp_id':
        # name becomes exp_id
        names = [f.parts[-3] for f in files]
    elif naming_scheme == 'iter':
        names = [f.stem for f in files]
    else:
        raise ValueError(f'not supported {naming_scheme}')
    fig, axs = plt.subplots(ncols=2, figsize=(16, 5))
    for f, color, name in zip(files, sns.color_palette("Blues", n_colors=len(files)), names):
        data = torch.load(f)
        # precision is n_iou, n_points, n_cat, n_area, max_det
        precision = data['precision']
        recall = data['params'].recThrs
        scores = data['scores']
        # take precision for all classes, all areas and 100 detections
        precision = precision[0, :, :, 0, -1].mean(1)
        scores = scores[0, :, :, 0, -1].mean(1)
        prec = precision.mean()
        rec = data['recall'][0, :, 0, -1].mean()
        print(f'{naming_scheme} {name}: mAP@50={prec * 100: 05.1f}, ' +
              f'score={scores.mean():0.3f}, ' +
              f'f1={2 * prec * rec / (prec + rec + 1e-8):0.3f}'
              )
        axs[0].plot(recall, precision, c=color)
        axs[1].plot(recall, scores, c=color)

    axs[0].set_title('Precision / Recall')
    axs[0].legend(names)
    axs[1].set_title('Scores / Recall')
    axs[1].legend(names)
    return fig, axs

# COCO classes
CLASSES_COCO = [
    'N/A', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A',
    'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse',
    'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack',
    'umbrella', 'N/A', 'N/A', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis',
    'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove',
    'skateboard', 'surfboard', 'tennis racket', 'bottle', 'N/A', 'wine glass',
    'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich',
    'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake',
    'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table', 'N/A',
    'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard',
    'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A',
    'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier',
    'toothbrush'
]

# colors for visualization
COLORS = [[0.000, 0.447, 0.741], [0.850, 0.325, 0.098], [0.929, 0.694, 0.125],
          [0.494, 0.184, 0.556], [0.466, 0.674, 0.188], [0.301, 0.745, 0.933]]

def plot_bbox_results(pil_img, prob, boxes, savepath=None, id2name=None):
    plt.figure(figsize=(16,10))
    plt.imshow(pil_img)
    ax = plt.gca()
    for p, (xmin, ymin, xmax, ymax), c in zip(prob, boxes.tolist(), COLORS * 100):
        ax.add_patch(plt.Rectangle((xmin, ymin), xmax - xmin, ymax - ymin,
                                   fill=False, color=c, linewidth=3))
        cl = p.argmax()
        if id2name is None:
            text = f'{CLASSES_COCO[cl]}: {p[cl]:0.2f}'
        else:
            cl = cl.item()
            text = f'{id2name[cl]}: {p[cl]:0.2f}'
        ax.text(xmin, ymin, text, fontsize=15,
                bbox=dict(facecolor='yellow', alpha=0.5))
    plt.axis('off')
    if savepath is None:
        plt.show()
    else:
        plt.savefig(savepath)


## Student_management_programing
import json
import os

jsonResult = []

def ask_path():
    ask = input("안녕하세요! 학생 주소록 관리 프로그램을 시작합니다. 경로에 파일이 없습니다. \n 1. 경로를 입력합니다.  2. 기본 경로로 생성하겠습니다.\n 메뉴를 선택하세요 : ")
    if ask == '1':
        path = input("새로운 경로를 입력하세요 : ")
        print("새로운 경로에 저장합니다.")
        return path
    else:
        print("기본경로로 생성하겠습니다.")
        path = 'ITT_Student.json'
        return path

def main_intro():
    print("")
    print("<< json 기반 주소록 관리 프로그램 >>")
    print("  1. 학생 정보 입력")
    print("  2. 학생 정보 조회")
    print("  3. 학생 정보 수정")
    print("  4. 학생 정보 삭제")
    print("  5. 프로 그램 종료")

def student_ID_number():
    try:
        if not os.path.isfile("ITT_Student.json"):
            with open('count.txt','w') as file:
                counter = '1'
                file.write(counter)
            student_id = "ITT" + counter.zfill(3)
            return  student_id
        else:
            with open('count.txt','r') as file:
                counter = file.readline()
                counter = int(counter) + 1
                student_id = "ITT" + str(counter).zfill(3)

            with open('count.txt', 'w') as file:
                file.write(str(counter))
            return student_id

    except FileNotFoundError:
        if len(jsonResult) == 0:
            counter = '1'
            student_id = "ITT" + counter.zfill(3)
            with open("count.txt",'w') as file:
                file.write(counter)
            return  student_id
        else:
            counter = str(len(jsonResult) + 1)
            with open('count.txt', 'w') as file:
                file.write(counter)
            student_id = "ITT" + counter.zfill(3)
            return student_id

def info_insert():
    student_dic = {}
    recent_info_list = []
    student_dic['name'] = input("이름을 입력하세요 : ")
    student_dic['age'] = str(input("나이를 입력하세요 : "))
    student_dic['address'] = input("주소를 입력하세요 : ")
    student_dic['past_record'] = input("과거 수강 횟수를 입력하세요 : ")
    while True:
        select = input("현재 강의 정보를 추가하시겠습니까? (y/n) : ")
        if select == 'y':
            recent_info_list.append(info_insert_course())
            student_dic['recent_info'] = recent_info_list
            continue
        else:
            break
    student_dic['student_ID'] = student_ID_number()
    jsonResult.append(student_dic)
    print("--------- 학생 정보가 입력되었습니다 ---------")

def info_insert_course():
    recent_info = {}
    recent_info['강의코드'] = input("현재 수강 과목 코드를 기입하세요 : ")
    recent_info['강의명'] = input("강의명을 입력하세요 : ")
    recent_info['강사명'] = input("강사명을 입력하세요 : ")
    recent_info['개강일'] = input("개강일을 입력하세요 : ")
    recent_info['종료일'] = input("종료일을 입력하세요 : ")
    return recent_info

def info_input():
    print("")
    print("--------- 학생 정보 조회를 시작합니다 ---------")
    print("1. 전체 항목 대상 조회")
    print("\t검색 조건 선택\t")
    print("2. 학생 이름")
    print("3. 학생 나이")
    print("4. 학생 주소")
    print("5. 학생 ID")
    print("6. 과거 수강 횟수")
    print("7. 강의명")
    print("8. 강사명")
    print("9. 강의코드")
    print("10. 이전화면으로 되돌아갑니다")
    print("")
    condition = int(input("검색 조건을 선택하세요."))
    return condition

def info_search(element, search_index):
    result = []
    for i in range(len(jsonResult)):
        if not element in jsonResult[i]["recent_info"] :
            if jsonResult[i][element] == search_index:
                result.append(jsonResult[i])
            elif search_index in jsonResult[i][element]:
                result.append(jsonResult[i])
        else:
            for j in range(len(jsonResult[i]["recent_info"])):
                if jsonResult[i]["recent_info"][j][element] == search_index:
                    result.append(jsonResult[i])
                elif search_index in jsonResult[i]["recent_info"][j][element]:
                    result.append(jsonResult[i])
    return result

def info_show_indiviual(result):
    print("")
    for i in range(len(result)):
        print("==================== 학생 회원 정보 ====================")
        print("이름 (예 : 홍길동) : %s " % result[i]['name'])
        print("나이 (예 : 22) : %s " % result[i]['age'])
        print("주소 (예 : 한양시 종로구 우리집) : %s " % result[i]['address'])
        print("학생ID (예 : ITT001) : %s " % result[i]['student_ID'])
        print("과거 수강 횟수 (예 : 1) : %s " % result[i]['past_record'])
        print("==================== 현재 수강 정보 ====================")
        for j in range(len(result[i].get('recent_info'))):
            print("강의코드 : %s"  % result[i].get('recent_info')[j]['강의코드'])
            print("강의명   : %s"  % result[i].get('recent_info')[j]['강의명'])
            print("강사     : %s"  % result[i].get('recent_info')[j]['강사명'])
            print("개강일   : %s"  % result[i].get('recent_info')[j]['개강일'])
            print("종료일   : %s"  % result[i].get('recent_info')[j]['종료일'])
            print("---------------------------------------------------------")
    print("---------------- 회원 정보 조회 성공!! -----------------")

def info_show_plural(result):
    for i in range(len(result)):
        print(">>> %d, 학생이름 : %s, 학생 ID : %s" % (i + 1, result[i]['name'], result[i]["student_ID"]))

def info_revise(result):
    while True:
        print("---- 학생 정보를 수정하겠습니다 ----")
        print("1. 이름\t2. 나이\t2. 주소\t4. 과거 수강 횟수\t5. 강의명\t6. 강의코드\t7. 강사명\t8. 새로운 강의 추가하기\t9. 뒤로가기")
        number = int(input("메뉴를 선택하세요 :"))
        if number < 7:
            revise_value = input("수정할 정보를 입력하세요 :")
            if number == 1 :
                result[0]['name'] = revise_value
            elif number == 2:
                result[0]['age'] = revise_value
            elif number == 3:
                result[0]['address'] = revise_value
            elif number == 4:
                result[0]['past_record'] = revise_value
            elif number == 5 :
                result[0].get('recent_info')[0]['강의명'] = revise_value
            elif number == 6:
                result[0].get('recent_info')[0]['강의코드'] = revise_value
            elif number == 7:
                result[0].get('recent_info')[0]['강사명'] = revise_value
        elif number == 8:
            result[0].get('recent_info').append(info_insert_course())
        elif number == 9 :
            return number
        Quit = input("종료를 원하시면 '종료'라고 입력하세요. 계속 수정하시려면 엔터를 눌러주세요")
        if Quit == '종료':
            break
        else:
            continue

def info_delete():
    know_ask = input("학생ID를 정확하게 알고계십니까?? y/n : ")
    if know_ask == 'n':
        index_key = input("기억하고 있는 정보를 입력하세요 : ")
        info_show_plural(info_search("student_ID",index_key))
    if know_ask == 'y':
        index = input("학생ID를 입력하세요 : ")
        info_show_indiviual(info_search("student_ID",index))
        print('메뉴를 선택하세요')
        number = int(input("1. 학생ID 전체삭제       2. 현재 수강중인 강의삭제 :"))
        if number == 1:
            for element in jsonResult:
                if element['student_ID'] == index:
                    element_del = element
                    jsonResult.remove(element_del)
        elif number == 2:
            index_2 = input("원하시는 과목코드를 입력하세요 : ")
            for i in range(len(jsonResult)):
                if jsonResult[i]['student_ID'] == index:
                    for element_2 in jsonResult[i]['recent_info']:
                        if element_2['강의코드'] == index_2:
                            element_del = element_2
                            jsonResult[i]['recent_info'].remove(element_del)
    print("============= 안전하게 삭제되었습니다 =============")

def info_start(path):
    try:
        with open(path, encoding='UTF8') as json_file:
            json_object = json.load(json_file)
            json_string = json.dumps(json_object)
            jsonResult_load = json.loads(json_string)
        return jsonResult_load

    except FileNotFoundError :
        with open(path, 'w', encoding='UTF8') as outfile:
            readable_result = json.dumps(jsonResult, indent=4, sort_keys=True, ensure_ascii=False)
            outfile.write(str(readable_result))
        return jsonResult

def info_save():
    with open('ITT_Student.json', 'w', encoding='UTF8') as outfile:
        readable_result = json.dumps(jsonResult, indent=4, sort_keys=True, ensure_ascii=False)
        outfile.write(str(readable_result))

print(" \t\t\t\t학생 주소록 관리 프로그램을 실행합니다.\t\t\t\t")

try:
    with open('ITT_Student.json', encoding='UTF8') as json_file:
        json_object = json.load(json_file)
        json_string = json.dumps(json_object)
        jsonResult = json.loads(json_string)

except FileNotFoundError:
     jsonResult = info_start(ask_path())
     print('ITT_Student.json SAVED')

while True :
    main_intro()
    option = int(input('메뉴을 선택해주세요 : '))
    try:
        if option == 1 :
            info_insert()
            index = input("지금까지의 정보 입력을 취소하시려면 'quit'를 입력하세요 :")
            if index == "quit": continue
            else:
                print("----------- 학생 정보 입력이 되었습니다 ----------")
                info_save()

        elif option == 2 :
            number = info_input()
            if number == 1:
                info_show_indiviual(jsonResult)
            elif 10 > number > 1:
                key_word = input("키워드를 입력하세요 : ")
                if number == 2 :
                    element = "name"
                elif number == 3 :
                    element = "age"
                elif number == 4:
                    element = "address"
                elif number == 5 :
                    element = "student_ID"
                elif number == 6 :
                    element = "past_record"
                elif number == 7 :
                    element = "강의명"
                elif number == 8 :
                    element = "강사명"
                elif number == 9 :
                    element = "강의코드"

                if len(info_search(element,key_word)) == 1:
                    info_show_indiviual(info_search(element,key_word))
                elif len(info_search(element,key_word)) > 1:
                    info_show_plural(info_search(element,key_word))
            elif number == 10:
                continue

        elif option == 3 :
            print("")
            print("------------- 학생 정보 수정을 시작합니다 -------------")
            print("!!!!! 학생ID는 수정이 불가합니다 !!!!!\n")
            while True:
                key_word = input("학생ID를 입력하세요 : ")
                if len(info_search("student_ID", key_word)) == 1:
                    info_show_indiviual(info_search("student_ID", key_word))
                    info_revise(info_search("student_ID", key_word))
                    break
                elif len(info_search("student_ID", key_word)) > 1:
                    info_show_plural(info_search("student_ID", key_word))
                    print("다시 입력하세요.")
                    continue
                info_show_indiviual(info_search("student_ID", key_word))
            info_save()

        elif option == 4 :
            info_delete()
            info_save()

        elif option == 5 :
            print("프로그램을 종료합니다.")
            break
    except:
        continue