"""
Nikunj Upadhyay
Class: CS 521 - Fall 1
Date: 10/16/2021
Homework Problem # Project
Description of Problem (1-2 sentence summary in your own words):

AddUpdatePatient helps to add a new patient to the system or update
the demographic details of the patient. Common functionality like
update address and contact details are re-used between new patient flow
and update patient flow.
"""

from model.Patient import Patient
from utilities.AppConstants import AppConstants
from utilities.CSVUtility import FileHandlerUtility
from utilities.PatientValidator import PatientValidator

class AddUpdateFlowHandler:
    """Helps to add a new patient or updated details of existing patient.
    Initializing the class with a non-empty patient, starts the flow in
    update demographic mode. It defaults to an empty patient object during
    initialization.
    """

    # Prompt to be displayed to request basic details like, name , date of
    # birth and gender.
    NAME_GENDER_INPUT_MESSAGE = "Please enter FirstName, LastName,Date of " \
                                "Birth and Gender of the patient you want " \
                                "to add, separated by '{}'\nFor Gender " \
                                "please enter M for Male, F for Female " \
                                "and O for Other."\
        .format(AppConstants.INPUT_DELIMITER)

    # Prompt to be displayed to request address details like address line 1,
    # state, zip and etc.
    ADDRESS_INPUT_MESSAGE = "Please enter Address Line 1, Line 2, City, " \
                            "State and Zip all separated " \
                            "by '{}'".format(AppConstants.INPUT_DELIMITER)

    # Prompt to be displayed to request contact details like phone and email.
    CONTACT_INPUT_MESSAGE = "Please enter Phone and email-id separated " \
                            "by '{}'".format(AppConstants.INPUT_DELIMITER)

    # Error message to be displayed when invalid gender value is entered out
    # of permissible values.
    ERROR_MESSAGE_GENDER = "Error! Please enter a valid gender value."

    # Error message to be displayed when a duplicate match is found, which
    # matches name, dob and gender.
    ERROR_DUPLICATE_PATIENT = "Error! Found Duplicate patient with same" \
                              " name {},{}.\nSystem does not allow to" \
                              " add Duplicate entries. Please try again!"

    # Error message to be displayed when the user enters zip code in in-valid
    # format.
    ERROR_ZIP_CODE = "Error! Please enter a valid value for zip code ex:" \
                     " 12345"

    # Error message to be displayed when user enters invalid character like a
    # comma in the input, which could affect the CSV format.
    ERROR_INVALID_DELIMITER_ENTRIES = "Error! Please enter valid " \
                                      "entries separated by '{}'". \
        format(AppConstants.INPUT_DELIMITER)

    # Message to be displayed when a new patient is registered.
    NEW_PATIENT_REGISTRATION_SUCCESS = "New Patient {},{} has been " \
                                       "added registered successfully " \
                                       "with the system.\n"

    # Count pertaining First name, last name , date of birth and Gender as the
    # basic demographic entries expected from input function.
    BASIC_DEMOGRAPHIC_ENTRIES = 4

    # Count pertaining address details like Address line 1, line 2, City, State
    # amd zip, expected from input function.
    ADDRESS_ENTRIES = 5

    # Count pertaining contact details like phone and e-mail
    # expected from input function.
    CONTACT_ENTRIES = 2

    def __init__(self, patient=None):
        """ Initialize with non empty patient object in case we want to use
        the current class in update patient details mode, else it defaults
        to new patient creation as the default patient value is immutable
        value None"""
        if patient is None:
            # Set a new object if none to private patient attribute
            # ex: New Patient creation flow.
            self.__patient = Patient()
        else:
            # Set the patient object if not None to private
            # patient attribute. ex: Update patient
            self.__patient = patient
        self.validator = PatientValidator()  # public validator attribute

    def add_update_patient_flow(self):
        """Start the create patient or update patient details mode. For
        a input patient object which is created using a non empty patient id
        it starts the update patient details mode.
        For update patient mode, name,dob and gender validation is skipped as
        the patient is already identified and
        flow directly  jumps to address and contact details validation.
        Also in update patient mode, it returns a patient object and does not
        save the object. It is upto the receiver to identify the change and
        save it.

        For new patient, the patient details are saved to the file.
        """
        name_dob_validation = False  # Name and dob validation status
        address_validation = False  # Address validation status
        contact_validation = False  # Contact validation status

        while True:  # Keep prompting user to enter patient details.
            if name_dob_validation is False and self.__is_in_new_patient_mode():
                # First perform basic details validation like name which exists
                # only for new patient.
                name_dob_validation = self.__handle_basic_entries()
            elif address_validation is False:
                # Second perform validation for address details.
                address_validation = self.__handle_address_entries()
            elif contact_validation is False:
                # At last perform validation for contact details.
                contact_validation = self.__handle_contact_entries()

            if (name_dob_validation or
                self.__is_in_new_patient_mode() is False) and \
                    address_validation and contact_validation:
                # All Validation passed so save the data.
                file_handler = FileHandlerUtility()  # CSV, File handler object

                if self.__is_in_new_patient_mode() is False:
                    return self.__patient  # Update returns modified patient
                else:
                    # New Patient writes to the CSV.
                    # New patient id is the max id + 1. This way a unique
                    # patient id is created with simple logic.
                    new_patient_id = self.validator.generate_new_patient_id()
                    self.__patient.set_patient_id(new_patient_id)

                    # Convert Patient object to list before saving to csv.
                    patient_details_list = \
                        self.__patient.get_list_template_to_save()
                    file_handler.write_new_record(patient_details_list)
                    print(AddUpdateFlowHandler.NEW_PATIENT_REGISTRATION_SUCCESS
                          .format(self.__patient.get_first_name(),
                                  self.__patient.get_last_name()))
                break

    def __is_in_new_patient_mode(self):
        """If the class is initialized with patient object which has a
         patient id, the flow starts in update demographic mode.
         It returns true to help identify if its a new patient creation else
         returns false for update demographics."""
        if len(self.__patient.get_patient_id()) == 0:
            return True  # New patient mode
        else:
            return False  # Update patient demographics mode.

    def __handle_basic_entries(self):
        """Handle the flow of basic patient entries like name, dob, gender and
        also perform the required validation with it. This is usually done
        during new patient registration.

        Returns True once the user enters all the input values correctly.
        After which flow can move to next input which is address details."""

        # Get the user input for address entries from console.
        name_dob = input(AddUpdateFlowHandler.NAME_GENDER_INPUT_MESSAGE)

        # Perform input string validation for invalid characters
        text_has_valid_chars = self.validator.has_valid_character(name_dob)
        if text_has_valid_chars[0] is False:  # In-valid input characters.
            # Error! Print invalid character message.s
            print(text_has_valid_chars[1])
        else:  # Found input text valid, proceed ahead.
            name_dob_input_list = self.validator.get_list_from_input(name_dob)

            if len(name_dob_input_list) != \
                    AddUpdateFlowHandler.BASIC_DEMOGRAPHIC_ENTRIES:
                # User entered less or more entries separated by delimiter.
                # Show the error message.
                print(AddUpdateFlowHandler.ERROR_INVALID_DELIMITER_ENTRIES)
            else:
                first_name_str, last_name_str, dob_str, gender_abbreviation_str\
                    = name_dob_input_list

                gender_str = self.validator.validate_gender(
                    gender_abbreviation_str)  # Validate gender abbreviation.

                dob_validation = self.validator.has_validate_date_format(
                    dob_str)  # Validate dob is in correct format or not.
                if dob_validation[0] is False:  # DOB validation failed.
                    print(dob_validation[1])  # Show DOB invalid message.
                elif gender_str is not None:
                    # All validation passed, finally check for duplicate.
                    if self.validator.check_if_patient_exits(first_name_str,
                                                             last_name_str,
                                                             dob_str,
                                                             gender_str):
                        # Duplicate patient found, show error message.
                        print(AddUpdateFlowHandler.ERROR_DUPLICATE_PATIENT.
                              format(last_name_str.title(),
                                     first_name_str.title()))
                    else:
                        # No duplicates and all validation passed update
                        # the patient attribute.
                        self.__patient.set_gender(gender_str)
                        self.__patient.set_first_name(first_name_str)
                        self.__patient.set_last_name(last_name_str)
                        self.__patient.set_dob(dob_str)
                        return True  # True helps to end basic info entry flow
                else:  # Gender Validation failed
                    print(AddUpdateFlowHandler.ERROR_MESSAGE_GENDER)

        return False

    def __handle_address_entries(self):
        """Handles the flow to ask user for address details during new
        patient registration or during update demographics.

        Returns True once the user enters all the input values correctly.
        After which flow can move to next input which is contact details."""

        # Get the user input for address entries from console.
        address = input(AddUpdateFlowHandler.ADDRESS_INPUT_MESSAGE)

        # Perform input string validation for invalid characters
        text_has_valid_chars = self.validator.has_valid_character(address)
        if text_has_valid_chars[0] is False:  # In-valid input characters.
            # Error! Print invalid character message.
            print(text_has_valid_chars[1])
        else:  # Found input text valid, proceed ahead.
            address_input_list = self.validator.get_list_from_input(address)

            if len(address_input_list) != AddUpdateFlowHandler.ADDRESS_ENTRIES:
                # User entered less or more entries separated by delimiter.
                # Show the error message.
                print(AddUpdateFlowHandler.ERROR_INVALID_DELIMITER_ENTRIES)
            else:  # List size matches the expected size
                address1, address2, city, state, address_zip = \
                    address_input_list  # assign using multiple assignment

                # Validate state input, must be 2 characters and match
                # the available list of states.
                state_validation = self.validator.has_valid_state(state)

                if self.validator.is_zip_code_valid(address_zip) is False:
                    # User entered invalid zip code, show message.
                    print(self.ERROR_ZIP_CODE)
                elif state_validation[0] is False:  # State validation failed.
                    print(state_validation[1])  # print error message
                else:
                    # All validation passed update the patient attribute.
                    self.__patient.set_address_line_1(address1)
                    self.__patient.set_address_line_2(address2)
                    self.__patient.set_address_city(city)
                    self.__patient.set_address_state(state)
                    self.__patient.set_address_zip(address_zip)
                    return True  # True helps to end address entry flow

        return False

    def __handle_contact_entries(self):
        """Handles the flow to ask user for contact details like phone and
        email during patient registration or during update demographics.

        Returns True once the user enters all the input values correctly.
        After which flow can be completed either by updating the demographics
        or creating a new patient.
        """

        # Get the user input for contact entries from console
        contact_details = input(
            AddUpdateFlowHandler.CONTACT_INPUT_MESSAGE)

        # Perform input string validation for invalid characters
        text_has_valid_chars = self.validator. \
            has_valid_character(contact_details)
        if text_has_valid_chars[0] is False:  # In-valid input characters.
            # Error! Print invalid character message.
            print(text_has_valid_chars[1])
        else:  # Found input text valid, proceed ahead.
            contact_input_list = self.validator.\
                get_list_from_input(contact_details)
            if len(contact_input_list) != AddUpdateFlowHandler.CONTACT_ENTRIES:
                # User entered less or more entries separated by delimiter.
                # Show the error message.
                print(AddUpdateFlowHandler.ERROR_INVALID_DELIMITER_ENTRIES)
            else:
                # All validation passed update the patient attribute.
                phone, email = contact_input_list
                self.__patient.set_phone(phone)
                self.__patient.set_email(email)
                return True  # True helps to end contact entry flow
        return False


import os

import matplotlib.pyplot as plt
import numpy as np

def intermediate_output_to_fig(z, img_ctr, label, predicted, confidence):
    n_columns = 4
    n_rows = 3
    f, ax = plt.subplots(n_rows, n_columns)
    f.tight_layout()
    for i, channel_o in enumerate(z):
        c_img = channel_o * 1
        r, c = divmod(i, n_columns)
        ax[r][c].set_title('Channel ' + str(i))
        # ax[r][c].xticks([])
        # ax[r][c].yticks([])
        low = np.quantile(c_img, 0.01)
        high = np.quantile(c_img, 0.99)
        im = ax[r][c].imshow(c_img, vmin=low, vmax=high, interpolation=None)
        f.colorbar(im, ax=ax[r][c])
    if not os.path.exists(f"bottleneck_output/7b-3ch/{label}"):
        os.mkdir(f"bottleneck_output/7b-3ch/{label}")
    f.savefig(f"bottleneck_output/7b-3ch/{label}/{predicted}{img_ctr}_conf={confidence}_3.png")
    plt.close()


