import traceback
from flask import views, request, jsonify, make_response, current_app, abort
from .basehandler import BaseHandler, AuthError, LogicError, ParamsError, Dict, VerifyError, BaseError

class BaseViewHandler(views.MethodView, BaseHandler):

    @property
    def input(self):
        d = Dict(request.values.items())
        if request.is_json:
            d.update(request.json)
        return d

class ApiViewHandler(BaseViewHandler):

    def dispatch_request(self, *args, **kwargs):
        self.set_header = {}
        self.set_cookie = {}
        self.delete_cookie = []
        self.http_origin = request.environ.get('HTTP_ORIGIN', '')

        handler = getattr(self, request.method.lower(), None)

        if not callable(handler):
            if request.method == 'HEAD':
                return make_response('', 200)
            else:
                abort(405)

        return self.api_wrapper(handler, *args, **kwargs)

    def api_wrapper(self, handler, *args, **kwargs):
        code = 1000
        data = msg = None
        start_time = self.get_timestamp()
        try:
            data = handler(*args, **kwargs)
        except AuthError as e:
            code = e.code
            msg = str(e)
        except LogicError as e:
            code = e.code
            msg = str(e)
            err = traceback.format_exc()
            current_app.logger.error(err)
        except ParamsError as e:
            code = e.code
            msg = str(e)
        except VerifyError as e:
            code = e.code
            msg = str(e)
        except BaseError as e:
            code = e.code
            msg = str(e)
            err = traceback.format_exc()
            current_app.logger.error(err)
        except Exception:
            code = 5000
            msg = '系统内部错误'
            err = traceback.format_exc()
            current_app.logger.error(err)

        cost_time = self.get_timestamp() - start_time

        res = {'code': code, 'data': data, 'cost': "{0}ms".format(round(cost_time * 1000, 2))}
        if msg:
            res.update({'msg': msg})

        response = make_response(jsonify(res))

        if self.set_header:
            for k, v in self.set_header.items():
                response.headers[k] = v

        if self.set_cookie:
            for k, v in self.set_cookie.items():
                response.set_cookie(k, v)

        if self.delete_cookie:
            for k in self.delete_cookie:
                response.delete_cookie(k)

        return response


import os

import matplotlib.pyplot as plt
import pandas as pd

class LogParser:
    def __init__(self, input_file_name: str):
        self.input_file_name = input_file_name
        self.data = self._clean_data(self._read_file())
        self.timespan = self._get_timespan()

    def __str__(self):
        return f"Dataset: {self.input_file_name}\nSize: {self.data.shape}\nTimespan: {self.timespan}"

    def _read_file(self) -> pd.DataFrame:
        df = pd.read_csv(
            self.input_file_name, delimiter=";", low_memory=False, na_values=['=""']
        )
        return df

    def _clean_data(self, df: pd.DataFrame) -> pd.DataFrame:
        # odstranimo posebne znake
        df = df.replace('="', "", regex=True)
        df = df.replace('"', "", regex=True)
        # uredimo stolpec time
        df["Time"] = pd.to_datetime(df["Time"], format="%Y.%m.%d %H:%M:%S.%f")
        df["Original_Time"] = df["Time"]
        df = df.set_index("Time")
        # pretvorimo stolpec Type v kategorijo
        df["Type"] = df["Type"].astype("category")
        return df

    def _get_timespan(self):
        diff = self.data["Original_Time"].max() - self.data["Original_Time"].min()
        return diff

    def export_clean_data(self, export_format: str = "csv"):
        """Exports clean data to selected format (csv, json, xlsx)"""
        converted_file_name = (
            f"{os.path.splitext(self.input_file_name)[0]}-converted.{export_format}"
        )
        if export_format == "csv":
            self.data.to_csv(converted_file_name)
        elif export_format == "json":
            data_to_json = self.data.copy()
            data_to_json = data_to_json.reset_index()
            data_to_json.to_json(converted_file_name, orient="index")
        elif export_format == "xlsx":
            self.data.to_excel(converted_file_name)
        else:
            raise ValueError("Parameter export_format should be: csv, json, xlsx.")

    def type_rrep_resample_count(self, resample: int = 60) -> pd.DataFrame:
        df_log_rrep = self.data[
            self.data["Type"].str.contains("LOADNG RREP", na=False)
        ].copy()
        groups_rrep = (
            df_log_rrep["Type"]
            .resample(f"{resample}T", label="right", closed="right")
            .count()
        )
        return pd.DataFrame(groups_rrep)

    def plot_type_rrep_resample_count(self, resample=60):
        df_result = self.type_rrep_resample_count(resample)
        fig, ax = plt.subplots()
        df_result.plot(kind="bar", ax=ax, legend=False, color="red")
        ax.set_xlabel("Time")
        ax.set_ylabel("# of rrep")
        ax.set_title("rrep results")
        plt.tight_layout()
        plt.savefig(f"{self.input_file_name}_{resample}_plot.png")

if __name__ == "__main__":
    input_file = "Del_07_Generatorji/data/20200915 081812_10_2_6_26.csv"

    parser = LogParser(input_file)
    # parser.export_clean_data(export_format="json")

    # print(parser.data.head())

    print(parser.type_rrep_resample_count())
    parser.plot_type_rrep_resample_count()


from . import views
from django.urls import path

app_name = 'limousineapp'

urlpatterns = [
    path('', views.home, name='home'),
    path('index/', views.index, name='index'),
    path('about/',views.about,name='about'),
    path('bahrain/',views.bahrain,name='bahrain'),
    path('saudi/',views.saudi,name='saudi'),
    path('gallery/',views.gallery,name='gallery'),
    path('review/',views.review,name='review'),
    path('contact/',views.contact,name='contact'),
]


"""Color util methods."""
import logging
import math
# pylint: disable=unused-import

_LOGGER = logging.getLogger(__name__)

HASS_COLOR_MAX = 500  # mireds (inverted)
HASS_COLOR_MIN = 154
COLORS = {
    'white': (255, 255, 255), 'beige': (245, 245, 220),
    'tan': (210, 180, 140), 'gray': (128, 128, 128),
    'navy blue': (0, 0, 128), 'royal blue': (8, 76, 158),
    'blue': (0, 0, 255), 'azure': (0, 127, 255), 'aqua': (127, 255, 212),
    'teal': (0, 128, 128), 'green': (0, 255, 0),
    'forest green': (34, 139, 34), 'olive': (128, 128, 0),
    'chartreuse': (127, 255, 0), 'lime': (191, 255, 0),
    'golden': (255, 215, 0), 'red': (255, 0, 0), 'coral': (0, 63, 72),
    'hot pink': (252, 15, 192), 'fuchsia': (255, 119, 255),
    'lavender': (181, 126, 220), 'indigo': (75, 0, 130),
    'maroon': (128, 0, 0), 'crimson': (220, 20, 60)}

def color_name_to_rgb(color_name):
    """Convert color name to RGB hex value."""
    hex_value = COLORS.get(color_name.lower())

    if not hex_value:
        _LOGGER.error('unknown color supplied %s default to white', color_name)
        hex_value = COLORS['white']

    return hex_value

# Taken from:
# http://www.developers.meethue.com/documentation/color-conversions-rgb-xy
# License: Code is given as is. Use at your own risk and discretion.
# pylint: disable=invalid-name
def color_RGB_to_xy(R, G, B):
    """Convert from RGB color to XY color."""
    if R + G + B == 0:
        return 0, 0, 0

    R = R / 255
    B = B / 255
    G = G / 255

    # Gamma correction
    R = pow((R + 0.055) / (1.0 + 0.055),
            2.4) if (R > 0.04045) else (R / 12.92)
    G = pow((G + 0.055) / (1.0 + 0.055),
            2.4) if (G > 0.04045) else (G / 12.92)
    B = pow((B + 0.055) / (1.0 + 0.055),
            2.4) if (B > 0.04045) else (B / 12.92)

    # Wide RGB D65 conversion formula
    X = R * 0.664511 + G * 0.154324 + B * 0.162028
    Y = R * 0.313881 + G * 0.668433 + B * 0.047685
    Z = R * 0.000088 + G * 0.072310 + B * 0.986039

    # Convert XYZ to xy
    x = X / (X + Y + Z)
    y = Y / (X + Y + Z)

    # Brightness
    Y = 1 if Y > 1 else Y
    brightness = round(Y * 255)

    return round(x, 3), round(y, 3), brightness

# taken from
# https://github.com/benknight/hue-python-rgb-converter/blob/master/rgb_cie.py
# Copyright (c) 2014 Benjamin Knight / MIT License.
# pylint: disable=bad-builtin
def color_xy_brightness_to_RGB(vX, vY, brightness):
    """Convert from XYZ to RGB."""
    brightness /= 255.
    if brightness == 0:
        return (0, 0, 0)

    Y = brightness

    if vY == 0:
        vY += 0.00000000001

    X = (Y / vY) * vX
    Z = (Y / vY) * (1 - vX - vY)

    # Convert to RGB using Wide RGB D65 conversion.
    r = X * 1.612 - Y * 0.203 - Z * 0.302
    g = -X * 0.509 + Y * 1.412 + Z * 0.066
    b = X * 0.026 - Y * 0.072 + Z * 0.962

    # Apply reverse gamma correction.
    r, g, b = map(
        lambda x: (12.92 * x) if (x <= 0.0031308) else
        ((1.0 + 0.055) * pow(x, (1.0 / 2.4)) - 0.055),
        [r, g, b]
    )

    # Bring all negative components to zero.
    r, g, b = map(lambda x: max(0, x), [r, g, b])

    # If one component is greater than 1, weight components by that value.
    max_component = max(r, g, b)
    if max_component > 1:
        r, g, b = map(lambda x: x / max_component, [r, g, b])

    r, g, b = map(lambda x: int(x * 255), [r, g, b])

    return (r, g, b)