from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.sql.types import *

spark = SparkSession.builder.appName("Covid ETL").getOrCreate()

covid_data = spark.read.csv('gs://[bucket-name]/data/*.csv',
                            sep=';', header='true', inferSchema='true')

# #### Processing data ####

# Removing hour from "data" column

covid_data = covid_data.withColumn("data", split(col("data"), " ").getItem(0))

# Preparing total cases data to transformation
covid_data = covid_data.withColumn("casosAcumulado",
                                   covid_data['casosAcumulado'].cast(FloatType()))

# Data is updated to December 2021

data = "2021-12-31"  # date = 2021 December 31th
regiao = "Brasil"  # region columns with "Brasil" value

brasil_covid = covid_data.where((covid_data.regiao == regiao) &
                                (covid_data.data == data))

# #### Creating views ####

# View for the recovered and under monitoring, respectively

recuperados_brasil = brasil_covid\
    .select(brasil_covid["Recuperadosnovos"].alias("Casos_Recuperados"),
            brasil_covid["emAcompanhamentoNovos"].alias("Em_Acompanhamento"))

# View of accumulated cases, new cases and incidence per 100 thousand people, respectively

casos_brasil = brasil_covid\
    .select(brasil_covid["casosAcumulado"].alias("Casos_Acumulados"),
            brasil_covid["casosNovos"].alias("Casos_Novos"),
            (round(brasil_covid["casosAcumulado"] /
                   brasil_covid["populacaoTCU2019"]*100000, 1))
            .alias("Incidencia"))

# View for deaths, fatality and mortality rate per 100 thousand people, respectively

obitos_brasil = brasil_covid\
    .select(brasil_covid["obitosAcumulado"].alias("Obitos_acumulados"),
            brasil_covid["obitosNovos"].alias("Obitos_novos"),
            (round(brasil_covid["obitosAcumulado"] /
                   brasil_covid["casosAcumulado"]*100, 1)).alias("Letalidade"),
            (round(brasil_covid["obitosAcumulado"] /
                   brasil_covid["populacaoTCU2019"]*100000, 1)).alias("Mortalidade"))

# #### Uploading views to BigQuery dataset tables ####

recuperados_brasil.write \
  .format("bigquery") \
  .option("writeMethod", "direct",) \
  .mode("overwrite") \
  .save("covid_views.recuperados_brasil")

casos_brasil.write \
  .format("bigquery") \
  .option("writeMethod", "direct") \
  .mode("overwrite") \
  .save("covid_views.casos_brasil")

obitos_brasil.write \
  .format("bigquery") \
  .option("writeMethod", "direct") \
  .mode("overwrite") \
  .save("covid_views.obitos_brasil")


#!/usr/bin/env python

from setuptools import setup

def reqs_from_file(filename):
    with open(filename) as f:
        lineiter = (line.rstrip() for line in f if not line.startswith("#"))
        return list(filter(None, lineiter))

setup(
    name='rewrite_cassandra_yaml',
    version='0.0.3',
    description='Script to rewrite a cassandra yaml file to allow remote access',
    author='Hugh Brown',
    author_email='hughdbrown@yahoo.com',

    # Required packages
    install_requires=reqs_from_file('requirements.txt'),
    # tests_require=reqs_from_file('test-requirements.txt'),

    # Main packages
    packages=[
        'src',
    ],

    zip_safe=False,

    scripts=[
        'bin/rewrite-cassandra-yaml',
    ],
    entry_points={
        'console_scripts': [
            'rewrite-cassandra-yaml = src.rewrite_cassandra_yaml:main',
        ],
    },
)


# encoding: utf-8
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Contact: Kyle Lahnakoski (kyle@lahnakoski.com)
#
import re
from datetime import datetime, date
from decimal import Decimal
from math import isnan

from mo_dots import split_field, NullType, is_many, is_data, concat_field, is_sequence
from mo_future import text, none_type, items, first, POS_INF
from mo_logs import Log
from mo_times import Date

def to_jx_type(value):
    if isinstance(value, JxType):
        return value
    try:
        return _json_type_to_jx_type[value]
    except Exception:
        return JX_ANY

class JxType(object):
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

    def __or__(self, other):
        other = to_jx_type(other)
        if self is JX_IS_NULL:
            return other
        if self is JX_ANY:
            return self

        sd = self.__dict__.copy()
        od = other.__dict__

        dirty = False
        for k, ov in od.items():
            sv = sd.get(k)
            if sv is ov:
                continue
            if sv is None:
                if k in JX_NUMBER_TYPES.__dict__ and sd.get(NUMBER_KEY):
                    continue
                elif k is NUMBER_KEY and any(sd.get(kk) for kk in JX_NUMBER_TYPES.__dict__.keys()):
                    for kk in JX_NUMBER_TYPES.__dict__.keys():
                        try:
                            del sd[kk]
                        except Exception as cause:
                            pass
                    sd[k] = JX_NUMBER.__dict__[k]
                    dirty = True
                    continue
                sd[k] = ov
                dirty = True
                continue
            if isinstance(sv, JxType) and isinstance(ov, JxType):
                new_value = sv | ov
                if new_value is sv:
                    continue
                sd[k] = new_value
                dirty = True
                continue

            Log.error("Not expected")

        if not dirty:
            return self

        output = _new(JxType)
        output.__dict__ = sd
        return output

    def __getitem__(self, item):
        if self is JX_ANY:
            return self
        return self.__dict__.get(item)

    def __hash__(self):
        return hash(tuple(sorted(self.__dict__.keys())))

    def leaves(self):
        if self in JX_PRIMITIVE:
            yield ".", self
        else:
            for k, v in self.__dict__.items():
                for p, t in v.leaves():
                    yield concat_field(k, p), t

    def __contains__(self, item):
        if isinstance(item, str):
            return item in self.__dict__
        if not isinstance(item, JxType):
            return False
        sd = self.__dict__
        od = item.__dict__
        for k, ov in od.items():
            sv = sd.get(k)
            if sv is ARRAY:
                continue
            if sv != ov:
                return False
        return True

    def __ne__(self, other):
        if self is JX_ANY and other is ARRAY:
            return False
        return not self == other

    def __eq__(self, other):
        if other is ARRAY and hasattr(self, ARRAY_KEY):
            # SHALLOW CHECK IF THIS IS AN ARRAY
            return True

        if not isinstance(other, JxType):
            return False

        if self is JX_INTEGER or self is JX_NUMBER:
            if other is JX_INTEGER or other is JX_NUMBER:
                return True

        # DETECT DIFFERENCE BY ONLY NAME DEPTH
        sd = base_type(self).__dict__
        od = base_type(other).__dict__

        if len(sd) != len(od):
            return False

        try:
            for k, sv in sd.items():
                ov = od.get(k)
                if sv != ov:
                    return False
            return True
        except Exception as cause:
            sd = self.__dict__
            od = other.__dict__

            # DETECT DIFFERENCE BY ONLY NAME DEPTH
            sd = base_type(sd)
            od = base_type(od)

            Log.error("not expected", cause)

    def __radd__(self, path):
        """
        RETURN self AT THE END OF path
        :param path
        """
        acc = self
        for step in reversed(split_field(path)):
            if IS_PRIMITIVE_KEY.match(step):
                continue
            acc = JxType(**{step: acc})
        return acc

    def __data__(self):
        return {k: v.__data__() if isinstance(v, JxType) else str(v) for k, v in self.__dict__.items()}

    def __str__(self):
        return str(self.__data__())

    def __repr__(self):
        return "JxType(**" + str(self.__data__()) + ")"

def array_of(type_):
    return JxType(**{ARRAY_KEY: type_})

def member_type(type_):
    """
    RETURN THE MEMBER TYPE, IF AN ARRAY
    """
    if type_ == ARRAY:
        return getattr(type_, ARRAY_KEY)
    else:
        return type_

def base_type(type_):
    """
    TYPES OFTEN COME WITH SIMPLE NAMES THAT GET IN THE WAY OF THE "BASE TYPE"
    THIS WILL STRIP EXTRANEOUS NAMES, RETURNING THE MOST BASIC TYPE
    EITHER A PRIMITIVE, OR A STRUCTURE

    USE THIS WHEN MANIPULATING FUNCTIONS THAT ACT ON VALUES, NOT STRUCTURES
    EXAMPLE: {"a": {"~n~": number}} REPRESENTS BOTH A STRUCTURE {"a": 1} AND A NUMBER
    """
    d = type_.__dict__
    ld = len(d)
    while ld == 1:
        n, t = first(d.items())
        if IS_PRIMITIVE_KEY.match(n):
            return type_
        if t in (ARRAY, JSON):
            return type_
        type_ = t
        d = t.__dict__
        ld = len(d)
    return type_

def union_type(*types):
    if len(types) == 1 and is_many(types[0]):
        Log.error("expecting many parameters")
    output = JX_IS_NULL

    for t in types:
        output |= t
    return output

def array_type(item_type):
    return _primitive(ARRAY_KEY, item_type)

_new = object.__new__

def _primitive(name, value):
    output = _new(JxType)
    setattr(output, name, value)
    return output

IS_NULL = "0"
BOOLEAN = "boolean"
INTEGER = "integer"
NUMBER = "number"
TIME = "time"
INTERVAL = "interval"
STRING = "string"
OBJECT = "object"
ARRAY = "nested"
EXISTS = "exists"
JSON = "any json"

ALL_TYPES = {
    IS_NULL: IS_NULL,
    BOOLEAN: BOOLEAN,
    INTEGER: INTEGER,
    NUMBER: NUMBER,
    TIME: TIME,
    INTERVAL: INTERVAL,
    STRING: STRING,
    OBJECT: OBJECT,
    ARRAY: ARRAY,
    EXISTS: EXISTS,
}
JSON_TYPES = (BOOLEAN, INTEGER, NUMBER, STRING, OBJECT)
NUMBER_TYPES = (INTEGER, NUMBER, TIME, INTERVAL)
PRIMITIVE = (EXISTS, BOOLEAN, INTEGER, NUMBER, TIME, INTERVAL, STRING)
INTERNAL = (EXISTS, OBJECT, ARRAY)
STRUCT = (OBJECT, ARRAY)

BOOLEAN_KEY, INTEGER_KEY, NUMBER_KEY, TIME_KEY, DURATION_KEY, STRING_KEY, ARRAY_KEY, EXISTS_KEY, JSON_KEY = "~b~", "~i~", "~n~", "~t~", "~d~", "~s~", "~a~", "~e~", "~j~"
IS_PRIMITIVE_KEY = re.compile(r"^~[bintds]~$")
IS_TYPE_KEY = re.compile(r"^~[bintdsaje]~$")

JX_IS_NULL = _new(JxType)
JX_BOOLEAN = _primitive(BOOLEAN_KEY, BOOLEAN)
JX_INTEGER = _primitive(INTEGER_KEY, INTEGER)
JX_NUMBER = _primitive(NUMBER_KEY, NUMBER)
JX_TIME = _primitive(TIME_KEY, TIME)
JX_INTERVAL = _primitive(DURATION_KEY, INTERVAL)  # d FOR DELTA
JX_TEXT = _primitive(STRING_KEY, STRING)
JX_ARRAY = _primitive(ARRAY_KEY, ARRAY)
JX_ANY = _primitive(JSON_KEY, JSON)

JX_PRIMITIVE = _new(JxType)
JX_PRIMITIVE.__dict__ = [
    (x, x.update(d))[0]
    for x in [{}]
    for d in [
        JX_BOOLEAN.__dict__,
        JX_INTEGER.__dict__,
        JX_NUMBER.__dict__,
        JX_TIME.__dict__,
        JX_INTERVAL.__dict__,
        JX_TEXT.__dict__,
    ]
][0]
JX_NUMBER_TYPES = _new(JxType)
JX_NUMBER_TYPES.__dict__ = [
    (x, x.update(d))[0]
    for x in [{}]
    for d in [JX_INTEGER.__dict__, JX_NUMBER.__dict__, JX_TIME.__dict__, JX_INTERVAL.__dict__]
][0]

_json_type_to_jx_type = {
    IS_NULL: JX_IS_NULL,
    BOOLEAN: JX_BOOLEAN,
    INTEGER: JX_INTERVAL,
    NUMBER: JX_NUMBER,
    TIME: JX_TIME,
    INTERVAL: JX_INTERVAL,
    STRING: JX_TEXT,
    ARRAY: JX_ARRAY,
}

def value_to_json_type(v):
    if v == None:
        return None
    elif isinstance(v, bool):
        return BOOLEAN
    elif isinstance(v, str):
        return STRING
    elif is_data(v):
        return OBJECT
    elif isinstance(v, float):
        if isnan(v) or abs(v) == POS_INF:
            return None
        return NUMBER
    elif isinstance(v, (int, Date)):
        return NUMBER
    elif is_sequence(v):
        return ARRAY
    return None

def value_to_jx_type(value):
    if is_many(value):
        return _primitive(ARRAY_KEY, union_type(*(value_to_json_type(v) for v in value)))
    elif is_data(value):
        return JxType(**{k: value_to_json_type(v) for k, v in value.items()})
    else:
        return _python_type_to_jx_type[value.__class__]

def python_type_to_jx_type(type):
    return _python_type_to_jx_type.get(type, JX_ANY)

_jx_type_to_json_type = {
    JX_IS_NULL: IS_NULL,
    JX_BOOLEAN: BOOLEAN,
    JX_INTEGER: NUMBER,
    JX_NUMBER: NUMBER,
    JX_TIME: NUMBER,
    JX_INTERVAL: NUMBER,
    JX_TEXT: STRING,
    JX_ARRAY: ARRAY,
    JX_ANY: OBJECT,
}

def jx_type_to_json_type(jx_type):
    return _jx_type_to_json_type.get(base_type(jx_type))

_python_type_to_jx_type = {
    int: JX_INTEGER,
    text: JX_TEXT,
    float: JX_NUMBER,
    Decimal: JX_NUMBER,
    bool: JX_BOOLEAN,
    NullType: JX_IS_NULL,
    none_type: JX_IS_NULL,
    Date: JX_TIME,
    datetime: JX_TIME,
    date: JX_TIME,
}

for k, v in items(_python_type_to_jx_type):
    _python_type_to_jx_type[k.__name__] = v

jx_type_to_key = {
    JX_IS_NULL: JSON_KEY,
    JX_BOOLEAN: BOOLEAN_KEY,
    JX_INTEGER: INTEGER_KEY,
    JX_NUMBER: NUMBER_KEY,
    JX_TIME: TIME_KEY,
    JX_INTERVAL: DURATION_KEY,
    JX_TEXT: STRING_KEY,
    JX_ARRAY: ARRAY_KEY,
}

python_type_to_jx_type_key = {
    bool: BOOLEAN_KEY,
    int: INTEGER_KEY,
    float: NUMBER_KEY,
    Decimal: NUMBER_KEY,
    Date: TIME_KEY,
    datetime: TIME_KEY,
    date: TIME_KEY,
    text: STRING_KEY,
    NullType: JSON_KEY,
    none_type: JSON_KEY,
    list: ARRAY_KEY,
    set: ARRAY_KEY,
}


import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QLineEdit, QPushButton, QDialog, QMessageBox, QVBoxLayout, QFormLayout, QDateEdit ,QComboBox
from PyQt5.QtCore import Qt, QDate, pyqtSignal, QObject
from PyQt5.QtGui import QIntValidator

class Communicate(QObject):
    form_submitted = pyqtSignal(str, str, str, str, str, str, str)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("Aplikasi Pembuatan Paspor")
        self.setGeometry(100, 100, 400, 300)

        self.central_widget = QWidget(self)
        self.setCentralWidget(self.central_widget)

        layout = QVBoxLayout(self.central_widget)
        form_layout = QFormLayout()

        self.label_name = QLabel("Nama:")
        self.lineedit_name = QLineEdit()

        self.label_address = QLabel("Alamat:")
        self.lineedit_address = QLineEdit()

        self.label_country = QLabel("Negara:")
        self.lineedit_country = QLineEdit()

        self.lineedit_gender = QLabel("Jenis Kelamin:")
        self.combo_box_gender = QComboBox(self)
        self.combo_box_gender.addItem("Laki-laki")
        self.combo_box_gender.addItem("Perempuan")

        self.label_birthdate = QLabel("Tanggal Lahir:")
        self.dateedit_birthdate = QDateEdit()
        self.dateedit_birthdate.setDisplayFormat("dd/MM/yyyy")
        self.dateedit_birthdate.setDate(QDate.currentDate())

        self.label_expired = QLabel("Expired:")
        self.dateedit_expired = QDateEdit()
        self.dateedit_expired.setDisplayFormat("dd/MM/yyyy")
        self.dateedit_expired.setDate(QDate.currentDate().addYears(10))

        self.label_registration = QLabel("Nomor Registrasi(hanya bisa di isi angka):")
        self.lineedit_registration = QLineEdit()
        self.lineedit_registration.setValidator(QIntValidator())
        form_layout.addRow(self.label_name, self.lineedit_name)
        form_layout.addRow(self.label_address, self.lineedit_address)
        form_layout.addRow(self.label_country, self.lineedit_country)
        form_layout.addRow(self.lineedit_gender,self.combo_box_gender)
        form_layout.addRow(self.label_birthdate, self.dateedit_birthdate)
        form_layout.addRow(self.label_expired, self.dateedit_expired)
        form_layout.addRow(self.label_registration, self.lineedit_registration)

        layout.addLayout(form_layout)

        self.button_submit = QPushButton("Submit")
        self.button_submit.clicked.connect(self.submit_form)
        layout.addWidget(self.button_submit)

        self.communicate = Communicate()
        self.communicate.form_submitted.connect(self.show_success_dialog)

    def submit_form(self):
        name = self.lineedit_name.text()
        address = self.lineedit_address.text()
        country = self.lineedit_country.text()
        gender =self.combo_box_gender.currentText()
        birthdate = self.dateedit_birthdate.date().toString(Qt.ISODate)
        expired = self.dateedit_expired.date().toString(Qt.ISODate)
        registration = self.lineedit_registration.text()

        if name and address and country and gender and birthdate and expired and registration:
            self.communicate.form_submitted.emit(name, address, country, gender, birthdate, expired, registration)
        else:
            QMessageBox.warning(self, "Peringatan", "Mohon isi semua kolom.")

    def show_success_dialog(self, name, address, country, gender, birthdate, expired, registration):
        dialog = QDialog(self)
        dialog.setWindowTitle("Sukses")
        dialog.setGeometry(100, 100, 400, 300)

        label_success = QLabel("Pembuatan paspor untuk {} dengan alamat {} berhasil.\n"
                               "Negara: {}\n"
                               "Jenis Kelamin: {}\n"
                               "Tanggal Lahir: {}\n"
                               "Expired: {}\n"
                               "Nomor Registrasi: {}".format(name, address, country, gender, birthdate, expired, registration))
        label_success.setAlignment(Qt.AlignLeft)
        label_success.setStyleSheet(
            """
            QLabel {
                background-image: url('background_image.jpg');
                background-repeat: no-repeat;
                background-position: center;
                color: black;
                font-size: 30px;
                padding: 20px;
            }
            """
        )

        layout = QVBoxLayout(dialog)
        layout.addWidget(label_success)

        dialog.exec_()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


import datetime
import re

from framework.packet import Packet
from framework.pmd_output import PmdOutput
from framework.test_case import TestCase
from framework.utils import convert_int2ip, convert_ip2int

ETHER_JUMBO_FRAME_MTU = 9000
DEFAULT_JUMBO_FRAME_MTU = 1500