def rgb_hex_to_rgb_list(hex_string):
    """Return an RGB color value list from a hex color string."""
    return [int(hex_string[i:i + len(hex_string) // 3], 16)
            for i in range(0,
                           len(hex_string),
                           len(hex_string) // 3)]

def color_temperature_to_rgb(color_temperature_kelvin):
    """
    Return an RGB color from a color temperature in Kelvin.

    This is a rough approximation based on the formula provided by T. Helland
    http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
    """
    # range check
    if color_temperature_kelvin < 1000:
        color_temperature_kelvin = 1000
    elif color_temperature_kelvin > 40000:
        color_temperature_kelvin = 40000

    tmp_internal = color_temperature_kelvin / 100.0

    red = _get_red(tmp_internal)

    green = _get_green(tmp_internal)

    blue = _get_blue(tmp_internal)

    return (red, green, blue)

def _bound(color_component, minimum=0, maximum=255):
    """
    Bound the given color component value between the given min and max values.

    The minimum and maximum values will be included in the valid output.
    i.e. Given a color_component of 0 and a minimum of 10, the returned value
    will be 10.
    """
    color_component_out = max(color_component, minimum)
    return min(color_component_out, maximum)

def _get_red(temperature):
    """Get the red component of the temperature in RGB space."""
    if temperature <= 66:
        return 255
    tmp_red = 329.698727446 * math.pow(temperature - 60, -0.1332047592)
    return _bound(tmp_red)

def _get_green(temperature):
    """Get the green component of the given color temp in RGB space."""
    if temperature <= 66:
        green = 99.4708025861 * math.log(temperature) - 161.1195681661
    else:
        green = 288.1221695283 * math.pow(temperature - 60, -0.0755148492)
    return _bound(green)

def _get_blue(tmp_internal):
    """Get the blue component of the given color temperature in RGB space."""
    if tmp_internal >= 66:
        return 255
    if tmp_internal <= 19:
        return 0
    blue = 138.5177312231 * math.log(tmp_internal - 10) - 305.0447927307
    return _bound(blue)

def color_temperature_mired_to_kelvin(mired_temperature):
    """Convert absolute mired shift to degrees kelvin."""
    return 1000000 / mired_temperature

def color_temperature_kelvin_to_mired(kelvin_temperature):
    """Convert degrees kelvin to mired shift."""
    return 1000000 / kelvin_temperature


#!/usr/bin/env python3
# Erik de Bueger

import os
import sys
import datetime
import logging
import optparse
from random import randint
import re
import json
import boto3
import pickle
import requests

standarddateformat  = '%Y%m%d'

# Daily data
URLS = {'daily': 'https://www.daggegevens.knmi.nl/klimatologie/daggegevens',
            'hourly': 'https://www.daggegevens.knmi.nl/klimatologie/uurgegevens',
            'daily_rain': 'https://www.daggegevens.knmi.nl/klimatologie/monv/reeksen'}

# STN      LON(east)   LAT(north)     ALT(m)  NAME
# 235:         4.785       52.924       0.50  DE KOOY
# 209         4.518       52.465      0.00        IJmond
STATIONREGEX=re.compile(r'^#\s*(?P<NUM>[0-9]+)\s+(?P<LON>[0-9\.]+)\s+(?P<LAT>[0-9\.]+)\s+(?P<ALT>[0-9\.-]+)\s+(?P<Station>.*)$', re.U)
# EV24     = Potential evapotranspiration (Makkink) (in 0.1 mm);
LEGENDREGEX=re.compile(r'^#\s+(?P<SYMBOL>[A-Z0-9]+)\s+:\s*(?P<legend>.*)$', re.U)
## STN,YYYYMMDD,DDVEC,FHVEC,   FG,  FHX, FHXH,  FHN, FHNH,  FXX, FXXH,   TG,   TN,  TNH,   TX,  TXH, T10N,T10NH,   SQ,   SP,    Q,   DR,   RH,  RHX, RHXH,   PG,   PX,  PXH,   PN,  PNH,  VVN, VVNH,  VVX, VVXH,   NG,   UG,   UX,  UXH,   UN,  UNH, EV24
HEADERREGEX=re.compile(r'^#\s+STN,\s*YYYYMMDD,(?P<header>.*)$', re.U)
#  209,20231019,  145,   60,   70,  100,   24,   50,   11,  130,    1,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,     ,
DATAREGEX=re.compile(r'^(\s*[0-9]*,){1,}(\s*[0-9]*){0,1}$', re.U)

# {event type:date}
class Cache(object) :
    def __init__(self, region,logger,starttime):
        self.logger    = logger
        self.starttime = starttime
        self.counter   = 0
        self.cache     =  None
        self.d         = {}
    def Get(self,key) :
        return(self.starttime)
    def Write(self,key, value):
        self.d[key]=value
        self.counter+=1
        if self.counter % 10 == 0:
            self.Flush()
    def Close(self) :
        self.Flush()
    def Flush(self) :
        pass
    def Print(self,fp) :
        for k,v in self.d.items() :
            fp.write('{} -- {}\n'.format(k,v.strftime(standarddateformat)))

class CacheFile(Cache) :
    def __init__(self, region,logger,starttime):
        self.logger = logger
        self.starttime = starttime
        self.counter = 0
        self.file = region
        self.fp = None
        self.d={}
        try:
            self.fp = open(os.path.join(sys.path[0],self.file),'rb')
            # use dict as fast cache
            self.d = pickle.load(self.fp)
            self.fp.close()
        except Exception as e:
            self.logger.warning(str(e))
            self.logger.warning('Filecache could not be opened: {}, will create later'.format(os.path.join(sys.path[0],self.file)))
            self.d={}

    def Get(self,key) :
        try:
            return(self.d[key])
        except KeyError:
            # Not in cache, use earliest date
            return(self.starttime)

    # write dict to cache
    def Flush(self) :
        try:
            self.fp = open(os.path.join(sys.path[0],self.file),'wb')
            pickle.dump(self.d,self.fp, protocol=0)
            self.fp.truncate()
            self.fp.flush()
            self.fp.close()
        except Exception as e:
            self.logger.warning(str(e))
            self.logger.warning('Error writing last_eventid to cache')

class CacheAWSParameter(Cache) :
    def __init__(self,region,logger,starttime):
        self.logger    = logger
        self.starttime = starttime
        self.counter   = 0
        self.cache     = boto3.client('ssm', region_name=region)
        self.d         = {}

    # Check last event tokens or timestamps per key in AWS cache
    # key is event type, value is date: knmi-daily:20211123
    def Get(self,key) :
        # First try local cache
        try:
            return(self.d[key])
        except KeyError:
            pass
        # Retrieve from remote cache
        cachekey = 'knmi-{}'.format(key)
        try:
            cachevalue = self.cache.get_parameter(Name=cachekey)['Parameter']['Value']
            # We have a string back from the cache, should be timestamp
            # Try timestamp
            self.d[key] = datetime.datetime.strptime(cachevalue, standarddateformat)
            return(self.d[key])
        except Exception as e:
            # No cache value found
            self.logger.warning(str(e))
            self.logger.warning('Error: {} not found in cache! Starting from {}. \n'.format(cachekey,self.starttime))
            return(self.starttime)

    # write dict to cache
    def Flush(self) :
        for k,v in self.d.items() :
            cachekey = 'knmi-{}'.format(k)
            try:
                # try date format
                x = self.cache.put_parameter(Name=cachekey, Type='String', Overwrite=True,Value=v.strftime(standarddateformat))
            except Exception as e:
                self.logger.warning(str(e))
                self.logger.warning('Error writing last_eventid to cache')

def MarshalGeneric(d) :
    # Remove emty fields
    if d==None: return(d)
    d=dict((k, v) for k, v in d.items() if v)
    for k,v in d.items() :
        try:
            d[k]=int(d[k])
        except:
            pass
    try:
        d['timestamp'] = datetime.datetime.strptime(str(d['YYYYMMDD']), standarddateformat).strftime('%Y-%m-%d:%H%M%S')
    except :
        pass
    return(d)

# Class for writing events to destination, either Splunk or Elastic.
# Overwrites possible for alternate destinations
class EventWriter(object) :
    def __init__(self, **kwargs):
        self.marshal  = kwargs.get('mfunc',None)
        self.logger   = kwargs.get('logger',None)

    # Send a kv-formatted message to stdout
    # message is json dict
    def send(self, message):
        if self.marshal != None :
            data=self.marshal(message)
        else :
            data=message
        #    data = message.encode('utf-8', 'replace')
        #sys.stdout.write('{}\n\n'.format(json.dumps(data).encode('utf-8', 'replace')))
        sys.stdout.write('{}\n\n'.format(json.dumps(data)))

    def flush(self) :
        pass

class EventWriterCached(EventWriter) :
    def __init__(self, **kwargs):
        self.marshal  = kwargs.get('mfunc',None)
        self.logger   = kwargs.get('logger',None)
        self.batch    = kwargs.get('batch',1)
        self.cache    = []

    def send(self, message):
        if self.marshal != None :
            data=self.marshal(message)
        else :
            data=message
        self.cache.append(data)
        if len(self.cache) >= self.batch :
            s='\n'.join([json.dumps(x) for x in self.cache])
            sys.stdout.write(s)
            sys.stdout.write('\n')
            self.cache=[]

    def flush(self) :
        if len(self.cache) > 0:
            s='\n'.join([json.dumps(x) for x in self.cache])
            sys.stdout.write(s)
            sys.stdout.write('\n')
            self.cache=[]

class EventWriterJSON(EventWriter) :
    def __init__(self, **kwargs):
        self.marshal  = kwargs.get('mfunc',None)
        self.logger   = kwargs.get('logger',None)
        self.url      = kwargs.get('endpoint',None)

    # message is dict
    def send(self, message):
        if self.marshal != None :
            data=self.marshal(message)
        else :
            data=message
        response = requests.post(self.url, data=json.dumps(data))
        if self.logger != None:
            self.logger.info('Endpoint response: {}'.format(response.text))

class EventWriterCachedJSON(EventWriter) :
    def __init__(self, **kwargs):
        self.marshal  = kwargs.get('mfunc',None)
        self.logger   = kwargs.get('logger',None)
        self.url      = kwargs.get('endpoint',None)
        self.batch    = kwargs.get('batch',1)
        self.cache    = []

    # message is dict
    def send(self, message):
        if self.marshal != None :
            data=self.marshal(message)
        else :
            data=message
        self.cache.append(data)
        if len(self.cache) >= self.batch :
            s='\n'.join([x for x in json.dumps(self.cache)])
            response = requests.post(self.url, data=s)
            self.cache=[]
            if self.logger != None:
                self.logger.info('Endpoint response: {}'.format(response.text))

    def flush(self) :
        if len(self.cache) > 0:
            s='\n'.join([x for x in json.dumps(self.cache)])
            response = requests.post(self.url, s)
            self.cache=[]

def GetDailyData(url, startdate,enddate, logger) :
    params = dict(stns='ALL')
    start = startdate.strftime(standarddateformat)
    end = enddate.strftime(standarddateformat)
    params.update(start=start)
    params.update(end=end)
    params.update(vars='ALL')
    r = requests.post(url=url, data=params)
    if r.status_code != 200:
        raise requests.HTTPError(r.status_code, url, params)
        return(None)
    return(r)

# Iterator over KNMI csv format file, returns dicts
def data_digger(raw):
    cols=['STN','YYYYMMDD']
    headerseen=False
    for line in raw.text.splitlines():
        if headerseen:
            m=DATAREGEX.match(line)
            if m:
                lColumns=[x.strip() for x in line.lstrip().rstrip().split(',')]
                dFormat=dict(list(zip(cols,lColumns)))
                yield(dFormat)
        else:
            m=HEADERREGEX.match(line)
            if m:
                headerseen=True
                cols=cols+[x.strip() for x in m.group('header').split(',')]

# Iterator over KNMI csv format file, returns dicts
def location_digger(raw):
    for line in raw.text.splitlines():
        m=HEADERREGEX.match(line)
        if m:
            return
        m =  STATIONREGEX.match(line)
        if m != None:
            d = {'STN':int(m.group('NUM')), 'lat':m.group('LAT'), 'lon':m.group('LON'), 'alt':m.group('ALT')}
            yield (d)

def legend_digger(raw):
    for line in raw.text.splitlines():
        m=HEADERREGEX.match(line)
        if m:
            return
        m=LEGENDREGEX.match(line)
        if m:
            try:
                yield({'symbol':m.group('SYMBOL'),'desc':m.group('legend')})
            except:
                pass

def station_digger(raw):
    for line in raw.text.splitlines():
        m=HEADERREGEX.match(line)
        if m:
            return
        m=STATIONREGEX.match(line)
        if m :
            # we have a station spec
            try:
                yield({'STN':int(m.group('NUM')),'LON':m.group('LON'), 'LAT':m.group('LAT'), 'ALT':m.group('ALT'), 'Station':m.group('Station').strip()})
            except:
                pass

# Helper to iterate over days
def daterange(start_date, end_date):
    for n in range(int((end_date - start_date).days)):
        yield start_date + datetime.timedelta(n)

def planning(latest,history,maxdays) :
    startdate= datetime.datetime.now()-datetime.timedelta(days=opts.history)
    enddate= datetime.datetime.now()-datetime.timedelta(days=opts.latest)

def DoCollect(startdate,enddate,cachedate,opts,eventwriter,cache,logger):
    # Decide which days we will try to collect: startdate=the start date requested, enddate=latest possible end date, cachedate=last date collected, or equal to startdate
    daysback= (datetime.datetime.now()-cachedate).days
    if daysback > opts.maxdays :
        enddate = cachedate + datetime.timedelta(days=opts.maxdays)
    startdate=cachedate + datetime.timedelta(days=1)
    logger.info('Planning to collect from {} to {}'.format(startdate.strftime(standarddateformat), enddate.strftime(standarddateformat)))

    # Write legend + stations inventory only on some random occasions
    writelegend = (randint(1,5)==3)

    # Start collecting on per-day basis
    for thedate in daterange(startdate, enddate):
        thedata = GetDailyData(URLS['daily'], thedate,thedate,logger)
        # Send data
        nEvents=0
        for d in data_digger(thedata):
            if d != None:
                d.update({'type':'daily'})
                eventwriter.send(d)
                nEvents+=1
        if writelegend:
            for d in legend_digger(thedata):
                if d != None:
                    d.update({'type':'legend'})
                    eventwriter.send(d)
            for d in station_digger(thedata):
                if d != None:
                    d.update({'type':'station'})
                    eventwriter.send(d)
            writelegend=False
        # Update cache
        if nEvents > 10:
            cache.Write('daily',thedate)
        logger.info('Send {} events for day {}'.format(nEvents,thedate.strftime(standarddateformat)))

# Main code
def main():
    # Parse command line options
    p = optparse.OptionParser("usage: %prog [options]")
    p.add_option("-u", "--url", dest="url", default=URLS['daily'], \
                     help = 'url for dutch KNMI daily data extraction, defaults to: {}\nAlternate option: {}'.format(URLS['daily'], URLS['hourly']))
    p.add_option("-y", "--hourly", dest="hourly", action='store_true', default=False, \
                     help = 'Extract hourly data as opposed to daily, defaults to: {}'.format(False))
    p.add_option("-t", "--stations", dest="stations", action='store_true', default=False, \
                 help='Extract list of stations and write to stdout, default=False')
    p.add_option("-g", "--legend", dest="legend", action='store_true', default=False, \
                 help='send legend output only, default=False')
    p.add_option("-f", "--format", dest="format", default='stdout', \
                 help='send output to {}, default output is stdout'.format('sumo,splunk,elastic, awselastic,json or stdout'))
    p.add_option("--latest", dest="latest", type='int', default=2, \
                     help = 'Collect this many days in the past as the latest available data, more recent days will not be populated, defaults to 30')
    p.add_option("--history", dest="history", type='int', default=30, \
                     help = 'Collect this many days of historic data, defaults to 10')
    p.add_option("--maxdays", dest="maxdays", type='int', default=5, \
                     help = 'Maximum amount of days to be collected in one run , defaults to 5')
    p.add_option("-b","--batch", dest="batch", type='int', default=10, \
                     help = 'output batch size, defaults to 10')
    p.add_option("--endpoint", dest="endpoint", default=None, \
                  help = 'endpoint (sumo, splunk, elastic url) where data is delivered, defaults to: {}'.format('None'))
    p.add_option("-n", "--stationnumber", dest="stationnumber", type='int', default=-1, \
                  help = 'Collect data for specific station, identified by station number, defaults to -1')
    p.add_option("--nolambda", dest="nolambda", action='store_true', default=False, \
                 help='if set donot run as as lambda function, default=False')
    p.add_option("--region", dest="region", default='us-east-2', \
                     help = 'AWS region, defaults to: {}'.format('us-east-2'))
    p.add_option("-l", "--log", dest="loglevel", default='WARNING', \
                 help = 'loglevel field, defaults to WARNING, options are: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET')
    p.add_option("--cache", dest="cache", default='lastknmievents', \
                 help = 'name of cache file or endpoint for AWS memcached service, defaults to : lastknmievent')
    opts,args = p.parse_args()

    # For AWS lambda: try to overwrite some options from environment
    for x in ('format','endpoint','logtype','url','loglevel','stationnumber','region','history','latest','maxdays','batch') :
        try:
            exec('opts.{}=os.environ[\'{}\']'.format(x,x))
        except Exception as e:
            pass
    try:
        opts.history = int(opts.history)
    except:
        pass
    try:
        opts.maxdays = int(opts.maxdays)
    except:
        pass
    try:
        opts.latest = int(opts.latest)
    except:
        pass
    try:
        opts.stationnumber = int(opts.stationnumber)
    except:
        pass
    try:
        opts.batch = int(opts.batch)
    except:
        pass

    startdate= datetime.datetime.now()-datetime.timedelta(days=opts.history)
    enddate= datetime.datetime.now()-datetime.timedelta(days=opts.latest)

    # Initiate Logging
    numeric_level = getattr(logging, opts.loglevel.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError('Invalid log level: %s' % opts.loglevel)

    formatter = logging.Formatter('%(asctime)s,Level=%(levelname)s,\
                                   LOGGING=%(message)s', '%m/%d/%Y %H:%M:%S')

    sh = logging.StreamHandler(sys.stderr)
    sh.setFormatter(formatter)
    logger        = logging.getLogger('KNMI')
    logger.handlers.clear()
    logger.addHandler(sh)
    logger.level=numeric_level

    # Open up the cache, which remembers per station what the date of the most recent event was
    if opts.nolambda:
        # revert to local file cache
        try:
            cache = CacheFile(opts.cache, logger, startdate)
        except Exception as e:
            # giving up
            logger.warning(str(e)+'\n')
            logger.warning('Could not open file cache, exit')
            return
    else:
        try:
            cache = CacheAWSParameter(opts.region,logger,startdate)
        except Exception as e:
            logger.warning(str(e)+'\n')
            logger.warning('Could not open AWS cache, exit')
            return

    # Retrieve latest date from cache
    cachedate = cache.Get('daily')

    # Create output channel
    if opts.format=='stdout':
        eventwriter=EventWriterCached(logger=logger,mfunc=MarshalGeneric,batch=opts.batch)
        logger.info('Writing events to stdout')
    elif opts.format=='sumo':
        #eventwriter=EventWriterJSON(endpoint=opts.endpoint,mfunc=MarshalGeneric, logger=logger)
        eventwriter=EventWriterCachedJSON(endpoint=opts.endpoint,mfunc=MarshalGeneric, logger=logger,batch=opts.batch)
        logger.info('Writing events to Sumo')
    else :
        logger.err('Unknow destination format provided: {}. Options are: stdout-splunk-elastic-sumo'.format(opts.format))
        sys.exit(0)

    # Process options
    if opts.stations:
        thedata = GetDailyData(URLS['daily'], startdate,startdate,logger)
        for d in station_digger(thedata):
            if d != None:
                d.update({'type':'station'})
                eventwriter.send(d)
        sys.exit()
    if opts.legend:
        thedata = GetDailyData(URLS['daily'], startdate,startdate,logger)
        for d in legend_digger(thedata):
            if d != None:
                d.update({'type':'legend'})
                eventwriter.send(d)
        sys.exit()
    if opts.stationnumber > 0 :
        thedata = GetDailyData(URLS['daily'], startdate,startdate,logger)
        for d in data_digger(thedata):
            if int(d['STN'])==opts.stationnumber:
                eventwriter.send(d)
                sys.exit()
        sys.exit()

    DoCollect(startdate,enddate,cachedate,opts,eventwriter,cache,logger)

    cache.Close()
    eventwriter.flush()

if __name__ == '__main__':
    main()

def lambda_handler(event, context):
    main()
    return {
        'statusCode': 200,
        'body': json.dumps('KNMI Lambda returns\n')
    }


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jun  2 16:06:27 2022

@author: Zhenzi Yu
"""

import os
import math
import numpy as np
import copy
import random
import time
import json

from pymatgen.io.cif import CifParser
from mofid.run_mofid import cif2mofid
import pymatgen.analysis.graphs as mgGraph
import pymatgen.core.bonds  as mgBond
import pymatgen.core.structure as mgStructure
from pymatgen.io.vasp.inputs import Poscar

from src.helper import CheckConnectivity, WriteStructure, CheckNeighbourMetalCluster, DebugVisualization, nodes_expansion
from src.DefectMOFStructure import DefectMOFStructure

from ase.io import read, write

class DefectMOFStructureBuilder():

    def __init__(self, cifFile_Name, output_dir = '.', sepMode = 'MetalOxo', cutoff = 12.8 ):

        self.cifFile_Name = cifFile_Name
        self.output_dir = output_dir
        self.sepMode = sepMode
        self.cutoff = cutoff

        self.original_nodes = None
        self.original_linkers, self.original_linkers_length = None, None
        self.processed_structure = None

        self.original_Structure = self.ReadStructure(self.cifFile_Name)
        self.SeperateStructure(self.cifFile_Name,linkerSepDir = os.path.join(self.output_dir,'linkerSep' ))

        return

    def ReadStructure(self,cifFile_Name):

        cifFile = CifParser(cifFile_Name)
        # bug fixed, cannot allow primitive reduction!
        structure = cifFile.get_structures(primitive=False)[0]

        return structure

    def SeperateStructure(self, cifFileName, linkerSepDir):

##############################################################################
#       Coding notes: Metal nodes append after linkers!!!!!
##############################################################################
#
#
        # use the packge to seperate the linker/nodes and read in
        t0 = time.time()
        try:
            os.mkdir(linkerSepDir)
        except:
            pass
        cif2mofid(cifFileName ,output_path = linkerSepDir)
        self.original_linkers = self.ReadStructure(os.path.join(linkerSepDir, self.sepMode, 'linkers.cif'))
        self.original_linkers_length = len(self.original_linkers.sites)
        print("SBU seperation finished, which takes %f Seconds" % (time.time()-t0))

        # Subgraph detection : linker_cluster_assignment - LCA
        linker_cluster_assignment = CheckConnectivity(self.original_linkers)

        self.original_nodes = self.ReadStructure(os.path.join(linkerSepDir, self.sepMode, 'nodes.cif'))
        # pbc expande nodes so that for linker delete step to find the right neighbour
        self.original_nodes = nodes_expansion(self.original_nodes)

        # Neighbour Metal Cluster detection : NbM
        coord_bond_array, metal_cluster_assignment, coord_bond_list = CheckNeighbourMetalCluster(self.original_linkers, self.original_nodes )
        NbM = [x + len(self.original_linkers) for x in coord_bond_array]

        # pass Subgraph detection to the mg structure;
        # NOTE: this could be combined together with the prvious step, but just for debug purposes, I seperated
        self.original_linkers.add_site_property('NbM',NbM)
        self.original_linkers.add_site_property('LCA',linker_cluster_assignment[1])
        self.original_linkers.add_site_property('NbL',[np.nan]*len(self.original_linkers))
        self.original_linkers.add_site_property('MCA',[np.nan]*len(self.original_linkers))
        self.linker_num = linker_cluster_assignment[0]

        # add property to nodes
        self.original_nodes.add_site_property('NbM',[np.nan]*len(self.original_nodes)) # add np.nan
        self.original_nodes.add_site_property('LCA',[np.nan]*len(self.original_nodes)) # add np.nan
        self.original_nodes.add_site_property('NbL',coord_bond_list) # NbL: neighbourhodd linker
        self.original_nodes.add_site_property('MCA',metal_cluster_assignment[1]) # MCA: Metal Cluster assginement
        self.original_nodes.add_site_property('is_linker',[False]*len(self.original_nodes))

        # create seperate molecules based on graph
        self.molecules = []
        indexes = []
        # detect linker type
        for i in range(self.linker_num):
            index = np.array( np.where(linker_cluster_assignment[1]==i)[0], dtype=int)
            indexes.append(index)
            sites = [ self.original_linkers[i] for i in index ]
            molecule = mgStructure.Structure.from_sites(sites)
            self.molecules.append(molecule)
        formulas = [ x.formula for x in self.molecules]
        self.linker_type = np.unique(formulas)

        # construct new MOF structure: add lable distinguishing Metal/linker, add label for linker type,
        # Step 0: add unique id for sites. In the late process, sites might be removed, so need to defined an id besides index.
        id_linkers = np.arange(len(self.original_linkers))
        self.original_linkers.add_site_property('fixed_id',id_linkers)
        id_nodes = np.arange(len(self.original_nodes))+len(self.original_linkers)
        self.original_nodes.add_site_property('fixed_id',id_nodes)

        # Step 1: label linker type
        linker_label = np.full(len(self.original_linkers),None)
        is_linker = np.full(len(self.original_linkers),True)

        for jj,molecule in enumerate(self.molecules):
            linker_type_num = np.where(self.linker_type == molecule.formula)[0]
            linker_label[indexes[jj]] = linker_type_num
        self.original_linkers.add_site_property('linker_label',linker_label)
        self.original_nodes.add_site_property('linker_label',[np.nan]*len(self.original_nodes))
        self.original_linkers.add_site_property('is_linker',is_linker)

        # Step 2 : add metal site into linker site, combined as a whole
        processed_structure_sites = []
        for site in self.original_linkers:
            processed_structure_sites.append(site)
        for site in self.original_nodes:
            processed_structure_sites.append(site)
        self.processed_structure = mgStructure.Structure.from_sites(processed_structure_sites)

        # print and summary
        # TODO: add some check function to make sure the right structure is read into the code

        print("There are %d atoms in Metal Cluster, and %d atoms in linkers, with %d linkers, %d types" \
        % ( len(self.original_nodes), len(self.original_linkers), self.linker_num, len(np.unique(formulas))))

        return None

    def _DefectDensityControl_(self):

        cell = self.original_Structure.lattice.abc
        min_index = cell.index(min(cell))
        max_index = cell.index(max(cell))
        # fix a = b = c
        if max_index==min_index:
            max_index += 1
        _mid_index = [0,1,2]
        _mid_index.remove(min_index)
        _mid_index.remove(max_index)
        mid_index = _mid_index[0]

        def assign_supercell(cellnum):
            cell = [1,1,1]
            if cellnum == 1:
                return cell
            elif cellnum ==2 or cellnum==3 or cellnum==5:
                cell[min_index] = cellnum
            elif cellnum == 6:
                cell[min_index] = 2
                cell[mid_index] = 3
            elif cellnum == 4:
                cell[min_index] = 2
                cell[mid_index] = 2
            else:
                raise "error for super cell assignment"
            return cell

        enumerate_conc = [1/2,1/3,2/3,1/4,3/4,1/5,2/5,3/5,4/5,1/6,5/6,1,2,3,4,5,6]
        corr_defect_num = [1,1,2,1,3,1,2,3,4,1,5,1,2,3,4,5,6]
        corr_cell = [2,3,3,4,4,5,5,5,5,6,6,1,1,1,1,1,1]
        original_conc = 1/self.linker_num
        desired_conc = [0.01, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4]
        achived_conc = {}

        for _conc_goal_ in desired_conc:
            for i,_conc_possible_ in enumerate(enumerate_conc):
                _conc_possible2_ = original_conc*_conc_possible_
                if abs((_conc_possible2_-_conc_goal_)/_conc_goal_) < 0.3:
                    achived_conc[_conc_possible2_] = [_conc_goal_, corr_defect_num[i], corr_cell[i], assign_supercell(corr_cell[i])]
                    break

        return achived_conc

    def StructureGeneration(self, superCell, defectConc, numofdefect, linker_type):

        working_mof = copy.deepcopy(self.processed_structure)

        with open('src/charge_dict.json') as json_file:
            charge_dict = json.load(json_file)

        if self.linker_type[linker_type] in charge_dict.keys():
            charge_comp = charge_dict[self.linker_type[linker_type]]
        else:

            for molecule in self.molecules:
                if molecule.formula == self.linker_type[linker_type]:
                    vis_structure = molecule
                    break
            DebugVisualization(vis_structure)

            charge_comp = input("unseen molecular:%s, please specify charge\n"%(self.linker_type[linker_type] ))
            try:
                charge_comp = int(charge_comp)
            except:
                raise("please input num")
            charge_dict[self.linker_type[linker_type]] = charge_comp

        with open('src/charge_dict.json', 'w') as fp:
            json.dump(charge_dict, fp)

        defect_structure = DefectMOFStructure(working_mof, superCell, defectConc, numofdefect, linker_type, self.output_dir, charge_comp)
        defect_structure.Build_supercell()
        defect_structure.DefectGen()
        # defect_structure.ReverseMonteCarlo()

        return

    def LinkerVacancy(self):

        self.possible_Defect_Density = self._DefectDensityControl_()
        for i_linker,linker_type in enumerate(self.linker_type):
            for key,val in self.possible_Defect_Density.items():
                print("Currently generate linker vacancy defect with %s, at conc. of %.3f" %(linker_type,key))
                self.StructureGeneration(val[3],key,val[1], i_linker)

        return


"""indexes

Revision ID: 6b4a2a657760
Revises: 4780158ba4af
Create Date: 2021-09-16 23:18:16.581206

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '6b4a2a657760'
down_revision = '4780158ba4af'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('student', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_student_active'), ['active'], unique=False)
        batch_op.create_index(batch_op.f('ix_student_student_email'), ['student_email'], unique=False)
        batch_op.create_index(batch_op.f('ix_student_student_name'), ['student_name'], unique=True)

    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('student', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_student_student_name'))
        batch_op.drop_index(batch_op.f('ix_student_student_email'))
        batch_op.drop_index(batch_op.f('ix_student_active'))

    # ### end Alembic commands ###


import requests
import datetime
import json

import boto3

# set up S3 client
s3 = boto3.client("s3")

def lambda_handler(event, context):

    try:
        # API endpoint for StackOverflow
        api_endpoint = "https://api.stackexchange.com/2.3/tags?order=desc&sort=popular&site=stackoverflow"
        # or           'https://api.stackexchange.com/2.3/questions?order=desc&sort=activity&site=stackoverflow'

        # Send GET request to the API endpoint
        response = requests.get(api_endpoint)

        if response.status_code != 200:
            raise ValueError(f"Request failed with error code {response.status_code}")

        # get the current timestamp
        current_time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
        year, month, day = current_time.split("-")[:3]

        # Define the S3 bucket and key
        s3_file_name = f"questions_raw/{year}/{month}/{day}/stackoverflow_raw_data_{current_time}.json"
        s3_bucket_name = "stackoverflow-raw-bucket"

        # upload the content to S3 bucket
        s3.put_object(Bucket=s3_bucket_name, Key=s3_file_name, Body=response.content)

        return {"statusCode": 200, "body": "Data fetched and saved to S3 bucket"}

    except Exception as e:
        return {"statusCode": 500, "body": json.dumps(f"Error: {str(e)}")}


import os
import traceback

from config.main import TMP_DIR
from lib.FileManager.workers.baseWorkerCustomer import BaseWorkerCustomer

class ReadImages(BaseWorkerCustomer):
    def __init__(self, paths, session, *args, **kwargs):
        super(ReadImages, self).__init__(*args, **kwargs)

        self.paths = paths
        self.session = session

    def run(self):
        try:
            self.preload()
            self.logger.info("FTP ReadImages process run")

            hash_str = self.random_hash()
            download_dir = TMP_DIR + '/images/' + self.login + '/' + hash_str + '/'
            success_paths, error_paths = self.copy_files_to_tmp(download_dir)

            if len(success_paths) == 1:
                one_file = True
            else:
                one_file = False

            if len(error_paths) == 0:  # Значит все хорошо, можно дальше обрабатывать

                file_list = {
                    "succeed": list(os.path.basename(filename) for filename in success_paths),
                    "failed": list(os.path.basename(filename) for filename in error_paths)
                }

                answer = {
                    "success": True,
                    "file_list": file_list,
                    "hash": hash_str,
                    "one_file": one_file,
                    "sid": self.login
                }

                result = {
                    "data": answer
                }

                self.on_success(result)
            else:
                raise Exception("read error")

        except Exception as e:
            result = {
                "error": True,
                "message": str(e),
                "traceback": traceback.format_exc()
            }

            self.on_error(result)

    def copy_files_to_tmp(self, target_path):
        if not os.path.exists(target_path):
            os.makedirs(target_path)

        ftp = self.get_ftp_connection(self.session)

        success_paths = []
        error_paths = []

        for path in self.paths:
            try:
                abs_path = ftp.path.abspath(path)
                source_path = ftp.path.dirname(path)
                file_basename = ftp.path.basename(abs_path)

                if ftp.isdir(abs_path):
                    destination = os.path.join(target_path, file_basename)

                    if not os.path.exists(destination):
                        os.makedirs(destination)
                    else:
                        raise Exception("destination already exist")

                    for current, dirs, files in ftp.ftp.walk(ftp.to_string(abs_path)):
                        current = current.encode("ISO-8859-1").decode("UTF-8")
                        relative_root = os.path.relpath(current, source_path)

                        for d in dirs:
                            d = d.encode("ISO-8859-1").decode("UTF-8")
                            target_dir = os.path.join(target_path, relative_root, d)
                            if not os.path.exists(target_dir):
                                os.makedirs(target_dir)
                            else:
                                raise Exception("destination dir already exists")

                        for f in files:
                            f = f.encode("ISO-8859-1").decode("UTF-8")
                            source_file = os.path.join(current, f)
                            target_file_path = os.path.join(target_path, relative_root)
                            target_file = os.path.join(target_path, relative_root, f)
                            if not os.path.exists(target_file):
                                download_result = ftp.download(source_file, target_file_path)
                                if not download_result['success'] or len(
                                        download_result['file_list']['failed']) > 0:
                                    raise download_result['error'] if download_result[
                                                                          'error'] is not None else Exception(
                                            "Download error")
                            else:
                                raise Exception("destination file already exists")

                elif ftp.isfile(abs_path):
                    try:
                        target_file = os.path.join(target_path, file_basename)
                        if not os.path.exists(target_file):
                            download_result = ftp.download(abs_path, target_path)
                            if not download_result['success'] or len(download_result['file_list']['failed']) > 0:
                                raise download_result['error'] if download_result[
                                                                      'error'] is not None else Exception(
                                        "Download error")
                        else:
                            raise Exception("destination file already exists")

                    except Exception as e:
                        self.logger.info("Cannot copy file %s , %s" % (abs_path, str(e)))
                        raise e

                success_paths.append(path)

            except Exception as e:
                self.logger.error(
                        "Error copy %s , error %s , %s" % (str(path), str(e), traceback.format_exc()))
                error_paths.append(path)

        return success_paths, error_paths


# Currency Cog
# ---------------------------------------------------------------------------------------------------------
# Imports
# Provides us with a way to work with JSON Files
from json import load, dump

# ---------------------------------------------------------------------------------------------------------

# Establish Variables
# Get the Currency dictionary from Currency-Accounts.json
with open(f'{bot_folder_path}Currency-Accounts.json', 'r') as currency_file:
    currency_dict = load(currency_file)

# ---------------------------------------------------------------------------------------------------------

# Establish Functions
# Check whether the user has an account with us, and returns their account if they do
def check_for_user(user_id):
    try:
        return currency_dict[str(user_id)]
    except KeyError:
        return False

# ---------------------------------------------------------------------------------------------------------

# Currency Commands
# Makes a Cog Class which houses all the currency commands
class Currency(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    # Checks if the user has an account, if they don't, one is made
    @commands.command()
    async def make_account(self, ctx):
        user_account = check_for_user(ctx.author.id)
        if user_account is not False:
            """

            do stuff

            """
            pass
        else:
            await ctx.send(f"{ctx.author.mention}, you already have an account with us!")

    # Displays the users balance or mentioned users balance
    @commands.command()
    async def balance(self, ctx, user:discord.Member=None):
        if user is None:
            user_account = check_for_user(ctx.author.id)
            if user_account is not False:
                embed=discord.Embed(title=">Balance", color=0x0302c0)
                embed.add_field(name=f"Exo${str(user_account['balance'])}", value=f"{ctx.author.display_name}'s Balance", inline=False)
                await ctx.send(embed=embed)
            else:
                await ctx.send(f"{ctx.author.mention}, it seems like you don't have an account with us. Use `E-make_account` to create an account.")

        elif user is not None:
            user_account = check_for_user(user.id)
            if user_account is not False:
                embed=discord.Embed(title=">Balance", color=0x0302c0)
                embed.add_field(name=f"Exo${str(user_account['balance'])}", value=f"{user.display_name}'s Balance", inline=False)
                await ctx.send(embed=embed)
            else:
                await ctx.send(f"{ctx.author.mention}, it seems like the mentioned user doesn't have an account with us. Use `E-make_account` to create an account.")


# https://atcoder.jp/contests/abc168/tasks/abc168_e

import sys
from math import gcd
from collections import Counter
# # def input(): return sys.stdin.readline().rstrip()
# # input = sys.stdin.readline
input = sys.stdin.buffer.readline
# sys.setrecursionlimit(10 ** 7)
MOD = 1000000007

N = int(input())
ab = []
for i in range(N):
    a,b = map(int, input().split())
    gcd_ab = gcd(a,b)
    a //= gcd_ab
    b //= gcd_ab
    if a<0:     # aは常に正にする
        a *= -1
        b *= -1
    ab.append((a,b))
Cnt = Counter(ab)
# print(Cnt)

ans = 1
done = set()
for (a, b), c in Cnt.items():
    # print(a,b,c)
    if (a,b) in done: continue
    if (a,b) == (0,0):
        done.add((a,b))
        continue
    elif b < 0:
        if (-b, a) in Cnt.keys():
            ans *= (pow(2,c,MOD)-1) + (pow(2,Cnt[(-b,a)],MOD)-1) + 1
            ans %= MOD
            done.add((a,b))
            done.add((-b,a))
        else:
            ans *= pow(2,c,MOD)
            ans %= MOD
            done.add((a,b))
    else:
        if (b, -a) in Cnt.keys():
            ans *= (pow(2,c,MOD)-1) + (pow(2,Cnt[(b,-a)],MOD)-1) + 1
            ans %= MOD
            done.add((a,b))
            done.add((b,-a))
        else:
            ans *= pow(2,c,MOD)
            ans %= MOD
            done.add((a,b))
# print(done)
if (0,0) not in Cnt:
    ans -= 1
    ans % MOD
print(ans)

# N = int(input())
# S = input()
# N, K = map(int, input().split())
# l = list(map(int, (input().split())))
# A = [[int(i) for i in input().split()] for _ in range(N)]


import asyncio
from asyncio import CancelledError, Queue

import pytest

from busrouter.router import (
    NokResponse,
    OkResponse,
    PublishRequest,
    PublishResponse,
    RouteSegment,
    SubscribeRequest,
    UnsubscribeAllRequest,
    UnsubscribeRequest,
    add_route,
    match_route,
    remove_route,
    remove_routes,
    route,
)

@pytest.mark.parametrize(
    "sub,pub,matches",
    [
        ["hello", "hello", True],
        ["hello/world", "hello/world", True],
        ["hello", "hello/world", False],
        ["hello/world", "hello", False],
        ["something/else", "#", True],
        ["#", "something/else", True],
        ["#", "#", True],
        ["#", "+", True],
        ["hello/+/world", "hello/nice/world", True],
        ["hello/nice/world", "hello/+/world", True],
        ["hello/+/world", "hello/nice/not", False],
    ],
)
def test_match_route(sub, pub, matches):
    route_map = RouteSegment()
    queue = object()
    add_route(route_map, sub, queue)
    if matches:
        assert match_route(route_map, pub) == [queue]
    else:
        assert match_route(route_map, pub) == []

def test_add_route():
    route_map = RouteSegment()
    queue = object()
    topic = "hello/world"
    add_route(route_map, topic, queue)

    assert "hello" in route_map
    assert "world" in route_map["hello"]
    assert route_map["hello"]["world"].routes == [queue]

def test_remove_route():
    route_map = RouteSegment()
    queue = object()
    queue2 = object()
    topic = "hello/world"
    topic2 = "other/world"
    add_route(route_map, topic, queue)
    add_route(route_map, topic2, queue)
    add_route(route_map, topic, queue2)
    add_route(route_map, topic2, queue2)

    assert route_map["hello"]["world"].routes == [queue, queue2]
    assert route_map["other"]["world"].routes == [queue, queue2]

    remove_route(route_map, topic, queue)
    assert route_map["hello"]["world"].routes == [queue2]
    assert route_map["other"]["world"].routes == [queue, queue2]

    remove_routes(route_map, queue2)
    assert route_map["hello"]["world"].routes == []
    assert route_map["other"]["world"].routes == [queue]

@pytest.mark.asyncio
async def test_subscribe_and_unsubscribe_request():
    request_queue = Queue()
    response_queue = Queue()
    topic = "cool/topic"
    router = asyncio.create_task(route(request_queue))
    await request_queue.put((response_queue, SubscribeRequest(topic)))
    response = await response_queue.get()
    assert isinstance(response, OkResponse)

    await request_queue.put((response_queue, UnsubscribeRequest(topic)))
    response = await response_queue.get()
    assert isinstance(response, OkResponse)

    router.cancel()
    try:
        await router
    except CancelledError:
        pass

@pytest.mark.asyncio
async def test_unsubscribe_request_error():
    request_queue = Queue()
    response_queue = Queue()
    topic = "cool/topic"
    router = asyncio.create_task(route(request_queue))

    await request_queue.put((response_queue, UnsubscribeRequest(topic)))
    response = await response_queue.get()
    assert isinstance(response, NokResponse)

    router.cancel()
    try:
        await router
    except CancelledError:
        pass

@pytest.mark.asyncio
async def test_unsubscribe_all_request():
    request_queue = Queue()
    response_queue = Queue()
    router = asyncio.create_task(route(request_queue))

    await request_queue.put((response_queue, UnsubscribeAllRequest()))
    response = await response_queue.get()
    assert isinstance(response, OkResponse)

    router.cancel()
    try:
        await router
    except CancelledError:
        pass

@pytest.mark.asyncio
async def test_publish():
    request_queue = Queue()
    pub_response_queue = Queue()
    sub_response_queue = Queue()
    router = asyncio.create_task(route(request_queue))
    sub_topic = "pubtest/+/topic"
    pub_topic = "pubtest/something/topic"

    message = b"testmsg"

    await request_queue.put((sub_response_queue, SubscribeRequest(sub_topic)))
    assert isinstance(await sub_response_queue.get(), OkResponse)
    await request_queue.put((pub_response_queue, PublishRequest(pub_topic, message)))
    assert isinstance(await pub_response_queue.get(), OkResponse)

    response = await sub_response_queue.get()
    assert isinstance(response, PublishResponse)
    assert response.topic == pub_topic
    assert response.message == message

    router.cancel()
    try:
        await router
    except CancelledError:
        pass


#!/usr/bin/env python3
#*******************************************************************************
#rrr_obs_bas_sub.py
#*******************************************************************************

#Purpose:
#Given a CSV file with timeseries observations at many gauges with the first
#column being time, the first row being gauge code (or name) and each subsequent
#row is flow observations, and given a shapefile with a subset of these gauges
#that includes both gauge code and river reach ID; this program creates a subset
#of observations in a format that is suitable for RAPID: i.e. a CSV file with
#sorted river IDS, and a CSV file with corresponding flow observations.
#Author:
#Cedric H. David, 2023-2023

#*******************************************************************************
#Import Python modules
#*******************************************************************************
import sys
import csv
import numpy
import fiona

#*******************************************************************************
#Declaration of variables (given as command line arguments)
#*******************************************************************************
# 1 - rrr_tQo_csv
# 2 - rrr_obs_shp
# 3 - rrr_rid_csv
# 4 - rrr_Qob_csv

#*******************************************************************************
#Get command line arguments
#*******************************************************************************
IS_arg=len(sys.argv)
if IS_arg != 5:
     print('ERROR - 4 and only 4 arguments can be used')
     raise SystemExit(22)

rrr_tQo_csv=sys.argv[1]
rrr_obs_shp=sys.argv[2]
rrr_rid_csv=sys.argv[3]
rrr_Qob_csv=sys.argv[4]

#*******************************************************************************
#Print input information
#*******************************************************************************
print('Command line inputs')
print(' - '+rrr_tQo_csv)
print(' - '+rrr_obs_shp)
print(' - '+rrr_rid_csv)
print(' - '+rrr_Qob_csv)

#*******************************************************************************
#Check if files exist
#*******************************************************************************
try:
     with open(rrr_tQo_csv) as file:
          pass
except IOError as e:
     print('ERROR - Unable to open '+rrr_tQo_csv)
     raise SystemExit(22)

try:
     with open(rrr_obs_shp) as file:
          pass
except IOError as e:
     print('WARNING - Unable to open '+rrr_obs_shp+', skipping')
     raise SystemExit(-22)

#*******************************************************************************
#Read CSV file
#*******************************************************************************
print('Read CSV file')

with open(rrr_tQo_csv) as csvfile:
     csvreader=csv.reader(csvfile)
     row=next(iter(csvreader))
     YV_tQo_nam=row[1:]
     IS_tQo_csv=len(YV_tQo_nam)

     IS_time=0
     for row in csvreader:
          IS_time=IS_time+1

print('- The number of gauges in CSV file is: '+str(IS_tQo_csv))
print('- The number of time steps in CSV file is: '+str(IS_time))

#*******************************************************************************
#Read gauge shapefile
#*******************************************************************************
print('Read gauge shapefile')

rrr_obs_lay=fiona.open(rrr_obs_shp, 'r')

if 'Sttn_Nm' in rrr_obs_lay[0]['properties']:
     YS_obs_nam='Sttn_Nm'
else:
     print('ERROR - Sttn_Nm does not exist in '+rrr_obs_shp)
     raise SystemExit(22)

if 'rivid' in rrr_obs_lay[0]['properties']:
     YS_obs_ids='rivid'
else:
     print('ERROR - rivid does not exist in '+rrr_obs_shp)
     raise SystemExit(22)

IS_obs_shp=len(rrr_obs_lay)
print(' - The number of gauge features is: '+str(IS_obs_shp))

YV_obs_nam=[]
IV_obs_ids=[]
for rrr_obs_fea in rrr_obs_lay:
     YV_obs_nam.append(rrr_obs_fea['properties'][YS_obs_nam])
     IV_obs_ids.append(rrr_obs_fea['properties'][YS_obs_ids])

#*******************************************************************************
#Create hash table
#*******************************************************************************
print('Create hash table')

YM_hsh={}
for JS_tQo_csv in range(IS_tQo_csv):
     tQo_nam=YV_tQo_nam[JS_tQo_csv]
     YM_hsh[tQo_nam]=JS_tQo_csv

print(' - Done')

#*******************************************************************************
#Check all requested basin stations are in input file
#*******************************************************************************
print('Check all requested basin stations are in input file')

for JS_obs_shp in range(IS_obs_shp):
     obs_nam=YV_obs_nam[JS_obs_shp]
     if obs_nam not in YM_hsh:
          print('ERROR - '+obs_nam+' does not exist in '+rrr_tQo_csv)
          raise SystemExit(22)

print(' - Done')

#*******************************************************************************
#Sort river IDs of subsample
#*******************************************************************************
print('Sort river IDs of subsample')

z=sorted(zip(IV_obs_ids,YV_obs_nam))
IV_obs_ids_srt,YV_obs_nam_srt=zip(*z)
#Sorting the lists together based on increasing value of the river ID.
IV_obs_ids_srt=list(IV_obs_ids_srt)
YV_obs_nam_srt=list(YV_obs_nam_srt)
#Because zip creates tuples and not lists

IV_obs_ids=IV_obs_ids_srt.copy()
YV_obs_nam=YV_obs_nam_srt.copy()
#Reassigning the original names after sorting

print(' - Done')

#*******************************************************************************
#Subsample observations and write CSV files
#*******************************************************************************
print('Subsample observations and write CSV files')

IV_obs_idx=[YM_hsh[tQo_nam] for tQo_nam in YV_obs_nam]

with open(rrr_rid_csv, 'w') as csvfil2:
     csvwriter = csv.writer(csvfil2, dialect='excel')
     for JS_obs_ids in range(len(IV_obs_ids)):
          csvwriter.writerow([IV_obs_ids[JS_obs_ids]])

with open(rrr_Qob_csv, 'w') as csvfil2:
     csvwriter = csv.writer(csvfil2, dialect='excel')

     with open(rrr_tQo_csv) as csvfile:
          csvreader=csv.reader(csvfile)
          row=next(iter(csvreader))

          for row in csvreader:
               ZV_Qob=row[1:]
               ZV_line=[ZV_Qob[idx] for idx in IV_obs_idx]
               csvwriter.writerow(ZV_line)

print(' - Done')

#*******************************************************************************
#End
#*******************************************************************************


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

labels = []
origtas = []
hyper = []
virttas = []

width = 0.20
with open('overhead.throughput.csv', 'r') as csvfile:
    plots = csv.reader(csvfile, delimiter='\t')

    for row in plots:
        labels.append(int(row[0]))
        virttas.append(float(row[1].strip()))
        origtas.append(float(row[3].strip()))
        hyper.append(float(row[2].strip()))

nm1 = np.array(origtas)
nm2 = np.array(hyper)
nm3 = np.array(virttas)

fig, ax = plt.subplots()

x_axis = np.arange(len(labels))
print(x_axis)
print(nm1)
ax.bar(x_axis- width, nm1, width, label='Monolithic TAS', color='#001a00')
ax.bar(x_axis, nm2, width, color='#006600', label='Grouped-TAS ', hatch='+'*3)
ax.bar(x_axis + width, nm3, width, color='#339933', label='Virt-TAS', hatch='/'*3)

ax.set_ylabel('Throughput (mbps)')
ax.set_yscale('log')
ax.set_ylim(100, 40000)

ax.set_xticks(x_axis)
ax.set_xticklabels(labels)
ax.set_title('Average throughput')
ax.set_xlabel('Message size (byte)')
ax.legend()

ax.grid(color='#b3b3b3', linestyle='-', linewidth=0.5)

fig.tight_layout()
plt.savefig("overhead.throughput.pdf", format="pdf", bbox_inches="tight")


""" Module for job searching on CareerBuilder.com. """

from job_searcher.job import Job
from job_searcher import JobSearcher

import requests
from bs4 import BeautifulSoup

class CareerBuilder (JobSearcher):

    """ JobSearcher for CareerBuilder.com. """

    BASE_URL = 'http://api.careerbuilder.com/v2/jobsearch'
    PARAM_DEV_KEY = 'DeveloperKey'
    PARAM_KEYWORDS = 'keywords'
    PARAM_PER_PAGE = "perpage"

    def __init__(self, developer_key):
        """ :param developer_key: Needed for identification. """
        self.developer_key = developer_key

    def find_results_amount(self, keyword=''):
        """Find the amount of results for a given keyword. """
        args = {self.PARAM_DEV_KEY: self.developer_key,
                self.PARAM_KEYWORDS: keyword}
        response = requests.get(self.BASE_URL, params=args)
        data = BeautifulSoup(response.text, features='xml')
        return int(data.ResponseJobSearch.TotalCount.contents[0])

    def find_results(self, keywords=[], amount=5):
        """ Perform a job search.

        :param keywords: Keywords, that should be contained in the returned
        results.
        :param amount: The amount of results wanted.
        :return: The jobs found by the given search parameters.
        """
        args = {self.PARAM_DEV_KEY: self.developer_key,
                self.PARAM_PER_PAGE: str(amount),
                self.PARAM_KEYWORDS: ','.join(keywords)}
        response = requests.get(self.BASE_URL, params=args)
        jobs = self.xml_to_jobs(response.text)
        return jobs

    @staticmethod
    def xml_to_jobs(xml):
        """ Convert xml to a list of jobs.

        :param xml: The xml string, that should be parsed.
        :return: A list of jobs.
        """
        soup = BeautifulSoup(xml, features='xml')
        results = soup.find_all('JobSearchResult')

        jobs = []
        for result in results:
            jobs.append(Job(title=result.JobTitle.text,
                            company_name=result.Company.text,
                            teaser=result.DescriptionTeaser.text,
                            job_url=result.JobDetailsURL.text))

        return jobs


from functools import partial

from PIL import Image, ImageFont, ImageDraw
import jax
import jax.numpy as jnp
from jax.example_libraries.optimizers import adam
import matplotlib.pyplot as plt

from pmwd import (
    Configuration,
    SimpleLCDM,
    boltzmann,
    white_noise, linear_modes,
    lpt,
    nbody,
    scatter,
)
from pmwd.vis_util import simshow

def model(modes, cosmo, conf):
    modes = linear_modes(modes, cosmo, conf)
    ptcl, obsvbl = lpt(modes, cosmo, conf)
    ptcl, obsvbl = nbody(ptcl, obsvbl, cosmo, conf)
    return ptcl

def scatter_2d(ptcl, conf):
    dens = jnp.zeros(tuple(2*s for s in conf.mesh_shape), dtype=conf.float_dtype)
    dens = scatter(ptcl, conf, mesh=dens, val=1, cell_size=conf.cell_size / 2)
    return dens.sum(axis=2)

pmwdshow = partial(simshow, figsize=(27/2, 8), cmap='cividis', colorbar=False)

def obj(tgt, modes, cosmo, conf):
    ptcl = model(modes, cosmo, conf)
    dens = scatter_2d(ptcl, conf)
    return (dens - tgt).var() / tgt.var()

obj_valgrad = jax.value_and_grad(obj, argnums=1)

def optim(tgt, modes, cosmo, conf, iters=100, lr=0.1):
    init, update, get_params = adam(lr)
    state = init(modes)

    def step(step, state, tgt, cosmo, conf):
        modes = get_params(state)
        value, grads = obj_valgrad(tgt, modes, cosmo, conf)
        state = update(step, grads, state)
        return value, state

    tgt = jnp.asarray(tgt)
    for i in range(iters):
        value, state = step(i, state, tgt, cosmo, conf)

    modes = get_params(state)
    return value, modes

text = 'pmwd'
font = ImageFont.truetype('../nova/NovaRoundSlim-BookOblique.ttf', 32)

ptcl_spacing = 10.
ptcl_grid_shape = (16, 27, 16)
mesh_shape = (32, 54, 32)
im_shape = (64, 108)
xy = (52, 28)

im = Image.new('L', im_shape[::-1], 255)
draw = ImageDraw.Draw(im)
draw.text(xy, text, font=font, anchor='mm')

# normalize the image to make the target
im_tgt = 1 - jnp.asarray(im) / 255
im_tgt *= jnp.prod(jnp.array(ptcl_grid_shape)) / im_tgt.sum()

conf = Configuration(ptcl_spacing, ptcl_grid_shape, mesh_shape)
cosmo = SimpleLCDM(conf)
seed = 0
modes = white_noise(seed, conf, real=True)
cosmo = boltzmann(cosmo, conf)

ptcl, obsvbl = lpt(linear_modes(modes, cosmo, conf), cosmo, conf)
fig, _ = pmwdshow(scatter_2d(ptcl, conf))
fig.savefig('optim_ini.pdf')
plt.close(fig)

ptcl, obsvbl = nbody(ptcl, obsvbl, cosmo, conf)
fig, _ = pmwdshow(scatter_2d(ptcl, conf))
fig.savefig('optim_0.pdf')
plt.close(fig)

ptcl, obsvbl = nbody(ptcl, obsvbl, cosmo, conf, reverse=True)
fig, _ = pmwdshow(scatter_2d(ptcl, conf))
fig.savefig('optim_rev.pdf')
plt.close(fig)

loss, modes_optim = optim(im_tgt, modes, cosmo, conf, iters=10)
fig, _ = pmwdshow(scatter_2d(model(modes_optim, cosmo, conf), conf))
fig.savefig('optim_10.pdf')
plt.close(fig)

loss, modes_optim = optim(im_tgt, modes, cosmo, conf, iters=100)
fig, _ = pmwdshow(scatter_2d(model(modes_optim, cosmo, conf), conf))
fig.savefig('optim_100.pdf')
plt.close(fig)

loss, modes_optim = optim(im_tgt, modes, cosmo, conf, iters=1000)
fig, _ = pmwdshow(scatter_2d(model(modes_optim, cosmo, conf), conf))
fig.savefig('optim_1000.pdf')
plt.close(fig)


import numpy as np
import torch
from PIL import Image
import random

def seed_random_generators(seed: int = 0, deterministic: bool = True) -> None:
    """
        Seed random generators with given seed.
    """
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    random.seed(seed)

    if deterministic:
        torch.backends.cudnn.benchmark = False
        torch.backends.cudnn.deterministic = True

def numpy_image_to_tensor(x):
    """
        Convert numpy image of shape (2, H, W, 3) with values 0 - 255 to torch tensor with values 0 - 1.
        Output tensor of shape (3, 2, H, W).
    """
    y = torch.from_numpy(x / 255).type(torch.Tensor)
    y = torch.permute(y, (3, 0, 1, 2))
    return y

def tensor_to_numpy_image(x: torch.Tensor) -> np.ndarray:
    """
        Convert tensor image of shape (3, 2, H, W) with values 0 - 1 to numpy image with values 0 - 255.
        Output numpy array of shape (2, H, W, 3).
    """
    y = torch.permute(x, (1, 2, 3, 0))
    return (y.cpu().detach() * 255).type(torch.uint8).numpy()

def normalize_tensor(x: torch.Tensor) -> torch.Tensor:
    return (x - x.min()) / (x.max() - x.min())

def visualize_tensor(x: torch.Tensor, filename: str = "") -> None:
    """
        Take tensor image and display left and right view side-by-side. If filename is provided, save image instead of displaying it.
    """
    y = tensor_to_numpy_image(x)
    y = np.hstack([y[0], y[1]])
    image = Image.fromarray(y)
    if filename:
        image.save(filename)
    else:
        image.show()

def choose_model(configs):
    """
    Ask user to choose model/config to use.
    """
    n = -1
    while n < 0 or n >= len(configs):
        print("Select model:")
        for i, config in enumerate(configs):
            print(f"[{i}] {config['name']}")
        n = int(input() or 0)

    config = configs[n]
    print("Loaded model configuration:")
    for key, value in config.items():
        print(f"\t* {key}: {value}")

    return config


import time
import wave
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import sys
import math

fig = plt.figure()

N = 1024
FS = 44100
HAM_WIN = np.hamming(N)

magnitude = np.array([])
sinFreq = np.array([])

def main():
    args = sys.argv

    path = args[1]

    wf = wave.open(path , "r" )
    buf = wf.readframes(wf.getnframes())
    # バイナリデータを16bit整数に変換
    data = np.frombuffer(buf, dtype="int16")

    # short型のデータバッファをfloatに
    in_float = np.frombuffer(data, dtype=np.int16).astype(np.float)
    # 値の範囲を-1.0 ~ 1,0に変換
    in_float[in_float > 0.0] /= float(2**15 - 1)
    in_float[in_float <= 0.0] /= float(2**15)

    dt = 1/FS
    t1 = np.arange(0, in_float.size*dt, N*dt) # 時間軸
    t2 = np.arange(0, in_float.size*dt, N*dt) # 時間軸
    t3 = np.arange(0, in_float.size*dt, dt) # 時間軸

    global magnitude
    global sinFreq

    sinBaseFreq = int(2000/(FS/N))

    for i in range(int(in_float.size/N)):
        start = int(i*N)

        f = HAM_WIN*in_float[start:start+N]
        fSp = np.fft.fft(f,n=None)
        ampSp = np.abs(fSp/(N/2))
        ampSum = ampSp[:int(N/2)].sum()
        db = 20*math.log10(ampSum)
        magnitude = np.r_[magnitude,ampSum]
        sinFreqMag = 0.000001
        sinFreqDB = 0
        if ampSum < 0.055:
            roop = 5
            for i in range(roop):
                sinFreqMag += ampSp[int(sinBaseFreq + i - roop/2)]
        # sinFreq = np.r_[sinFreq,sinFreqDB]
        sinFreq = np.r_[sinFreq,sinFreqMag]

    # PowerSpectreArea
    # plt.subplot(3,1,1)
    # plt.ylim([0.0,0.6])
    # plt.plot(t1,magnitude)
    # plt.ylabel('SpectrumArea', fontsize=10)
    # 20kFreqPower
    # plt.subplot(2,1,1)
    plt.ylim([0.0,0.006])
    plt.plot(t2,sinFreq)
    plt.ylabel('Magnitude', fontsize=10)
    # 元信号
    # plt.subplot(2,1,2)
    # plt.ylim([-0.25,0.25])
    # plt.plot(t3,in_float)
    # plt.ylabel('Amplitude', fontsize=10)
    plt.xlabel("Time[sec]", fontsize=10)
    plt.show()

if __name__ == '__main__':
    main()


from datetime import timedelta
from freezegun import freeze_time

from healthysnake import levels
from healthysnake.dependency import Dependency

def success_check():
    return True

class TestDependencyInitialisation(object):
    """
    Tests initialization of the dependency class
    """
    def test_defaults(self):
        """
        The dependency should be initialized with appropriate default values
        """
        srv = Dependency('sherlock', success_check)
        assert srv.name == 'sherlock'
        assert srv._check == success_check
        assert srv._healthy is True
        assert srv.level == levels.HARD
        assert srv._interval == timedelta(seconds=Dependency.DEFAULT_INTERVAL)

    def test_str(self):
        """
        The string representation of the dependency should return the dependency name, state and failure level
        """
        srv = Dependency('sherlock', success_check)
        stringified = str(srv)
        assert stringified == 'sherlock [state=healthy, level=2]'

    def test_state_str(self):
        """
        The method should return the appropriate value depending on the value of the _healthy attribute
        """
        srv = Dependency('sherlock', success_check)
        assert srv._state_str() == Dependency.STATE_HEALTHY
        srv._healthy = False
        assert srv._state_str() == Dependency.STATE_UNHEALTHY

    @freeze_time('2017-1-1 12:00:00')
    def test_due(self):
        """
        The method should return False if checked within last <interval> seconds, otherwise True
        """
        srv = Dependency('sherlock', success_check)
        assert srv.due() is False
        srv.last_updated = srv.last_updated - timedelta(seconds=60)
        assert srv.due() is True

    def test_healthy(self):
        """
        The method should identify whether the dependency is healthy or not
        """
        srv = Dependency('sherlock', success_check)
        srv._healthy = False
        assert srv.healthy() == (False, '')
        srv.last_updated = srv.last_updated - timedelta(seconds=60)
        assert srv.healthy() == (True, '')


from requests import get
from dotenv import load_dotenv
import requests
import speech_recognition as sr
import pywhatkit as kit
import wikipedia
import pyttsx3
import datetime
import random
import webbrowser
import pyjokes
import sys
import os
import time
import cv2
import speedtest
import re

load_dotenv()
api_key = os.getenv("API_KEY")
if api_key is None:
    sys.exit("The API key was not defined correctly. Please check the .env file.")

engine = pyttsx3.init("sapi5")
voices = engine.getProperty("voices")

desired_index = 0
for index, voice in enumerate(voices):
    if voice.name == "Microsoft Zira Desktop - English (United States)":
        desired_index = index
        break

engine.setProperty("voice", voices[desired_index].id)

def speak(audio):
    engine.say(audio)
    print(audio)
    engine.runAndWait()

# Config Voice IA
def guidecommand():
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening now...")
        r.pause_threshold = 1
        audio = r.listen(source, timeout=5, phrase_time_limit=8)

    try:
        print("Recognizing...")
        query = r.recognize_google(audio, language="en-in")
        print(f"User said: {query}")
    except Exception as e:
        speak("Say that again please...")
        return "none"
    return query

greetings = [
    "Hi sir. How can I make your day better?",
    "Hi, I'm here to help. How can I be of assistance?",
    "Hi handsome, what do we have for today?" "How can I assist you today?",
    "What can I do to help you?",
    "What do you need help with?",
    "Is there anything I can do for you?",
]

helps = [
    "Sir, do you have any other work?",
    "Sir, do you need help with anything else?",
    "Sir, do you need assistance with any other matters or issues?",
    "Sir, is there something else I can help you with?",
    "Sir, is there anything else I can do for you today?",
    "Sir, are there any other matters I can attend to on your behalf?",
]

def news():
    req_url = f"http://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey={api_key}"

    main_page = requests.get(req_url).json()
    articles = main_page["articles"]
    head = []
    day = [
        "first",
        "second",
        "third",
        "fourth",
        "fifth",
        "sixth",
        "seventh",
        "eighth",
        "ninth",
        "tenth",
    ]
    for ar in articles:
        head.append(ar["title"])
    for i in range(len(day)):
        speak(f"'today's {day[i]} news is: {head[i]}")

def get_quote():
    url = "https://api.quotable.io/random"
    response = requests.get(url)
    data = response.json()
    quote = data["content"]
    author = data["author"]
    return quote, author

def calculate(expression):
    expression = re.sub("[^0-9+\-*/().]", "", expression)
    try:
        result = eval(expression)
        return str(result)
    except:
        return "Sorry, unable to calculate the expression."

# Config Time and Welcome
def initiate():
    hour = int(datetime.datetime.now().hour)
    tt = time.strftime("%I:%M %p")

    if hour >= 0 and hour <= 12:
        speak(f"Good Morning, its {tt}")
    elif hour > 12 and hour < 18:
        speak(f"Good Afternoon, its {tt}")
    else:
        speak(f"Good Evening, its {tt}")
    greeting = random.choice(greetings)
    speak(greeting)

if __name__ == "__main__":
    initiate()

    while True:
        if 1:
            request = guidecommand().lower()

            # Logic building for tasks here
            if "open notepad" in request:
                npath = "C:\\Windows\\system32\\notepad.exe"
                os.startfile(npath)

            elif "close notepad" in request:
                speak("Okay, closing notepad")
                os.system("taskkill /f /im notepad.exe")

            elif "open vscode" in request:
                speak("Opening visual studio code")
                os.system("code")

            elif "close vscode" in request:
                speak("Okay, closing visual studio code")
                os.system("taskkill /f /im code.exe")

            elif "motivational quote" in request:
                quote, author = get_quote()
                speak(quote)
                speak(f"- {author}")

            elif "my ip" in request:
                ip = get("https://api.ipify.org").text
                speak(f"your IP address is {ip}")

            elif "calculate" in request:
                speak("Sure, what is the expression?")
                expression = guidecommand().lower()
                result = calculate(expression)
                speak(f"The result is: {result}")

            elif "joke" in request:
                joke_rq = pyjokes.get_joke(language="en", category="neutral")
                speak(joke_rq)

            elif "any news" in request:
                speak("Sir, Well... let me see")
                news()

            elif "wikipedia" in request:
                speak("Searching in wikipedia...")
                request = request.place("wikipedia", "")
                results = wikipedia.summary(request, sentences=2)
                speak("according to wikipedia")
                speak(results)

            elif "open camera" in request:
                cap = cv2.VideoCapture(0)
                while True:
                    ret, img = cap.read()
                    cv2.imshow("webcam", img)
                    k = cv2.waitkey(50)
                    if k == 27:
                        break
                    cap.release()
                    cv2.destroyAllWindows()

            elif "play music" in request:
                music_dir = "E:\\music"
                songs = os.listdir(music_dir)
                for song in songs:
                    if song.endswith(".mp3"):
                        os.startfile(os.path.join(music_dir, song))

            elif "open prompt" in request:
                os.system("start cmd")

            elif "open email" in request:
                speak("Opening email")
                webbrowser.open("https://outlook.live.com/mail/")

            elif "open youtube" in request:
                webbrowser.open("www.youtube.com")

            elif "open facebook" in request:
                webbrowser.open("www.facebook.com")

            elif "open twitter" in request:
                webbrowser.open("www.twitter.com")

            elif "open google" in request:
                speak("Sir, what should I search on google")
                cm = guidecommand().lower()
                webbrowser.open(f"{cm}")

            elif "play song on youtube" in request:
                kit.playonyt("see you again")

            elif "play surprise" in request:
                webbrowser.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ")

            elif "send message" in request:
                kit.sendwhatmsg("+DDDANDNUMBER", "Hi, how are you?", 4, 13)
                time.sleep(120)
                speak("message has been successfully")

            elif "my sir" in request:
                webbrowser.open("https://github.com/coelhiN77")

            elif "your name" in request:
                name = "My name is EVA"
                speak(name)

            elif "my name" in request:
                creator = "Your name is coelhiN"
                speak(creator)

            elif "how old are you" in request:
                age = "I am an artificial intelligence, I don't have an age like humans"
                speak(age)

            elif "current time" in request:
                time = datetime.datetime.now().strftime("%I%M%p")
                speak(time)

            elif "bye eva" in request:
                speak("Thanks for using me sir, have a good day.")
                sys.exit()

            elif "you can sleep now" in request:
                speak("I will rest now, see you later")
                sys.exit()

            help = random.choice(helps)
            speak(help)


import requests  #Importamos la librería requests
#especie = input()
especie = "human"
print("SOLICITANDO INFORMACION DE INTERNET")
print("espere....")
URL = "https://rickandmortyapi.com/api/character/?species="+especie #configuramos la url
#solicitamos la información y guardamos la respuesta en data.
dataPage = requests.get(URL)
dataPage = dataPage.json() #convertimos la respuesta en dict
paginas = dataPage['info']['pages']
cantidad = dataPage['info']['count']
#for element in data: #iteramos sobre data
    #print(element) #Accedemos a sus valores
#print("Total de "+str(especie)+" "+str(data['info']['count']))

j = 0
for i in range(1,paginas+1):
    URL = "https://rickandmortyapi.com/api/character/?page="+str(i)+"&species="+especie
    data = requests.get(URL)
    data = data.json() #convertimos la respuesta en dict
    for j in data['results']:
        print(j['name']+" "+['species'])


'''K-nearest neighbors classification and elbow method visualization.
(Figure 2.4 and 2.5).
'''

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.neighbors import KNeighborsClassifier
from sklearn.decomposition import PCA

plt.style.use('seaborn')

def generate_dataset():
    X, y = make_classification(n_samples=2000, n_features=20, n_redundant=8,
                                n_informative=4,
                                n_clusters_per_class=1, n_classes=2)
    X = StandardScaler().fit_transform(X)
    pca = PCA(n_components=2)
    X = pca.fit_transform(X)
    return X, y

def generate_mesh(X):
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5

    h = .02  # step size in the mesh
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                            np.arange(y_min, y_max, h))
    return xx, yy

def generate_plot(X_train, X_test, y_train, y_test, xx, yy):
    figure = plt.figure(figsize=(10, 6))

    ax1 = plt.subplot(1, 2, 1)
    ax1 = plot_dataset(ax1, X_train, X_test, y_train, y_test, xx, yy)
    ax2 = plt.subplot(1, 2, 2)
    ax2 = plot_decision_boundary(ax2, X_train, X_test, y_train, y_test, xx, yy)

    plt.tight_layout()
    plt.show()

def plot_dataset(ax, X_train, X_test, y_train, y_test, xx, yy):
    cm_bright = ListedColormap(['#FF0000', '#0000FF'])
    # Plot the training points
    ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright,
                edgecolors='k')
    # Plot the testing points
    ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6,
                edgecolors='k')
    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xticks(())
    ax.set_yticks(())
    return ax

def plot_decision_boundary(ax, X_train, X_test, y_train, y_test, xx, yy):
    clf, _ = classify(K_NEIGHBORS, X_train, y_train, X_test, y_test)

    # Plot the decision boundary. For that, we will assign a color to each
    # point in the mesh [x_min, x_max]x[y_min, y_max].
    Z = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1]

    # Put the result into a color plot
    Z = Z.reshape(xx.shape)

    cm_bright = ListedColormap(['#99ccff', '#ff9999'])
    cm_dark = ListedColormap(['#FF0000', '#0000FF'])

    ax.contourf(xx, yy, Z, cmap=cm_bright, alpha=.8)

    # Plot the training points
    ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_dark,
                edgecolors='k')
    # Plot the testing points
    ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_dark,
                edgecolors='k', alpha=0.6)

    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xticks(())
    ax.set_yticks(())
    return ax

def classify(K, X_train, y_train, X_test, y_test):
    clf = KNeighborsClassifier(K)
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
    error = np.mean(y_pred != y_test)
    return clf, error

def optim_K(X_train, X_test, y_train, y_test):
    K_lst = np.arange(1, 60)
    error_buffer = []
    for K in K_lst:
        _, error = classify(K, X_train, y_train, X_test, y_test)
        error_buffer.append(error)

    fig = plt.figure(figsize=(8,6))
    plt.plot(K_lst, error_buffer, color='b', linestyle='dashed', marker='o',
            markerfacecolor='r', markersize=5)
    plt.xlabel('K value')
    plt.ylabel('error rate')
    fig.tight_layout()
    plt.show()

if __name__ == '__main__':
    K_NEIGHBORS = 15

    X, y = generate_dataset()
    X_train, X_test, y_train, y_test = \
        train_test_split(X, y, test_size=.4, random_state=42)
    xx, yy = generate_mesh(X)
    generate_plot(X_train, X_test, y_train, y_test, xx, yy)

    optim_K(X_train, X_test, y_train, y_test)