class TestVhostPmdXstats(TestCase):
    def set_up_all(self):
        """
        Run at the start of each test suite.
        """
        self.dut_ports = self.dut.get_ports(self.nic)
        txport = self.tester.get_local_port(self.dut_ports[0])
        self.txItf = self.tester.get_interface(txport)
        self.scapy_num = 0
        self.queues = 2
        self.dmac = self.dut.get_mac_address(self.dut_ports[0])
        self.virtio1_mac = "52:54:00:00:00:01"
        self.core_config = "1S/6C/1T"
        self.ports_socket = self.dut.get_numa_id(self.dut_ports[0])
        self.cores_num = len(
            [n for n in self.dut.cores if int(n["socket"]) == self.ports_socket]
        )
        self.verify(self.cores_num >= 6, "There has not enough cores to test this case")
        self.core_list = self.dut.get_core_list(
            self.core_config, socket=self.ports_socket
        )
        self.core_list_user = self.core_list[0:3]
        self.core_list_host = self.core_list[3:6]
        self.dst_mac = self.dut.get_mac_address(self.dut_ports[0])
        self.app_testpmd_path = self.dut.apps_name["test-pmd"]
        self.testpmd_name = self.app_testpmd_path.split("/")[-1]
        self.vhost_user = self.dut.new_session(suite="vhost-user")
        self.virtio_user0 = self.dut.new_session(suite="virtio-user0")
        self.vhost_user_pmd = PmdOutput(self.dut, self.vhost_user)
        self.virtio_user0_pmd = PmdOutput(self.dut, self.virtio_user0)

    def set_up(self):
        """
        Run before each test case.
        Launch vhost sample using default params
        """
        self.dut.send_expect("rm -rf ./vhost-net*", "#")
        self.dut.send_expect("killall -s INT %s" % self.testpmd_name, "#")

    @property
    def check_2M_env(self):
        out = self.dut.send_expect(
            "cat /proc/meminfo |grep Hugepagesize|awk '{print($2)}'", "# "
        )
        return True if out == "2048" else False

    def scapy_send_packet(self, pktsize, dmac, num=1):
        """
        Send a packet to port
        """
        self.scapy_num += 1
        options = {
            "ip": {"src": "192.168.0.1", "dst": "192.168.1.1"},
            "layers_config": [],
        }
        # give a default value to ip
        try:
            src_ip_num = convert_ip2int(options["ip"]["src"])
        except:
            src_ip_num = 0
        try:
            dst_ip_num = convert_ip2int(options["ip"]["dst"])
        except:
            dst_ip_num = 0
        if num == 1:
            count = 1
            group = num
        else:
            count = 1000
            group = int(num / count)
        for _ in range(group):
            srcip = convert_int2ip(src_ip_num, ip_type=4)
            dstip = convert_int2ip(dst_ip_num, ip_type=4)
            pkt = Packet(pkt_type="IP_RAW", pkt_len=pktsize)
            pkt.config_layer("ether", {"dst": dmac})
            pkt.config_layer("ipv4", {"src": srcip, "dst": dstip})
            dst_ip_num += 1
            pkt.send_pkt(self.tester, tx_port=self.txItf, count=count)

    def send_verify(self, scope, num):
        """
        according the scope to check results
        """
        out = self.vhost_user_pmd.execute_cmd("show port xstats 1")
        rx_pattern = re.compile("rx_q\d+_%s_packets:\s*(\d+)" % scope)
        packet_rx = rx_pattern.findall(out)
        sum_packet_rx = 0
        for item in packet_rx:
            sum_packet_rx += int(item)

        tx_pattern = re.compile("tx_q\d+_%s_packets:\s*(\d+)" % scope)
        packet_tx = tx_pattern.findall(out)
        sum_packet_tx = 0
        for item in packet_tx:
            sum_packet_tx += int(item)

        self.verify(
            int(sum_packet_rx) == num, "Insufficient the received packets from nic"
        )
        self.verify(
            int(sum_packet_tx) == num, "Insufficient the received packets from virtio"
        )

    def start_vhost_testpmd(self):
        """
        start testpmd on vhost
        """
        vdevs = ["net_vhost0,iface=vhost-net,queues=%d,client=0" % self.queues]
        param = "--nb-cores=2 --rxq=2 --txq=2"
        self.vhost_user_pmd.start_testpmd(
            cores=self.core_list_host,
            param=param,
            vdevs=vdevs,
            ports=[0],
            prefix="vhost",
        )
        self.vhost_user_pmd.execute_cmd("set fwd io")
        self.vhost_user_pmd.execute_cmd("start")

    def start_virtio_testpmd(self, args):
        """
        start testpmd on virtio
        """
        eal_param = ""
        if self.check_2M_env:
            eal_param += " --single-file-segments"
        vdevs = [
            "net_virtio_user0,mac=00:01:02:03:04:05,path=./vhost-net,queues=%d,%s"
            % (self.queues, args["version"])
        ]
        param = "%s --nb-cores=2 --rxq=2 --txq=2" % args["path"]
        self.virtio_user0_pmd.start_testpmd(
            cores=self.core_list_user,
            eal_param=eal_param,
            param=param,
            vdevs=vdevs,
            no_pci=True,
            prefix="virtio",
        )
        self.virtio_user0_pmd.execute_cmd("set fwd io")
        self.virtio_user0_pmd.execute_cmd("start")

    def xstats_number_and_type_verify(self):
        """
        Verify receiving and transmitting packets correctly in the Vhost PMD xstats
        """
        out = self.vhost_user_pmd.execute_cmd("show port xstats 1")
        p = re.compile(r"rx_q0_size_[0-9]+_[\w+]*packets")
        categories = p.findall(out)
        categories = categories[:-1]
        self.verify(
            len(categories) > 0, "Unable to find the categories of RX packet size!"
        )
        for cat in categories:
            scope = re.search(r"(?<=rx_)\w+(?=_packets)", cat).group(0)
            pktsize = int(re.search(r"(?<=rx_q0_size_)\d+", cat).group(0))
            if pktsize > 1518:
                self.tester.send_expect(
                    "ifconfig %s mtu %d" % (self.txItf, ETHER_JUMBO_FRAME_MTU), "# "
                )
            types = ["ff:ff:ff:ff:ff:ff", "01:00:00:33:00:01"]
            for p in types:
                if p == "ff:ff:ff:ff:ff:ff":
                    scope = "broadcast"
                    self.dmac = "ff:ff:ff:ff:ff:ff"
                elif p == "01:00:00:33:00:01":
                    scope = "multicast"
                    self.dmac = "01:00:00:33:00:01"
                self.scapy_send_packet(int(pktsize + 4), self.dmac, 10000)
                self.send_verify(scope, 10000)
                self.clear_port_xstats(scope)
            self.tester.send_expect(
                "ifconfig %s mtu %d" % (self.txItf, DEFAULT_JUMBO_FRAME_MTU), "# "
            )

    def test_vhost_xstats_split_ring_inorder_mergeable_path(self):
        """
        Test Case 1: Vhost pmd xstats stability test with split ring inorder mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=1,mrg_rxbuf=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_split_ring_inorder_no_mergeable_path(self):
        """
        Test Case 2: Vhost pmd xstats test with split ring inorder non-mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=1,mrg_rxbuf=0",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_split_ring_mergeable_path(self):
        """
        Test Case 3: Vhost pmd xstats test with split ring mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=0,mrg_rxbuf=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_split_ring_no_mergeable_path(self):
        """
        Test Case 4: Vhost pmd xstats test with split ring non-mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=0,mrg_rxbuf=0,vectorized=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_split_ring_vector_rx_path(self):
        """
        Test Case 5: Vhost pmd xstats test with split ring vector_rx path
        """
        virtio_pmd_arg = {
            "version": "in_order=0,mrg_rxbuf=0,vectorized=1",
            "path": "--tx-offloads=0x0",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_packed_ring_inorder_mergeable_path(self):
        """
        Test Case 6: Vhost pmd xstats test with packed ring inorder mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=1,mrg_rxbuf=1,packed_vq=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_packed_ring_inorder_no_mergeable_path(self):
        """
        Test Case 7: Vhost pmd xstats test with packed ring inorder non-mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=1,mrg_rxbuf=0,vectorized=1,packed_vq=1",
            "path": "--rx-offloads=0x10 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_packed_ring_mergeable_path(self):
        """
        Test Case 8: Vhost pmd xstats test with packed ring mergeable path
        """
        self.scapy_num = 0
        virtio_pmd_arg = {
            "version": "in_order=0,mrg_rxbuf=1,packed_vq=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        # stability test with basic packets number check
        self.scapy_num = 0
        date_old = datetime.datetime.now()
        date_new = date_old + datetime.timedelta(minutes=2)
        while 1:
            date_now = datetime.datetime.now()
            scope = "multicast"
            self.dmac = "01:00:00:33:00:01"
            self.scapy_send_packet(64, self.dmac, 1)
            if date_now >= date_new:
                break
        self.send_verify(scope, self.scapy_num)
        self.close_all_testpmd()

    def test_vhost_xstats_packed_ring_no_mergeable_path(self):
        """
        Test Case 9: Vhost pmd xstats test with packed ring non-mergeable path
        """
        virtio_pmd_arg = {
            "version": "in_order=0,mrg_rxbuf=0,packed_vq=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        self.close_all_testpmd()

    def test_vhost_xstats_packed_ring_vectorized_path(self):
        """
        Test Case 10: Vhost pmd xstats test with packed ring vectorized path
        """
        virtio_pmd_arg = {
            "version": "in_order=1,mrg_rxbuf=0,vectorized=1,packed_vq=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        # stability test with basic packets number check
        self.scapy_num = 0
        date_old = datetime.datetime.now()
        date_new = date_old + datetime.timedelta(minutes=2)
        while 1:
            date_now = datetime.datetime.now()
            scope = "broadcast"
            self.dmac = "ff:ff:ff:ff:ff:ff"
            self.scapy_send_packet(64, self.dmac, 1)
            if date_now >= date_new:
                break
        self.send_verify(scope, self.scapy_num)
        self.close_all_testpmd()

    def test_vhost_xstats_packed_ring_vectorized_path_ringsize_not_powerof_2(self):
        """
        Test Case 11: Vhost pmd xstats test with packed ring vectorized path with ring size is not power of 2
        """
        virtio_pmd_arg = {
            "version": "in_order=1,mrg_rxbuf=0,vectorized=1,queue_size=1221,packed_vq=1",
            "path": "--tx-offloads=0x0 --enable-hw-vlan-strip --rss-ip --rxd=1221 --txd=1221",
        }
        self.start_vhost_testpmd()
        self.start_virtio_testpmd(virtio_pmd_arg)
        self.xstats_number_and_type_verify()
        # stability test with basic packets number check
        self.scapy_num = 0
        date_old = datetime.datetime.now()
        date_new = date_old + datetime.timedelta(minutes=2)
        while 1:
            date_now = datetime.datetime.now()
            scope = "broadcast"
            self.dmac = "ff:ff:ff:ff:ff:ff"
            self.scapy_send_packet(64, self.dmac, 1)
            if date_now >= date_new:
                break
        self.send_verify(scope, self.scapy_num)
        self.close_all_testpmd()

    def close_all_testpmd(self):
        """
        close all testpmd of vhost and virtio
        """
        self.vhost_user_pmd.quit()
        self.virtio_user0_pmd.quit()

    def clear_port_xstats(self, scope):

        self.vhost_user_pmd.execute_cmd("clear port xstats 1")
        out = self.vhost_user_pmd.execute_cmd("show port xstats 1")
        rx_pattern = re.compile("rx_q\d+_%s_packets:\s*(\d+)" % scope)
        rx_packet_list = rx_pattern.findall(out)
        for rx_packet in rx_packet_list:
            self.verify(int(rx_packet) == 0, "Insufficient the received package")

    def tear_down(self):
        """
        Run after each test case.
        """
        self.dut.send_expect("killall -s INT %s" % self.testpmd_name, "#")

    def tear_down_all(self):
        """
        Run after each test suite.
        """
        self.dut.close_session(self.vhost_user)
        self.dut.close_session(self.virtio_user0)


from django.shortcuts import render, redirect
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.views.generic import View, ListView, DetailView, CreateView, UpdateView, DeleteView
from .models import Document, Useful
from .forms import DocumentForm
from django.http import HttpResponseRedirect
from django.utils import timezone
from django.urls import reverse
from django.db.models import Q
# Create your views here.
User = get_user_model

class DocumentList(ListView):
    model = Document
    template_name = 'studymaterial/document_list.html'
    context_object_name = 'documents'
    paginate_by = 10

    def get_queryset(self):
        category = self.request.GET.get('category')
        q        = self.request.GET.get('q')

        if category == None:
            category = 'ALL'

        if category != 'ALL' and q:
            return Document.objects.filter( Q(name__icontains=q) | Q(uploaded_by__username__icontains=q) | Q(description__icontains=q), uploaded_at__lte=timezone.now(), category = category).order_by('-uploaded_at')
        elif category != 'ALL':
            return Document.objects.filter(uploaded_at__lte=timezone.now(), category = category).order_by('-uploaded_at')
        elif q:
            return Document.objects.filter( Q(name__icontains=q) | Q(uploaded_by__username__icontains=q) | Q(description__icontains=q), uploaded_at__lte=timezone.now()).order_by('-uploaded_at')
        else:
            return Document.objects.filter(uploaded_at__lte=timezone.now()).order_by('-uploaded_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Document.CATEGORY
        return context
@login_required
def upload_document(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            doc = form.save(commit=False)
            doc.uploaded_by = request.user
            doc.save()
            # Always return an HttpResponseRedirect after successfully dealing
            # with POST data. This prevents data from being posted twice if a
            # user hits the Back button.
            return HttpResponseRedirect(reverse('studymaterial:document_list'))
    else:
        form = DocumentForm()
    return render(request, 'studymaterial/upload_form.html', {'form':form})

@login_required
def found_useful(request, slug):
    document = Document.objects.get(slug=slug)
    useful_object, created = Useful.objects.get_or_create(person=request.user, document=document)
    return redirect('studymaterial:document_list')

@login_required
def unlike(request, slug):
    document = Document.objects.get(slug=slug)
    Useful.objects.filter(document=document, person=request.user).delete()
    return redirect('studymaterial:document_list')


import os
import sys
import requests
from types import NoneType
from pprint import pprint
import time
from datetime import datetime
from PIL import Image
from io import BytesIO
from spotipy.oauth2 import SpotifyClientCredentials
from spotipy.oauth2 import SpotifyOAuth
import spotipy
from pixoo import Channel, ImageResampleMode, Pixoo

#Change variables below (ipAdd, clID, clSEC, rURI)

ipAdd = 'PIXOO64-IP-ADDRESS'
clID = "SPOTIFY-CLIENT-ID"
clSEC = "SPOTIFY-CLIENT-SECRET"
rURI = "SPOTIFY-CLIENT-URI"
scope = "user-read-playback-state"

pixoo = Pixoo(ipAdd, 64, False)

def getCurrTrkImg():
    sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=clID, client_secret=clSEC, redirect_uri=rURI, scope=scope))
    playTr = sp.current_playback()

    imgURL = playTr["item"]["album"]["images"][2]["url"]
    response = requests.get(imgURL)
    img = Image.open(BytesIO(response.content))

    return img

def checkPlay():
    sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=clID, client_secret=clSEC, redirect_uri=rURI, scope=scope))
    playTr = sp.current_playback()

    if playTr is None:
        isPlaying = False
    else:
        isPlaying = True

    return isPlaying

def checkPod():
    sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=clID, client_secret=clSEC, redirect_uri=rURI, scope=scope))
    playTr = sp.current_playback()

    checkPodPlay = playTr["currently_playing_type"]

    if checkPodPlay == "episode":
        isPod = True
    else:
        isPod = False

    return isPod

def showTime():
    pixoo.draw_filled_rectangle((44, 56), (62, 62), (51, 51, 51))
    pixoo.draw_pixel((53, 58), (255, 255, 255))
    pixoo.draw_pixel((53, 60), (255, 255, 255))

    now = datetime.today()
    currtimeh = now.strftime("%I")
    currtimem = now.strftime("%M")
    pixoo.draw_text(currtimeh, (45, 57), (255, 255, 255))
    pixoo.draw_text(currtimem, (55, 57), (255, 255, 255))

def main():
    fallbackImg = "NotPlaying.png"
    podcastImg = "Podcast.png"

    while True:
        if checkPlay() is False:
            pixoo.draw_image(fallbackImg)

            showTime()

            pixoo.push()
        else:
            if checkPod() is True:
                fallbackImg = podcastImg
                pixoo.draw_image(podcastImg)

                showTime()

                pixoo.push()
            else:
                fallbackImg = getCurrTrkImg()
                pixoo.draw_image(getCurrTrkImg())

                showTime()

                pixoo.push()

        time.sleep(2)

if __name__ == '__main__':
    main()


from unicodedata import normalize

from bs4 import BeautifulSoup
import requests
from FFDao.Dao import Dao
from FFDao import core, core_insert

bd = Dao
core = core_insert

#global url_player2

def scrapperPlayers():
	i = 1
	url = 'https://footystats.org/brazil/serie-a'
	url2 = 'https://footystats.org'

	url_player = []
	url_player2 = []

	r = requests.get(url)
	soup =  BeautifulSoup(r.text, 'lxml')

	lista_nome = soup.find_all('td', class_='team borderRightContent')
	for lista_url in lista_nome:
		if lista_url.next_element.name == 'a':
			url_player.append('{0}{1}'.format(url2, lista_url.next_element.get('href')))

	for url_time in url_player:
		url_player2 = []
		r = requests.get(url_time)
		soup =  BeautifulSoup(r.text, 'lxml')

		#PEGA A URL DOS JOGADORES DOS TIMES
		lista_player = soup.find_all('p', class_='col-lg-6 ellipses')

		for lista_url in lista_player:
			url_player2.append('{0}{1}'.format(url2, lista_url.next_element.get('href')))
			#print(('{0}{1}'.format(url2, lista_url.next_element.get('href'))))

		for url_player2 in url_player2:
				r = requests.get(url_player2)
				soup =  BeautifulSoup(r.text, 'lxml')

				#PEGAR INFO DO JOGADOR
				info_p = []
				#player_info = soup.find_all('div', class_='row cf lightGrayBorderBottom ')
				player_info = soup.find_all('p', class_='col-lg-7 lh14e')
				for p_info in player_info:
					info_p.append(p_info.text)

				#TRATAR O NOME
				p_name = info_p[0]

				#TRATAR PARA USAR O NOME COMO URL
				p_url = p_name.lower()
				p_url = p_url.replace(" ","-")
				p_url = normalize('NFKD', p_url).encode('ASCII', 'ignore').decode('ASCII')

				#PAIS DE ORIGEM
				p_origem = info_p[1]

				#POSICAO DO JOGADOR
				p_position = info_p[2]

				#IDADE DO JOGADOR
				p_age = info_p[3]

				player_club = soup.find('span', class_='fa-adjust-h3')
				p_club = player_club.text
				p_club = p_club[0:len(p_club)-6]

				stats_p = []
				#RETIRA AS STATS DO JOGADOR
				player_stats = soup.find('div', class_='w100 cf player_season_row')
				player_stats = player_stats.find_all('p', class_='mild-small')
				for p_stats in player_stats:
					stats_p.append(p_stats)

				p_matches_played = stats_p[0].text
				p_gols           = stats_p[1].text
				p_assistence     = stats_p[2].text
				p_yellow_card    = stats_p[3].text
				p_red_card		 = stats_p[4].text
				p_penaulti       = stats_p[5].text
				p_played_time    = stats_p[6].text.replace("'","")

				#GRAVA JOGADOR NO BANCO
				bd.add_Player("", p_name, p_club, p_position, p_origem, p_matches_played,  p_gols, p_assistence, p_yellow_card, p_red_card, p_penaulti, p_played_time)
				print(i,"Adicionado ", p_name, " com Sucesso no time:", p_club)
				i = i+1

def scrapperClub():

	url_clubs = []
	url2 = "https://footystats.org"

	#CRIAR OS CLUBES NO
	#for arrayClub in arrayClub:
	#	bd.add_club("", arrayClub)

	url = "https://footystats.org/brazil/serie-a"
	r = requests.get(url)
	soup =  BeautifulSoup(r.text, 'lxml')

	#ENCONTRAR AS URLS DOS TIMES
	lista_nome =  soup.find_all('td', class_='team borderRightContent')
	for lista_url in lista_nome:
		if lista_url.next_element.name == 'a':
			url_clubs.append('{0}{1}'.format(url2, lista_url.next_element.get('href')))

	#PERCORRE AS URLS DOS CLUBES PARA PEGAR OS DADOS
	for url_clubs in url_clubs:
		r = requests.get(url_clubs)
		soup =  BeautifulSoup(r.text, 'lxml')

		#PEGAR NOME DO CLUBE
		even = soup.find('h1', class_='teamName')
		even = even.text.split("-")
		even2 = even[0].lower()
		valor = len(even2)
		even2 = even2[0:valor -1]
		club_name = even2[1:len(even2)]

		#PEGANDO NUMERO DE VITORIAS DENTRO E FORA
		even = soup.find_all('td', class_='w')
		i = 0;
		for vitorias in even:
			if (i == 0):
				club_n_win    = vitorias.text
				i = i+1
			elif (i == 1):
				club_n_win_in = vitorias.text

		#PEGANDO NUMERO DE DERROTAS DENTRO E FORA
		even = soup.find_all('td', class_='d')
		i = 0;
		for derrotas in even:
			if (i == 0):
				club_n_defeat    = derrotas.text
				i = i+1
			elif (i == 1):
				club_n_defeat_in = derrotas.text

		#PEGANDO NUMERO DE EMPATES DENTRO E FORA
		even = soup.find_all('td', class_='l')
		i = 0;
		for empates in even:
			if (i == 0):
				club_n_tie    = empates.text
				i = i+1
			elif (i == 1):
				club_n_tie_in = empates.text

		#PEGAR OS UTLIMOS JOGOS E OS PROXIMOS

		#***** VEERIFICAR GRAVACAO NO BANCO********"
		club_games = []

		time_in = soup.find_all('div', class_='homeTeamInfo')
		time_out = soup.find_all('div', class_='awayTeamInfo')
		date = soup.find_all('span', class_='monthAndDay')

		for i, val in enumerate(time_in):
			club_games.append(date[i].text)
			club_games.append(time_in[i].text)
			club_games.append(time_out[i].text)

		#CRIAR A URL COM O EMBLEMA DO CLUBE
		nome = club_name.replace(" ","-")
		nome = normalize('NFKD', nome).encode('ASCII', 'ignore').decode('ASCII')
		nome = nome[0:len(nome)]
		club_emblem = "/static/emblem/" + nome + ".png"
		#print(club_emblem)

		#VARIAVEL DE NACIONLIDADE DO CLUBE
		club_country = "Brasil"

		#ADICIONA NO BANCO DE DADOS O CLUBE
		bd.add_club("", club_name, club_n_win, club_n_defeat, club_n_tie, club_emblem, club_country, club_n_win_in, club_n_defeat_in, club_n_tie_in)
		print("Adicionado ", club_name, " Vitorias: ", club_n_win, " Derrotas: ",  club_n_defeat, " Empates: ", club_n_tie, " Emblema: ",club_emblem, " Pais: ",club_country, "Vitoria Dentro :",  club_n_win_in)

def search(busca):
	valor = []
	s_search = []

	j  = busca.split(" ")

	for i in j:
		s_search.append(i)

	all_player = bd.consultar_all_Players("")

	for player in all_player:
		even = player[1].split(" ")
		for i in even:
			if busca == i:
				valor.append(even)
				pass

	print(valor)
	return valor

def scrapperPlayers2():

		aux = "https://www.academiadasapostasbrasil.com/stats/person/brasil/"
		arr =  []
		arr2 = []
		url_player = []
		jogadores = ["diego-alves/8905", "/sidao/112354", "keiller/446980","lucas-franca/431776",  "fabio-santos/8968", "mayke/268729","marcelo-grohe/9187","corinthians/320",
					 "cassio/17304", "fernando-prass/16938","agenor/64369",  "gilberto/187555", "jefferson/4802", "douglas-pires/191016", "rafael-thyere/286196", "joao-paulo/317934",
					 "pedro-botelho/9116", "giovanni/115289","mansur/185489", "otavio/328063",  "tiago-alves/80072"]

		#ENCONTRA AS URLS DOS JOGADORES COM BASE EM UM DELES:
		for j in jogadores:
			url = aux + j
			print(url)
			#url = aux + "/norberto-neto/163583"
			r = requests.get(url)
			soup =  BeautifulSoup(r.text, 'lxml')

			#PEGA VALORES DA LINHA EVEN
			players =  soup.find_all('tr', class_='even')

			for p in players:
				arr.append(p.find('a'))

			for i in arr:
				if i is None:
					pass
				else:
					arr2.append(i.get('href'))

			for j in arr2:
				if j.find('person') == -1:
				 	pass
				else:
				 	url_player.append(j)

			#PEGA VALORES DA LINHA ODD
			players =  soup.find_all('tr', class_='odd')
			for p in players:
				arr.append(p.find('a'))

			for i in arr:
				if i is None:
					pass
				else:
					arr2.append(i.get('href'))

			for j in arr2:
				if j.find('person') == -1:
				 	pass
				else:
				 	url_player.append(j)

			for url in url_player:

				#PEGA DADOS DE JOGO DO JOGADORES:
			    #url = "https://www.academiadasapostasbrasil.com/stats/person/brasil/norberto-neto/163583"
				r = requests.get(url)
				soup =  BeautifulSoup(r.text, 'lxml')

				players =  soup.find_all('tr', class_='stats-player-odd')

				p_stats = []
				odd  = []

				#PEGA VALORES DA LINHA EVEN
				players =  soup.find_all('tr', class_='even')
				for i, val in enumerate(players):
					p = players[i].find_all('td')
					for row in p:
						p_stats.append(row.text.replace("\n", "").replace("  ", "").replace("\r", ""))

				#PEGA VALORES DA LINHA ODD
				players =  soup.find_all('tr', class_='odd')
				for i, val in enumerate(players):
					p = players[i].find_all('td')
					for row in p:
						p_stats.append(row.text.replace("\n", "").replace("  ", "").replace("\r", ""))

				#PEGA NOME E ATRIBUTOS DO JOGADOR:
				name =  soup.find_all('h2', class_='boxed-header')
				p_name = name[0].text.replace("\n", "").replace("  ", "")

				position = soup.find_all('img', class_='player_pos_img')
				p_position = position[0].get('title')

				#PEGA DADOS GERAIS
				info =  soup.find_all('tr', class_='stats-player-odd')
				p_info = []
				for i, val in enumerate(info):
					p = info[i].find_all('td')
					for row in p:
						p_info.append(row.text.replace("\n", "").replace("  ", ""))

				info =  soup.find_all('tr', class_='stats-player-even')
				for i, val in enumerate(info):
					p = info[i].find_all('td')
					for row in p:
						p_info.append(row.text.replace("\n", "").replace("  ", ""))

				#TRATAMENTO DOS DADOS RECEBIDOS
				p_info.pop(0)
				p_info.pop(1)
				p_info.pop(1)
				p_info.pop(1)
				p_info.pop(2)
				p_info.pop(3)
				p_info.pop(4)
				p_info.pop(5)
				p_info.pop(6)

				p_photo = "/static/photo/default.png"

				if p_position is "coach":
					pass
				else:
					core.insert_Player(p_name, p_info[0], p_info[5], p_photo, p_info[4], p_position, p_stats[1], p_stats[4], p_stats[9], 0, p_stats[11], p_stats[13], p_stats[12],
		                  p_stats[3], p_stats[5], p_stats[8])
					print("Jogador " + p_name + " adicionado com sucesso no:" + p_stats[1])

if __name__ == '__main__':
    #scrapperPlayers()
    #scrapperClub()
    scrapperPlayers2()
	#print(bd.consultar_all_Club(""))
	#print(bd.consultar_all_Players(""))
	#search("Jose Henrique")


from __future__ import print_function
from test_route_base import OrloHttpTest

__author__ = 'alforbes'

class TestInternalRoute(OrloHttpTest):
    def test_version(self):
        """
        Test /version returns 200
        """
        response = self.client.get('/internal/version')
        self.assert200(response)
        self.assertIn('version', response.json)


#String project
#January 4th, 2021
#Note: code organized chronologically (in order of project directions/steps)

daily_sales = \
"""Edith Mcbride   ;,;$1.21   ;,;   white ;,;
09/15/17   ,Herbert Tran   ;,;   $7.29;,;
white&blue;,;   09/15/17 ,Paul Clarke ;,;$12.52
;,;   white&blue ;,; 09/15/17 ,Lucille Caldwell
;,;   $5.13   ;,; white   ;,; 09/15/17,
Eduardo George   ;,;$20.39;,; white&yellow
;,;09/15/17   ,   Danny Mclaughlin;,;$30.82;,;
purple ;,;09/15/17 ,Stacy Vargas;,; $1.85   ;,;
purple&yellow ;,;09/15/17,   Shaun Brock;,;
$17.98;,;purple&yellow ;,; 09/15/17 ,
Erick Harper ;,;$17.41;,; blue ;,; 09/15/17,
Michelle Howell ;,;$28.59;,; blue;,;   09/15/17   ,
Carroll Boyd;,; $14.51;,;   purple&blue   ;,;
09/15/17   , Teresa Carter   ;,; $19.64 ;,;
white;,;09/15/17   ,   Jacob Kennedy ;,; $11.40
;,; white&red   ;,; 09/15/17, Craig Chambers;,;
$8.79 ;,; white&blue&red   ;,;09/15/17   , Peggy Bell;,; $8.65 ;,;blue   ;,; 09/15/17,   Kenneth Cunningham ;,;   $10.53;,;   green&blue   ;,;
09/15/17   ,   Marvin Morgan;,;   $16.49;,;
green&blue&red   ;,;   09/15/17 ,Marjorie Russell
;,; $6.55 ;,;   green&blue&red;,;   09/15/17 ,
Israel Cummings;,;   $11.86   ;,;black;,;
09/15/17,   June Doyle   ;,;   $22.29 ;,;
black&yellow ;,;09/15/17 , Jaime Buchanan   ;,;
$8.35;,;   white&black&yellow   ;,;   09/15/17,
Rhonda Farmer;,;$2.91 ;,;   white&black&yellow
;,;09/15/17, Darren Mckenzie ;,;$22.94;,;green
;,;09/15/17,Rufus Malone;,;$4.70   ;,; green&yellow
;,; 09/15/17   ,Hubert Miles;,;   $3.59
;,;green&yellow&blue;,;   09/15/17   , Joseph Bridges  ;,;$5.66   ;,; green&yellow&purple&blue
;,;   09/15/17 , Sergio Murphy   ;,;$17.51   ;,;
black   ;,;   09/15/17 , Audrey Ferguson ;,;
$5.54;,;black&blue   ;,;09/15/17 ,Edna Williams ;,;
$17.13;,; black&blue;,;   09/15/17,   Randy Fleming;,;   $21.13 ;,;black ;,;09/15/17 ,Elisa Hart;,; $0.35   ;,; black&purple;,;   09/15/17   ,
Ernesto Hunt ;,; $13.91   ;,;   black&purple ;,;
09/15/17,   Shannon Chavez   ;,;$19.26   ;,;
yellow;,; 09/15/17   , Sammy Cain;,; $5.45;,;
yellow&red ;,;09/15/17 ,   Steven Reeves ;,;$5.50
;,;   yellow;,;   09/15/17, Ruben Jones   ;,;
$14.56 ;,;   yellow&blue;,;09/15/17 , Essie Hansen;,;   $7.33   ;,;   yellow&blue&red
;,; 09/15/17   ,   Rene Hardy   ;,; $20.22   ;,;
black ;,;   09/15/17 ,   Lucy Snyder   ;,; $8.67
;,;black&red  ;,; 09/15/17 ,Dallas Obrien ;,;
$8.31;,;   black&red ;,;   09/15/17,   Stacey Payne
;,;   $15.70   ;,;   white&black&red ;,;09/15/17
,   Tanya Cox   ;,;   $6.74   ;,;yellow   ;,;
09/15/17 , Melody Moran ;,;   $30.84
;,;yellow&black;,;   09/15/17 , Louise Becker   ;,;
$12.31 ;,; green&yellow&black;,;   09/15/17 ,
Ryan Webster;,;$2.94 ;,; yellow ;,; 09/15/17
,Justin Blake ;,; $22.46   ;,;white&yellow ;,;
09/15/17,   Beverly Baldwin ;,;   $6.60;,;
white&yellow&black ;,;09/15/17   ,   Dale Brady
;,;   $6.27 ;,; yellow   ;,;09/15/17 ,Guadalupe Potter ;,;$21.12   ;,; yellow;,; 09/15/17   ,
Desiree Butler ;,;$2.10   ;,;white;,; 09/15/17
,Sonja Barnett ;,; $14.22 ;,;white&black;,;
09/15/17, Angelica Garza;,;$11.60;,;white&black
;,;   09/15/17   ,   Jamie Welch   ;,; $25.27   ;,;
white&black&red ;,;09/15/17   ,   Rex Hudson
;,;$8.26;,;   purple;,; 09/15/17 ,   Nadine Gibbs
;,;   $30.80 ;,;   purple&yellow   ;,; 09/15/17   ,
Hannah Pratt;,;   $22.61   ;,;   purple&yellow
;,;09/15/17,Gayle Richards;,;$22.19 ;,;
green&purple&yellow ;,;09/15/17   ,Stanley Holland
;,; $7.47   ;,; red ;,; 09/15/17 , Anna Dean;,;$5.49 ;,; yellow&red ;,;   09/15/17   ,
Terrance Saunders ;,;   $23.70  ;,;green&yellow&red
;,; 09/15/17 ,   Brandi Zimmerman ;,; $26.66 ;,;
red   ;,;09/15/17 ,Guadalupe Freeman ;,; $25.95;,;
green&red ;,;   09/15/17   ,Irving Patterson
;,;$19.55 ;,; green&white&red ;,;   09/15/17 ,Karl Ross;,;   $15.68;,;   white ;,;   09/15/17 , Brandy Cortez ;,;$23.57;,;   white&red   ;,;09/15/17,
Mamie Riley   ;,;$29.32;,; purple;,;09/15/17 ,Mike Thornton   ;,; $26.44 ;,;   purple   ;,; 09/15/17,
Jamie Vaughn   ;,; $17.24;,;green ;,; 09/15/17   ,
Noah Day ;,;   $8.49   ;,;green   ;,;09/15/17
,Josephine Keller ;,;$13.10 ;,;green;,;   09/15/17 ,   Tracey Wolfe;,;$20.39 ;,; red   ;,; 09/15/17 ,
Ignacio Parks;,;$14.70   ;,; white&red ;,;09/15/17
, Beatrice Newman ;,;$22.45   ;,;white&purple&red
;,;   09/15/17, Andre Norris   ;,;   $28.46   ;,;
red;,;   09/15/17 ,   Albert Lewis ;,; $23.89;,;
black&red;,; 09/15/17,   Javier Bailey   ;,;
$24.49   ;,; black&red ;,; 09/15/17   , Everett Lyons ;,;$1.81;,;   black&red ;,; 09/15/17 ,
Abraham Maxwell;,; $6.81   ;,;green;,;   09/15/17
,   Traci Craig ;,;$0.65;,; green&yellow;,;
09/15/17 , Jeffrey Jenkins   ;,;$26.45;,;
green&yellow&blue   ;,;   09/15/17,   Merle Wilson
;,;   $7.69 ;,; purple;,; 09/15/17,Janis Franklin
;,;$8.74   ;,; purple&black   ;,;09/15/17 ,
Leonard Guerrero ;,;   $1.86   ;,;yellow
;,;09/15/17,Lana Sanchez;,;$14.75   ;,; yellow;,;
09/15/17   ,Donna Ball ;,; $28.10  ;,;
yellow&blue;,;   09/15/17   , Terrell Barber   ;,;
$9.91   ;,; green ;,;09/15/17   ,Jody Flores;,;
$16.34 ;,; green ;,;   09/15/17,   Daryl Herrera
;,;$27.57;,; white;,;   09/15/17   , Miguel Mcguire;,;$5.25;,; white&blue   ;,;   09/15/17 ,
Rogelio Gonzalez;,; $9.51;,;   white&black&blue
;,;   09/15/17   ,   Lora Hammond ;,;$20.56 ;,;
green;,;   09/15/17,Owen Ward;,; $21.64   ;,;
green&yellow;,;09/15/17,Malcolm Morales ;,;
$24.99   ;,;   green&yellow&black;,; 09/15/17 ,
Eric Mcdaniel ;,;$29.70;,; green ;,; 09/15/17
,Madeline Estrada;,;   $15.52;,;green;,;   09/15/17
, Leticia Manning;,;$15.70 ;,; green&purple;,;
09/15/17 ,   Mario Wallace ;,; $12.36 ;,;green ;,;
09/15/17,Lewis Glover;,;   $13.66   ;,;
green&white;,;09/15/17,   Gail Phelps   ;,;$30.52
;,; green&white&blue   ;,; 09/15/17 , Myrtle Morris
;,;   $22.66   ;,; green&white&blue;,;09/15/17"""

#------------------------------------------------
# Start coding below!

#First step: removing ;,; as the individual transaction delimiter and replacing it with a "|"
daily_sales_replaced = daily_sales.replace(";,;","|")
#print(daily_sales_replaced)

#now we can split the string by individual transaction (using a comma since we fixed the possible issue above)
daily_transactions = daily_sales_replaced.split(",")
#print(daily_transactions)

daily_transactions_split = []

#splitting transaction list by pipe delimiter
for each in daily_transactions:
  daily_transactions_split.append(each.split("|"))

#print(daily_transactions_split)

transactions_clean = []

#removing unecessary white space from transaction list
for each in daily_transactions_split:
  for eachVar in each:
    transactions_clean.append(eachVar.strip())

#print(transactions_clean)

#delaring empty lists to be populated in for loop below
customers = []
sales  = []
thread_sold = []

#used to grab correct data from the list to populate the three lists above (customers, sales, thread_sold)
count = 4

#building a list that contains the details of each individual's transaction (customer name, total sale of the customer, thread colors bought, date of purchase)
for each in transactions_clean:
  if count % 4 == 0:
    customers.append(each)
  elif count % 4 == 1:
    sales.append(each)
  elif count % 4 == 2:
    thread_sold.append(each)
  count = count + 1

#print(customers)
#print(sales)
#print(thread_sold)

#to be used in the following for loop
total_sales = 0
temp = 0

#removing the "$" sign so that we are able to tabulate the total sales made for the day
for each in sales:
  temp = float(each.replace("$",""))
  total_sales = total_sales + temp

#print(total_sales)

#declaring empty lists to be populated in the following for loop
thread_sold_split = []
tempList = []

#builds a list containing all the colors that were sold in all transactions (individually)
for each in thread_sold:
  if "&" in each:
    tempList = each.split("&")
    for var in tempList:
      thread_sold_split.append(var)
  else:
    thread_sold_split.append(each)

#print(thread_sold_split)

#a function that returns the number of times an occurrence of a specified color appears in the "thread_sold_split" list
def color_count(color):
  countColor = 0
  for each in thread_sold_split:
    if each == color:
      countColor = countColor + 1
  return countColor

#prints the number of white threads sold
#print(color_count("white"))

#a list containing all the possible colors of thread that are available to buy
colors = ['red','yellow','green','white','black','blue','purple']

#a loop that iterates through the store's listing of thread colors and prints the number of each color sold that day
for each in colors:
  temp = "{} " + " " + each + " threads were sold today."
  print(temp.format(color_count(each)))


import os, sys, re, math
from math import inf, ceil, floor
from operator import itemgetter
from functools import wraps, cmp_to_key, reduce, lru_cache
from itertools import count, combinations, permutations
from collections import namedtuple, defaultdict, Counter, deque
from queue import Queue
from bisect import bisect_left, bisect_right
from copy import deepcopy
sys.setrecursionlimit(1000000)
class CustomException(Exception): pass

if os.getenv('SJDEAK'):
  sys.stdin = open(os.path.expanduser('./in.txt'))
  # sys.stdout = open(os.path.expanduser('./out.txt'), 'w')
  from icpc_util import dump_args, debug
else:
  debug = lambda *args, **kwargs: None
  dump_args = lambda func: func

if __name__ == '__main__':
  T = int(input())
  for caseIndex in range(T):
    N, G, M = list(map(int, input().split()))
    Guests = []
    for i in range(G):
      H, Direction = input().split()
      Guests.append(namedtuple('Guest', ['id', 'st', 'direction'])(i, int(H) - 1, Direction))

    consulateRecords = defaultdict(list)
    # M %= N

    for guest in Guests:
      for t in range(M + 1):
        if guest.direction == 'C':
          consulateRecords[(guest.st + t) % N].append((t, guest.id))
        else:
          consulateRecords[(guest.st - t + N) % N].append((t, guest.id))

    debug('consulateRecords:', consulateRecords)

    counter = {i: 0 for i in range(G)}
    for consulateId in consulateRecords:
      consulate = consulateRecords[consulateId]
      consulate.sort(reverse=True)
      if consulate:
        for record in consulate:
          time, guestId = record
          if time == consulate[0][0]:
            counter[guestId] += 1

    debug('counter:', counter)

    print('Case #{}:'.format(caseIndex + 1), *counter.values())


from aws_cdk import aws_lambda as lambda_
from aws_cdk import core

class DependenciesStack(core.Stack):
    def __init__(self,
                 scope: core.Construct,
                 stack_id: str,
                 *,
                 layer_code: lambda_.Code,
                 layer_name: str,
                 **kwargs):
        super().__init__(scope, stack_id, **kwargs)

        self.dependencies_layer = lambda_.LayerVersion(
            self,
            'DependenciesLayer',
            code=layer_code,
            compatible_runtimes=[lambda_.Runtime.PYTHON_3_8],
            layer_version_name=layer_name)


"""
    Breadth-first search and depth-first search.

    Author: Wenru Dong
"""

from typing import List, Optional, Generator, IO
from collections import deque

class Graph:
    """Undirected graph."""
    def __init__(self, num_vertices: int):
        self._num_vertices = num_vertices
        self._adjacency = [[] for _ in range(num_vertices)]

    def add_edge(self, s: int, t: int) -> None:
        self._adjacency[s].append(t)
        self._adjacency[t].append(s)

    def _generate_path(self, s: int, t: int, prev: List[Optional[int]]) -> Generator[str, None, None]:
        if prev[t] or s != t:
            yield from self._generate_path(s, prev[t], prev)
        yield str(t)

    def bfs(self, s: int, t: int) -> IO[str]:
        """Print out the path from Vertex s to Vertex t
        using bfs.
        """
        if s == t: return

        visited = [False] * self._num_vertices
        visited[s] = True
        q = deque()
        q.append(s)
        prev = [None] * self._num_vertices

        while q:
            v = q.popleft()
            for neighbour in self._adjacency[v]:
                if not visited[neighbour]:
                    prev[neighbour] = v
                    if neighbour == t:
                        print("->".join(self._generate_path(s, t, prev)))
                        return
                    visited[neighbour] = True
                    q.append(neighbour)

    def dfs(self, s: int, t: int) -> IO[str]:
        """Print out a path from Vertex s to Vertex t
        using dfs.
        """
        found = False
        visited = [False] * self._num_vertices
        prev = [None] * self._num_vertices

        def _dfs(from_vertex: int) -> None:
            nonlocal found
            if found: return
            visited[from_vertex] = True
            if from_vertex == t:
                found = True
                return
            for neighbour in self._adjacency[from_vertex]:
                if not visited[neighbour]:
                    prev[neighbour] = from_vertex
                    _dfs(neighbour)

        _dfs(s)
        print("->".join(self._generate_path(s, t, prev)))

if __name__ == "__main__":

    graph = Graph(8)

    graph.add_edge(0, 1)
    graph.add_edge(0, 3)
    graph.add_edge(1, 2)
    graph.add_edge(1, 4)
    graph.add_edge(2, 5)
    graph.add_edge(3, 4)
    graph.add_edge(4, 5)
    graph.add_edge(4, 6)
    graph.add_edge(5, 7)
    graph.add_edge(6, 7)

    graph.bfs(0, 7)
    graph.dfs(0, 7)


from final_project_part1 import *
import csv
station_line = {}
direct_dis = {}
path_length = {}

def add_different_value(list,v1,v2):
    # This function check if v1 and v2 are in the list, if not then add them to list.
    if not v1 in list:
        list.append(v1)
    if not v2 in list:
        list.append(v2)

with open('london_stations.csv', mode ='r')as file:
    ls_csv = csv.reader(file)
    for line in ls_csv:
        if line[0] == "id":
            continue
        direct_dis[line[0]] = (line[1],line[2],line[6])

with open("london_connections.csv", mode = 'r') as file:
    lc_csv = csv.reader(file)

    for line in lc_csv:
        if line[0] == "station1":
            continue
        if line[2] not in station_line.keys():
            station_line[line[2]] = []
        add_different_value(station_line[line[2]],line[0],line[1])
        path_length[(line[0],line[1])] = line[3]
        path_length[(line[1],line[0])] = line[3]

def h(s,d):
    return ((direct_dis[s][0] - direct_dis[d][0])**2 + (direct_dis[s][1] - direct_dis[d][1])**2)**(1/2)

def a_star(G, s, d, h):
    pred = {} #Predecessor dictionary. Isn't returned, but here for your understanding
    dist = {} #Distance dictionary
    Q = min_heap.MinHeap([])
    nodes = list(G.adj.keys())
    for node in nodes:
        Q.insert(min_heap.Element(node, float("inf")))
        dist[node] = float("inf")
    Q.decrease_key(s, h(s,d))
    while not Q.is_empty():
        current_element = Q.extract_min()
        if current_element == d:
            break
        current_node = current_element.value
        dist[current_node] = current_element.key - h[current_node]
        for neighbour in G.adj[current_node]:
            if dist[current_node] + G.w(current_node, neighbour) < dist[neighbour]:
                Q.decrease_key(neighbour, dist[current_node] + G.w(current_node, neighbour) + h(neighbour,d) )
                dist[neighbour] = dist[current_node] + G.w(current_node, neighbour)
                pred[neighbour] = current_node
    return (pred, path_from_pred(pred,s,d))

def create_london_graph():
    G = DirectedWeightedGraph()


from HITEMP_spectra import init_database, calc_stick_spectrum
from discrete_integral_transform_simple import synthesize_spectrum
import numpy as np
import matplotlib.pyplot as plt
from time import perf_counter
import sys
sys.path.append('../hapi/')
from discrete_integral_transform_hapi import synthesize_spectrum as  synthesize_spectrum2

## Download database files from https://hitran.org/hitemp/
HITEMP_path = "C:/HITEMP/"
init_database([HITEMP_path + "02_2000-2125_HITEMP2010.par",
               HITEMP_path + "02_2125-2250_HITEMP2010.par",
               HITEMP_path + "02_2250-2500_HITEMP2010.par"])

v_min = 2200.0 #cm-1
v_max = 2400.0 #cm-1
dv =     0.002 #cm-1
v_arr = np.arange(v_min,v_max,dv) #cm-1

dxG = 0.1
dxL = 0.1

T = 2000.0 #K
p =    0.1 #bar

v0i,log_wGi,log_wLi,S0i = calc_stick_spectrum(p,T)
wGi = np.exp(log_wGi)
wLi = np.exp(log_wLi)
print('{:.2f}M lines '.format(len(v0i)*1e-6))

I_arr, S_klm = synthesize_spectrum(v_arr,v0i,log_wGi,log_wLi,S0i,dxG=dxG,dxL=dxL)
I_arr2, S_klm2 = synthesize_spectrum2(v_arr,v0i,wGi,wLi,S0i,dxG=dxG,dxL=dxL)

##plt.plot(v_arr,I_arr-I_arr2,'-')
plt.plot(v_arr,I_arr,'-',lw=0.5)
##plt.plot(v_arr,I_arr2,'--')
plt.xlim(v_arr[-1],v_arr[0])
plt.axhline(0,c='k')
plt.xlabel('$\\nu$ (cm$^{-1}$)')
plt.xlim(2231.01,2228.99)
plt.ylim(-0.02,0.3)
plt.show()


import json
from config import get_config
from generators import retrieve_generator

if __name__ == "__main__":

    config = get_config()
    tasks = config['tasks']
    jobs = []

    generator = retrieve_generator('stepbystep')()

    with open('stepbystep_input.txt', 'w') as fid:
        buffer = []
        for sample in generator:
            buffer.append(sample)

            if len(buffer) == 3:
                fid.write(json.dumps(buffer))
                fid.write('\n')
                buffer.clear()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Oct 29 19:17:36 2020

@author: ljia
"""
import os
import pickle
import numpy as np
from tqdm import tqdm
import sys
from gklearn.dataset import Dataset
from gklearn.experiments import DATASET_ROOT

def get_dataset(ds_name):
	# The node/edge labels that will not be used in the computation.
#	if ds_name == 'MAO':
#		irrelevant_labels = {'node_attrs': ['x', 'y', 'z'], 'edge_labels': ['bond_stereo']}
#	if ds_name == 'Monoterpenoides':
#		irrelevant_labels = {'edge_labels': ['valence']}
#	elif ds_name == 'MUTAG':
#		irrelevant_labels = {'edge_labels': ['label_0']}
	if ds_name == 'AIDS_symb':
		irrelevant_labels = {'node_attrs': ['chem', 'charge', 'x', 'y'], 'edge_labels': ['valence']}
		ds_name = 'AIDS'
	else:
		irrelevant_labels = {}

	# Load predefined dataset.
	dataset = Dataset(ds_name, root=DATASET_ROOT)
	# Remove irrelevant labels.
	dataset.remove_labels(**irrelevant_labels)
	print('dataset size:', len(dataset.graphs))
	return dataset

def set_edit_cost_consts(ratio, node_labeled=True, edge_labeled=True, mode='uniform'):
	if mode == 'uniform':
		edit_cost_constants = [i * ratio for i in [1, 1, 1]] + [1, 1, 1]

	if not node_labeled:
		edit_cost_constants[2] = 0
	if not edge_labeled:
		edit_cost_constants[5] = 0

	return edit_cost_constants

def nested_keys_exists(element, *keys):
	'''
	Check if *keys (nested) exists in `element` (dict).
	'''
	if not isinstance(element, dict):
		raise AttributeError('keys_exists() expects dict as first argument.')
	if len(keys) == 0:
		raise AttributeError('keys_exists() expects at least two arguments, one given.')

	_element = element
	for key in keys:
		try:
			_element = _element[key]
		except KeyError:
			return False
	return True

# Check average relative error along elements in two ged matrices.
def matrices_ave_relative_error(m1, m2):
	error = 0
	base = 0
	for i in range(m1.shape[0]):
		for j in range(m1.shape[1]):
			error += np.abs(m1[i, j] - m2[i, j])
# 			base += (np.abs(m1[i, j]) + np.abs(m2[i, j]))
			base += (m1[i, j] + m2[i, j]) # Require only 25% of the time of "base += (np.abs(m1[i, j]) + np.abs(m2[i, j]))".

	base = base / 2

	return error / base

def compute_relative_error(ged_mats):

	if len(ged_mats) != 0:
		# get the smallest "correct" GED matrix.
		ged_mat_s = np.ones(ged_mats[0].shape) * np.inf
		for i in range(ged_mats[0].shape[0]):
			for j in range(ged_mats[0].shape[1]):
				ged_mat_s[i, j] = np.min([mat[i, j] for mat in ged_mats])

		# compute average error.
		errors = []
		for i, mat in enumerate(ged_mats):
			err = matrices_ave_relative_error(mat, ged_mat_s)
		#			 if not per_correct:
		#				 print('matrix # ', str(i))
		#				 pass
			errors.append(err)
	else:
		errors = [0]

	return np.mean(errors)

def parse_group_file_name(fn):
	splits_all = fn.split('.')
	key1 = splits_all[1]

	pos2 = splits_all[2].rfind('_')
#	key2 = splits_all[2][:pos2]
	val2 = splits_all[2][pos2+1:]

	pos3 = splits_all[3].rfind('_')
#	key3 = splits_all[3][:pos3]
	val3 = splits_all[3][pos3+1:] + '.' + splits_all[4]

	return key1, val2, val3

def get_all_errors(save_dir, errors):

	# Loop for each GED matrix file.
	for file in tqdm(sorted(os.listdir(save_dir)), desc='Getting errors', file=sys.stdout):
		if os.path.isfile(os.path.join(save_dir, file)) and file.startswith('ged_mats.'):
			keys = parse_group_file_name(file)

			# Check if the results is in the errors.
			if not keys[0] in errors:
				errors[keys[0]] = {}
			if not keys[1] in errors[keys[0]]:
				errors[keys[0]][keys[1]] = {}
			# Compute the error if not exist.
			if not keys[2] in errors[keys[0]][keys[1]]:
				ged_mats = np.load(os.path.join(save_dir, file))
				errors[keys[0]][keys[1]][keys[2]] = compute_relative_error(ged_mats)

	return errors

def get_relative_errors(save_dir, overwrite=False):
	"""	# Read relative errors from previous computed and saved file. Create the
	file, compute the errors, or add and save the new computed errors to the
	file if necessary.

	Parameters
	----------
	save_dir : TYPE
		DESCRIPTION.
	overwrite : TYPE, optional
		DESCRIPTION. The default is False.

	Returns
	-------
	None.
	"""
	if not overwrite:
		fn_err = save_dir + '/relative_errors.pkl'

		# If error file exists.
		if os.path.isfile(fn_err):
			with open(fn_err, 'rb') as f:
				errors = pickle.load(f)
				errors = get_all_errors(save_dir, errors)
		else:
			errors = get_all_errors(save_dir, {})

	else:
		errors = get_all_errors(save_dir, {})

	with open(fn_err, 'wb') as f:
		pickle.dump(errors, f)

	return errors

def interpolate_result(Z, method='linear'):
	values = Z.copy()
	for i in range(Z.shape[0]):
		for j in range(Z.shape[1]):
			if np.isnan(Z[i, j]):

				# Get the nearest non-nan values.
				x_neg = np.nan
				for idx, val in enumerate(Z[i, :][j::-1]):
					if not np.isnan(val):
						x_neg = val
						x_neg_off = idx
						break
				x_pos = np.nan
				for idx, val in enumerate(Z[i, :][j:]):
					if not np.isnan(val):
						x_pos = val
						x_pos_off = idx
						break

				# Interpolate.
				if not np.isnan(x_neg) and not np.isnan(x_pos):
					val_int = (x_pos_off / (x_neg_off + x_pos_off)) * (x_neg - x_pos) + x_pos
					values[i, j] = val_int
					break

				y_neg = np.nan
				for idx, val in enumerate(Z[:, j][i::-1]):
					if not np.isnan(val):
						y_neg = val
						y_neg_off = idx
						break
				y_pos = np.nan
				for idx, val in enumerate(Z[:, j][i:]):
					if not np.isnan(val):
						y_pos = val
						y_pos_off = idx
						break

				# Interpolate.
				if not np.isnan(y_neg) and not np.isnan(y_pos):
					val_int = (y_pos_off / (y_neg_off + y_neg_off)) * (y_neg - y_pos) + y_pos
					values[i, j] = val_int
					break

	return values

def set_axis_style(ax):
	ax.set_axisbelow(True)
	ax.spines['top'].set_visible(False)
	ax.spines['bottom'].set_visible(False)
	ax.spines['right'].set_visible(False)
	ax.spines['left'].set_visible(False)
	ax.xaxis.set_ticks_position('none')
	ax.yaxis.set_ticks_position('none')
	ax.tick_params(labelsize=8, color='w', pad=1, grid_color='w')
	ax.tick_params(axis='x', pad=-2)
	ax.tick_params(axis='y', labelrotation=-40, pad=-2)
#	ax.zaxis._axinfo['juggled'] = (1, 2, 0)
	ax.set_xlabel(ax.get_xlabel(), fontsize=10, labelpad=-3)
	ax.set_ylabel(ax.get_ylabel(), fontsize=10, labelpad=-2, rotation=50)
	ax.set_zlabel(ax.get_zlabel(), fontsize=10, labelpad=-2)
	ax.set_title(ax.get_title(), pad=30, fontsize=15)
	return

def dichotomous_permutation(arr, layer=0):
	import math

# 	def seperate_arr(arr, new_arr):
# 		if (length % 2) == 0:
# 			half = int(length / 2)
# 			new_arr += [arr[half - 1], arr[half]]
# 			subarr1 = [arr[i] for i in range(1, half - 1)]
# 		else:
# 			half = math.floor(length / 2)
# 			new_arr.append(arr[half])
# 			subarr1 = [arr[i] for i in range(1, half)]
# 		subarr2 = [arr[i] for i in range(half + 1, length - 1)]
# 		subarrs = [subarr1, subarr2]
# 		return subarrs

	if layer == 0:
		length = len(arr)
		if length <= 2:
			return arr

		new_arr = [arr[0], arr[-1]]
		if (length % 2) == 0:
 			half = int(length / 2)
 			new_arr += [arr[half - 1], arr[half]]
 			subarr1 = [arr[i] for i in range(1, half - 1)]
		else:
 			half = math.floor(length / 2)
 			new_arr.append(arr[half])
 			subarr1 = [arr[i] for i in range(1, half)]
		subarr2 = [arr[i] for i in range(half + 1, length - 1)]
		subarrs = [subarr1, subarr2]
# 		subarrs = seperate_arr(arr, new_arr)
		new_arr += dichotomous_permutation(subarrs, layer=layer+1)

	else:
		new_arr = []
		subarrs = []
		for a in arr:
			length = len(a)
			if length <= 2:
				new_arr += a
			else:
# 				subarrs += seperate_arr(a, new_arr)
				if (length % 2) == 0:
 					half = int(length / 2)
 					new_arr += [a[half - 1], a[half]]
 					subarr1 = [a[i] for i in range(0, half - 1)]
				else:
 					half = math.floor(length / 2)
 					new_arr.append(a[half])
 					subarr1 = [a[i] for i in range(0, half)]
				subarr2 = [a[i] for i in range(half + 1, length)]
				subarrs += [subarr1, subarr2]

		if len(subarrs) > 0:
			new_arr += dichotomous_permutation(subarrs, layer=layer+1)

	return new_arr

# 	length = len(arr)
# 	if length <= 2:
# 		return arr

# 	new_arr = [arr[0], arr[-1]]
# 	if (length % 2) == 0:
# 		half = int(length / 2)
# 		new_arr += [arr[half - 1], arr[half]]
# 		subarr1 = [arr[i] for i in range(1, half - 1)]
# 	else:
# 		half = math.floor(length / 2)
# 		new_arr.append(arr[half])
# 		subarr1 = [arr[i] for i in range(1, half)]
# 	subarr2 = [arr[i] for i in range(half + 1, length - 1)]
# 	if len(subarr1) > 0:
# 		new_arr += dichotomous_permutation(subarr1)
# 	if len(subarr2) > 0:
# 		new_arr += dichotomous_permutation(subarr2)

# 	return new_arr

def mix_param_grids(list_of_grids):
	mixed_grids = []
	not_finished = [True] * len(list_of_grids)
	idx = 0
	while sum(not_finished) > 0:
		for g_idx, grid in enumerate(list_of_grids):
			if idx < len(grid):
				mixed_grids.append(grid[idx])
			else:
				not_finished[g_idx] = False
		idx += 1

	return mixed_grids

if __name__ == '__main__':
	root_dir = 'outputs/CRIANN/'
#	for dir_ in sorted(os.listdir(root_dir)):
#		if os.path.isdir(root_dir):
#			full_dir = os.path.join(root_dir, dir_)
#			print('---', full_dir,':')
#			save_dir = os.path.join(full_dir, 'groups/')
#			if os.path.exists(save_dir):
#				try:
#					get_relative_errors(save_dir)
#				except Exception as exp:
#					print('An exception occured when running this experiment:')
#					print(repr(exp))


import pandas as pd
from sklearn import svm, metrics

and_data = [[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 1]]
and_df = pd.DataFrame(and_data)
and_data = and_df[[0, 1]] # 0,1열  데이터
and_label = and_df[2]  #  2열

clf = svm.SVC()
clf.fit(and_data, and_label)
pre = clf.predict(and_data)
ac_score = metrics.accuracy_score(and_label, pre)
print("정확도 :", ac_score)


import markdown as _md

from markdown_include.include import MarkdownInclude as _MarkdownInclude
from typing import IO as _IO
from pathlib import Path as _Path
from weasyprint import HTML as _HTML

# Attribution:
# to_html() and to_pdf() are adapated from ljpengelen's md2pdf.py
# https://github.com/ljpengelen/markdown-to-pdf/blob/master/md2pdf.py

def to_html(
    markdown: str | _Path | _IO,
    css: str | _Path | _IO,
    include_path: str | _Path,
    encoding: str = "utf-8",
) -> str | None:
    """
    Convert markdown to HTML.

    Args:
        markdown (str | _Path | _IO): The markdown to convert.
        css (str | _Path | _IO): The CSS to use when converting the markdown.
        include_path (str | _Path): The directory to use when resolving includes.

    Returns:
        str | None: The HTML if `output` is None, otherwise None.
    """
    html: str = ""

    # Load the markdown
    markdown_data: str = ""
    if isinstance(markdown, str):
        markdown_data = markdown
    elif isinstance(markdown, _Path):
        with open(markdown, "r") as f:
            markdown_data = f.read()
    elif isinstance(markdown, _IO):
        markdown_data = markdown.read()

    # Load the CSS
    css_data: str = ""
    if isinstance(css, str):
        css_data = css
    elif isinstance(css, _Path):
        with open(css, "r") as f:
            css_data = f.read()
    elif isinstance(css, _IO):
        css_data = css.read()

    # Load the include settings
    include_kwargs: dict = {}
    if include_path:
        include_kwargs["base_path"] = include_path
    if encoding:
        include_kwargs["encoding"] = encoding
    markdown_include: _MarkdownInclude = _MarkdownInclude(**include_kwargs)

    html = markdown.markdown(markdown_data, extensions=[markdown_include])

    return f"""
        <html>
            <head>
                <style rel="stylesheet" type="text/css">
                    {css_data}
                </style>
            </head>
            <body>
                {html}
            </body>
        </html>
    """

def to_pdf(
    markdown: str | _Path | _IO,
    output: str | _Path | _IO,
    css: str | _Path | _IO,
    **kwargs,
) -> None:
    """
    Convert markdown to PDF.

    Args:
        markdown (str | _Path | _IO): The markdown to convert.
        output (_Path | _IO): The output file to write the PDF to.
        css (str | _Path | _IO): The CSS to use when converting the markdown.
        **kwargs: Additional keyword arguments to pass to weasyprint.HTML.
    """
    if isinstance(markdown, (str, _Path)):
        with open(markdown, "r") as f:
            markdown = f.read()
    if isinstance(css, (str, _Path)):
        with open(css, "r") as f:
            css = f.read()
    HTML(string=markdown, base_url=".").write_pdf(output, stylesheets=[css], **kwargs)