from django.urls import path
from . import views

app_name = 'ihub'

urlpatterns = [
    path('', views.IndexTemplateView.as_view(), name="index"),  # TESTED

    # PERSON #
    ##########
    path('people/', views.PersonListView.as_view(), name="person_list"),  # TESTED
    path('person/new/', views.PersonCreateView.as_view(), name="person_new"),  # TESTED
    path('person/new/popout/', views.PersonCreateViewPopout.as_view(), name="person_new_pop"),  # TESTED
    path('person/<int:pk>/view/', views.PersonDetailView.as_view(), name="person_detail"),  # TESTED
    path('person/<int:pk>/edit/', views.PersonUpdateView.as_view(), name="person_edit"),  # TESTED
    path('person/<int:pk>/edit/popout/', views.PersonUpdateViewPopout.as_view(), name="person_edit_pop"),  # TESTED
    path('person/<int:pk>/delete/', views.PersonDeleteView.as_view(), name="person_delete"),  # TESTED

    # ORGANIZATION #
    ################
    path('organizations/', views.OrganizationListView.as_view(), name="org_list"),  # TESTED
    path('organization/new/', views.OrganizationCreateView.as_view(), name="org_new"),  # TESTED
    path('organization/<int:pk>/view/', views.OrganizationDetailView.as_view(), name="org_detail"),  # TESTED
    path('organization/<int:pk>/edit/', views.OrganizationUpdateView.as_view(), name="org_edit"),  # TESTED
    path('organization/<int:pk>/delete/', views.OrganizationDeleteView.as_view(), name="org_delete"),  # TESTED

    # ORGANIZATIONPERSON #
    ######################
    path('organization/<int:org>/member/new/', views.MemberCreateView.as_view(), name="member_new"),  # TESTED
    path('member/<int:pk>/edit/', views.MemberUpdateView.as_view(), name="member_edit"),  # TESTED
    path('member/<int:pk>/delete/', views.MemberDeleteView.as_view(), name="member_delete"),  # TESTED
    # path('member/<int:pk>/delete/', views.member_delete, name="member_delete"),

    # # Entry #
    # #########
    path('entries/', views.EntryListView.as_view(), name="entry_list"),  # TESTED
    path('entry/new/', views.EntryCreateView.as_view(), name="entry_new"),  # TESTED
    path('entry/<int:pk>/view', views.EntryDetailView.as_view(), name="entry_detail"),  # TESTED
    path('entry/<int:pk>/edit', views.EntryUpdateView.as_view(), name="entry_edit"),  # TESTED
    path('entry/<int:pk>/delete', views.EntryDeleteView.as_view(), name="entry_delete"),  # TESTED

    # NOTES #
    #########
    path('entry/<int:entry>/note/new/', views.NoteCreateView.as_view(), name="note_new"),  # TESTED
    path('note/<int:pk>/edit/', views.NoteUpdateView.as_view(), name="note_edit"),  # TESTED
    path('note/<int:pk>/delete/', views.note_delete, name="note_delete"),  # TESTED

    # ENTRYPERSON #
    ###############
    path('entry/<int:entry>/person/new/', views.EntryPersonCreateView.as_view(), name="ep_new"),  # TESTED
    path('dfo-person/<int:pk>/edit/', views.EntryPersonUpdateView.as_view(), name="ep_edit"),  # TESTED
    path('dfo-person/<int:pk>/delete/', views.entry_person_delete, name="ep_delete"),  # TESTED

    # Consultation Instructions #
    #############################
    path('organization/<int:org>/instructions/new/', views.InstructionCreateView.as_view(), name="instruction_new"),  # TESTED
    path('instructions/<int:pk>/edit/', views.InstructionUpdateView.as_view(), name="instruction_edit"),  # TESTED
    path('instructions/<int:pk>/delete/', views.InstructionDeleteView.as_view(), name="instruction_delete"),  # TESTED

    # ConsultationRole (ie.. a member who is consulted ) #
    ##############
    path('organization/<int:organization>/member/<int:member>/new/', views.ConsultationRoleCreateView.as_view(), name="consultee_new"),
    path('consultee/<int:pk>/edit/', views.ConsultationRoleUpdateView.as_view(), name="consultee_edit"),
    path('consultee/<int:pk>/delete/', views.ConsultationRoleDeleteView.as_view(), name="consultee_delete"),

    # FILE #
    ########
    path('entry/<int:entry>/file/new/', views.FileCreateView.as_view(), name="file_new"),
    path('file/<int:pk>/edit/', views.FileUpdateView.as_view(), name="file_edit"),
    path('file/<int:pk>/delete/', views.file_delete, name="file_delete"),

    # Reports #
    ###########
    path('reports/search/', views.ReportSearchFormView.as_view(), name="report_search"),
    path('reports/capacity-report/fy/<str:fy>/sectors/<str:sectors>/orgs/<str:orgs>/', views.capacity_export_spreadsheet,
         name="capacity_xlsx"),
    path('reports/cue-card/org/<int:org>/', views.OrganizationCueCard.as_view(), name="report_q"),
    path('reports/summary-report/fy/<str:fy>/sectors/<str:sectors>/orgs/<str:orgs>/', views.summary_export_spreadsheet,
         name="summary_xlsx"),
    path('reports/summary-report-pdf/fy/<str:fy>/sectors/<str:sectors>/orgs/<str:orgs>/', views.PDFSummaryReport.as_view(),
         name="summary_pdf"),
    path(
        'reports/consultation-log/fy/<str:fy>/orgs/<str:orgs>/statuses/<str:statuses>/entry-types/<str:entry_types>/report-title/<str:report_title>/',
        views.ConsultationLogPDFTemplateView.as_view(), name="consultation_log"),
    path(
        'reports/consultation-log/fy/<str:fy>/orgs/<str:orgs>/statuses/<str:statuses>/entry-types/<str:entry_types>/report-title/<str:report_title>/xlsx/',
        views.consultation_log_export_spreadsheet, name="consultation_log_xlsx"),

    path('reports/consultation-instructions/pdf/', views.ReportConsultationInstructionsPDFView.as_view(), name="consultation_instructions_pdf"),
    path('reports/consultation-instructions/xlsx/', views.consultation_instructions_export_spreadsheet, name="consultation_instructions_xlsx"),

    # SETTINGS #
    ############

    path('settings/organizations/', views.OrganizationFormsetView.as_view(), name="manage_orgs"),  # TESTED

    path('settings/sectors/', views.SectorFormsetView.as_view(), name="manage_sectors"),  # TESTED
    path('settings/sector/<int:pk>/delete/', views.SectorHardDeleteView.as_view(), name="delete_sector"),  # TESTED

    path('settings/statuses/', views.StatusFormsetView.as_view(), name="manage_statuses"),  # TESTED
    path('settings/status/<int:pk>/delete/', views.StatusHardDeleteView.as_view(), name="delete_status"),  # TESTED

    path('settings/entry-types/', views.EntryTypeFormsetView.as_view(), name="manage_entry_types"),  # TESTED
    path('settings/entry-type/<int:pk>/delete/', views.EntryTypeHardDeleteView.as_view(), name="delete_entry_type"),  # TESTED

    path('settings/funding-purposes/', views.FundingPurposeFormsetView.as_view(), name="manage_funding_purposes"),  # TESTED
    path('settings/funding-purpose/<int:pk>/delete/', views.FundingPurposeHardDeleteView.as_view(), name="delete_funding_purpose"),
    # TESTED

    path('settings/reserves/', views.ReserveFormsetView.as_view(), name="manage_reserves"),  # TESTED
    path('settings/reserve/<int:pk>/delete/', views.ReserveHardDeleteView.as_view(), name="delete_reserve"),  # TESTED

    path('settings/nations/', views.NationFormsetView.as_view(), name="manage_nations"),  # TESTED
    path('settings/nation/<int:pk>/delete/', views.NationHardDeleteView.as_view(), name="delete_nation"),  # TESTED

    path('settings/funding-programs/', views.FundingProgramFormsetView.as_view(), name="manage_programs"),  # TESTED
    path('settings/funding-program/<int:pk>/delete/', views.FundingProgramHardDeleteView.as_view(), name="delete_program"),  # TESTED

    path('settings/relationship-ratings/', views.RelationshipRatingFormsetView.as_view(), name="manage_ratings"),  # TESTED
    path('settings/relationship-rating/<int:pk>/delete/', views.RelationshipRatingHardDeleteView.as_view(), name="delete_rating"),  # TESTED

    path('settings/users/', views.UserListView.as_view(), name='user_list'),
    path('settings/users/ihub/<int:ihub>/', views.UserListView.as_view(), name='user_list'),
    path('settings/user/<int:pk>/toggle/<str:type>/', views.toggle_user, name='toggle_user'),
]


def doit(func):
    print(f"func: {func}")
    print(f"type(func): {type(func)}")

    result = func()
    return result

def apple():
    return 42

x = doit(apple)
print(f"x: {x}")

y = doit(lambda : 100)
print(f"y: {y}")

fruits = ['pomegranate', 'cherry', 'apricot', 'apple',
'lemon', 'kiwi', 'orange', 'lime', 'watermelon', 'guava',
'papaya', 'fig', 'pear', 'banana', 'tamarind', 'persimmon',
'elderberry', 'peach', 'blueberry', 'lychee', 'grape', 'date' ]

sorted_fruits = sorted(fruits, key=lambda f: (f[-1], f[0]))
print(f"sorted_fruits: {sorted_fruits}")


from __future__ import print_function

import codecs
import collections
import json
import math
import os
import sys
import time

import numpy as np
import tensorflow as tf
import pandas as pd

def hash_single_batch(batch,hparams):
    for b in batch:
        for i in range(len(b)):
            b[i]=abs(hash('key_'+str(i)+' value_'+str(b[i]))) % hparams.single_hash_num
    return batch

def hash_multi_batch(batch,hparams):
    lengths=0
    for b in batch:
        for i in range(len(b)):
            b[i]=[abs(hash('key_'+str(i)+' value_'+str(x)))% hparams.multi_hash_num for x in str(b[i]).split()]
            lengths=max(lengths,len(b[i]))
            if len(b[i])==0:
                b[i]=[abs(hash('key_'+str(i)+' value_'+str('<pad>')))% hparams.multi_hash_num]
    batch_t=np.zeros((len(batch),len(hparams.multi_features),min(hparams.max_length,lengths)))
    weights_t=np.zeros((len(batch),len(hparams.multi_features),min(hparams.max_length,lengths)))

    for i in range(len(batch)):
        for j in range(len(batch[i])):
            for k in range(min(hparams.max_length,len(batch[i][j]))):
                batch_t[i,j,k]=batch[i][j][k]
                weights_t[i,j,k]=1

    return batch_t,weights_t

def print_time(s, start_time):
  """Take a start time, print elapsed duration, and return a new time."""
  print("%s, time %ds, %s." % (s, (time.time() - start_time), time.ctime()))
  sys.stdout.flush()
  return time.time()

def print_out(s, f=None, new_line=True):
  """Similar to print but with support to flush and output to a file."""
  if isinstance(s, bytes):
    s = s.decode("utf-8")

  if f:
    f.write(s.encode("utf-8"))
    if new_line:
      f.write(b"\n")

  # stdout
  out_s = s.encode("utf-8")
  if not isinstance(out_s, str):
    out_s = out_s.decode("utf-8")
  print(out_s, end="", file=sys.stdout)

  if new_line:
    sys.stdout.write("\n")
  sys.stdout.flush()

def print_step_info(prefix,epoch, global_step, info):
    print_out("%sepoch %d step %d lr %g loss %.6f gN %.2f, %s" %
      (prefix, epoch,global_step, info["learning_rate"],
       info["train_ppl"], info["avg_grad_norm"], time.ctime()))

def print_hparams(hparams, skip_patterns=None, header=None):
  """Print hparams, can skip keys based on pattern."""
  if header: print_out("%s" % header)
  values = hparams.values()
  for key in sorted(values.keys()):
    if not skip_patterns or all(
        [skip_pattern not in key for skip_pattern in skip_patterns]):
      print_out("  %s=%s" % (key, str(values[key])))


#!/usr/bin/env python

import aoc
from collections import Counter

def solve(inp: str):
    ingredients = Counter()
    allergens = {}
    for line in inp.splitlines():
        ingredients_str, allergens_str = line[:-1].split(' (contains ')
        ingrs = set(ingredients_str.split(' '))
        ingredients.update(ingrs)
        for a in allergens_str.split(', '):
            if a not in allergens:
                allergens[a] = ingrs
            else:
                allergens[a] = allergens[a].intersection(ingrs)

    ingr_without_allergens = ingredients.keys() - set(
        [i for ingrs in allergens.values() for i in ingrs])
    print('Part 1:', sum([ingredients[i]
                          for i in ingr_without_allergens]))

    used = set([])
    while len(used) < len(allergens):
        for a, ingrs in allergens.items():
            if len(ingrs) > 1:
                allergens[a] -= used
            else:
                used.update(ingrs)

    print('Part 2:', ','.join([allergens[a].pop()
                               for a in sorted(allergens.keys())]))

# with open('test.txt', 'r') as f:
#     inp = f.read()
#     solve(inp)

with open('input.txt', 'r') as f:
    inp = f.read()
    solve(inp)


import numpy as np
import time

data = np.array([[1,2,3,4,5,6,67,7,8,8,8,9],[1,2,3,4,5,6,67,7,8,8,8,9]])
data1 = np.array([[1,2,3,4,5,6,67,7,8,8,8,9],[1,2,3,4,5,6,67,7,8,8,8,9]])

numpy_data = np.frombuffer(data, np.int32)
# print(data.nbytes, numpy_data.nbytes)
times = []
s = time.time()
for i in range(100):
    s = time.time()
    ans = data+data1
    times.append(time.time()-s)

print(np.average(times))
print(ans)


import numpy as np

def MahalanobisDist(data):
    '''Computing covariance matrix for the data'''
    covariance_matrix = np.cov(data, rowvar=False)

    '''Computing pseudoinverse of the covariance matrix'''
    inv_covariance_matrix = np.linalg.pinv(covariance_matrix)
    vars_mean = []

    '''Appending mean of the columns respectively in vars_mean'''
    for i in range(data.shape[0]):
        vars_mean.append(list(data.mean(axis=0)))

    diff = data - vars_mean
    md = []

    '''Computing Mahalanobis distance for each feature'''
    for i in range(len(diff)):
        md.append(np.sqrt(diff[i].dot(inv_covariance_matrix).dot(diff[i])))

    return md

def MD_detectOutliers(data, extreme=False):

    MD = MahalanobisDist(data)

    '''one popular way to specify the threshold'''
    m = np.mean(MD)
    t = 3. * m if extreme else 2. * m
    outliers = []
    for i in range(len(MD)):
       if MD[i] > t:
           outliers.append(i)  # index of the outlier
    return np.array(outliers)

    '''
    or according to the 68–95–99.7 rule

    std = np.std(MD)
    k = 3. * std if extreme else 2. * std
    m = np.mean(MD)
    up_t = m + k
    low_t = m - k
    outliers = []
    for i in range(len(MD)):
        if (MD[i] >= up_t) or (MD[i] <= low_t):
            outliers.append(i)  # index of the outlier
    return np.array(outliers)
    '''


from turtle import Screen
from paddle import Paddle
from ball import Ball
from scoreboard import Scoreboard
import time

screen = Screen()
screen.listen()
screen.bgcolor("black")
screen.title("PONG")
screen.setup(width=800, height=600)
screen.tracer(0)

p1 = Paddle((350, 0))
p2 = Paddle((-350, 0))
ball = Ball()
score = Scoreboard()

screen.listen()
screen.onkeypress(p1.go_up, "Up")
screen.onkeypress(p1.go_down, "Down")
screen.onkeypress(p2.go_up, "w")
screen.onkeypress(p2.go_down, "s")

game_is_on = True

while game_is_on:
    time.sleep(ball.move_speed)
    screen.update()
    ball.move()

    # Detect collision with wall
    if ball.ycor() > 280 or ball.ycor() < -280:
        ball.bounce_y()

    # Detect collision with paddle
    if ball.distance(p1) < 50 and ball.xcor() > 320 or ball.distance(p2) < 50 and ball.xcor() < -320:
        ball.bounce_x()

    # Detect when right paddle misses
    if ball.xcor() > 380:
        ball.reset_position()
        score.l_point()

    # Detect when left paddle misses
    if ball.xcor() < -380:
        ball.reset_position()
        score.r_point()

screen.exitonclick()

Turtle Graphics Library Projects/4. Pong game/main.py


import ui,app,chat,chr,net,player,wndMgr,uiCommon,eXLib
from OpenBot.Modules.Protector.protector_module import protector_module
from OpenBot.Modules.Attacker.attacker_module import attacker_module
from OpenBot.Modules.WaitHack.waithack_module import instance
from OpenBot.Modules.WaitHack.waithack_interface import waithack_interface
from OpenBot.Modules.Farmbot.farmbot_module import farm
from OpenBot.Modules.Fishbot.fishbot_module import fishbot_module
from OpenBot.Modules.Settings.settings_module import instance as sett_instance
from OpenBot.Modules.Skillbot.skillbot_module import instance as skillbot_instance
from OpenBot.Modules.ShopSearcher.shop_searcher_module import shop_searcher_module
from OpenBot.Modules import PythonManager, Hooks, UIComponents
from OpenBot.Modules.Networking import NetworkingWebsockets

class OpenBotHackbarDialog(ui.ScriptWindow):

    Hackbar = 0
    Teleport = 0
    ShortCuts = 0
    comp = UIComponents.Component()
    python_manager = PythonManager.PythonManagerDialog()

    def __init__(self):
        self.OpenBotBoard = ui.ThinBoard(layer="TOP_MOST")
        self.OpenBotBoard.SetPosition(0, 40)
        self.OpenBotBoard.SetSize(51, 75)
        self.OpenBotBoard.AddFlag("float")
        self.OpenBotBoard.AddFlag("movable")
        self.OpenBotBoard.Hide()

        self.ShowHackbarButton = self.comp.Button(None, '', 'Show Hackbar', wndMgr.GetScreenWidth()-99, 260, self.OpenHackbar, eXLib.PATH + 'OpenBot/Images/Shortcuts/show_0.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/show_1.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/show_0.tga')
        self.HideHackbarButton = self.comp.HideButton(None, '', 'Hide Hackbar', wndMgr.GetScreenWidth()-99, 260, self.OpenHackbar, eXLib.PATH + 'OpenBot/Images/Shortcuts/hide_0.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/hide_1.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/hide_0.tga')
        self.ShortCutButton = self.comp.Button(None, '', 'ShortCuts', wndMgr.GetScreenWidth()-62, 260, self.OpenShortCuts, eXLib.PATH + 'OpenBot/Images/Shortcuts/shortcut_0.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/shortcut_1.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/shortcut_0.tga')
        self.CrashButton = self.comp.HideButton(None, '', 'Exit', wndMgr.GetScreenWidth()-45, 310, self.CloseRequest, eXLib.PATH + 'OpenBot/Images/Shortcuts/close_0.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/close_1.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/close_0.tga')

        self.RunPythonButton = self.comp.Button(self.OpenBotBoard, '', 'Run-Python', 10, 10, self.RunPython, eXLib.PATH + 'OpenBot/Images/Shortcuts/loadpy_0.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/loadpy_1.tga', eXLib.PATH + 'OpenBot/Images/Shortcuts/loadpy_0.tga')
        self.networkButton = self.comp.Button(self.OpenBotBoard, '', 'Reconnect server', 8, 45, self.OnNetworkButton, eXLib.PATH + 'OpenBot/Images/Hackbar/action_0.tga', eXLib.PATH + 'OpenBot/Images/Hackbar/action_1.tga', eXLib.PATH + 'OpenBot/Images/Hackbar/action_0.tga')

    def OpenHackbar(self):
        if self.Hackbar:
            self.Hackbar = 0
            self.ShowHackbarButton.Show()
            self.HideHackbarButton.Hide()
            self.OpenBotBoard.Hide()
        else:
            self.Hackbar = 1
            self.ShowHackbarButton.Hide()
            self.HideHackbarButton.Show()
            self.OpenBotBoard.Show()

    def OpenShortCuts(self):
        if player.GetName() == "":
            #return
            pass
        if self.ShortCuts:
            self.ShortCuts = 0
            self.CrashButton.Hide()
        else:
            self.ShortCuts = 1
            self.CrashButton.Show()

    def OnNetworkButton(self):
        reload(NetworkingWebsockets)

    def RunPython(self):
        self.python_manager.switch_state()

    def CloseRequest(self):
        self.QuestionDialog = uiCommon.QuestionDialog()
        self.QuestionDialog.SetText("Do You want to quit Metin2 immediately?")
        self.QuestionDialog.SetAcceptEvent(ui.__mem_func__(self.Close))
        self.QuestionDialog.SetCancelEvent(ui.__mem_func__(self.CancelQuestionDialog))
        self.QuestionDialog.Open()

    def Close(self):
        app.Abort()

    def CancelQuestionDialog(self):
        self.QuestionDialog.Close()
        self.QuestionDialog = None

try:
    app.Shop.Close()
except:
    pass

settings_loaded = False
def __PhaseChangeLoadSettingsCallback(phase, phaseWnd):
    global settings_loaded
    from OpenBot.Modules.FileHandler.FileHandlerInterface import file_handler_interface
    from OpenBot.Modules import OpenLib
    if phase == OpenLib.PHASE_GAME and not settings_loaded:
        def load():
            file_handler_interface.load_last_other_settings()
            file_handler_interface.load_last_pickup_list()
        OpenLib.SetTimerFunction(2, load)
        settings_loaded = True

Hooks.registerPhaseCallback("loadingCallback", __PhaseChangeLoadSettingsCallback)

app.Shop = OpenBotHackbarDialog()


import traceback, time
import rclpy

from rclpy.node import Node
from std_msgs.msg import String, Bool

from rclpy.qos import ReliabilityPolicy, QoSProfile, LivelinessPolicy, DurabilityPolicy, HistoryPolicy
from rclpy.duration import Duration

class BarNode(Node):
    def __init__ (self):
        super().__init__('bar_node')
        QoS_profile = QoSProfile(
            history=HistoryPolicy.KEEP_LAST,
            depth=10,
            reliability=ReliabilityPolicy.RELIABLE,
            durability=DurabilityPolicy.TRANSIENT_LOCAL,
            lifespan=Duration(seconds=300),
            liveliness=LivelinessPolicy.AUTOMATIC,
            liveliness_lease_duration=Duration(seconds=2))
        self.publish_bar_health = self.create_publisher(
            Bool, 'bar_health', qos_profile=QoS_profile)

        self.get_logger().info(f'Bar node started!')

def main(args=None):

    rclpy.init(args=args)
    bar_node = BarNode()
    rclpy.spin(bar_node)

    bar_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    try:
        main()
    except:
        traceback.print_exc()


from itertools import chain

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.db.models import Value, CharField, Q
from django.contrib import messages
from django.core.paginator import Paginator
from django.db import IntegrityError

from review import forms, models

from authentication import models as authentication_models

# Create your views here.

@login_required
def create_ticket(request):
    """
    view nous permettant de créer un ticket et de l'enregistrer
    pour le ticket on recupere une photo et on l'enregistre

    Args:
        request (object): requete http

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    ticket_form = forms.TicketForm()
    if request.method == "POST":
        ticket_form = forms.TicketForm(request.POST)
        photo = request.FILES.get("photo")
        if ticket_form.is_valid():
            ticket = ticket_form.save(commit=False)
            ticket.author = request.user
            ticket.photo = photo
            ticket.save()
            return redirect("flux")

    context = {
        "ticket_form": ticket_form,
    }

    return render(request, "review/create_ticket.html", context=context)

@login_required
def create_review_and_ticket(request):
    """
    view nous permettant de créer un ticket avec une review sur ce même ticket
    pour cela on utlise 3 formulaire:
    TicketForm, PhotoForm, ReviewForm

    Args:
        request (object): requete http

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    ticket_form = forms.TicketForm()
    review_form = forms.ReviewForm()
    if request.method == "POST":
        ticket_form = forms.TicketForm(request.POST)
        review_form = forms.ReviewForm(request.POST)
        rating = request.POST.get("rating")
        photo = request.FILES.get("photo")
        if all([ticket_form.is_valid(), review_form.is_valid()]):
            ticket = ticket_form.save(commit=False)
            ticket.photo = photo
            ticket.author = request.user
            ticket.save()
            review = review_form.save(commit=False)
            review.user = request.user
            review.ticket = ticket
            review.rating = rating
            review.save()
            return redirect("flux")
    context = {
        "ticket_form": ticket_form,
        "review_form": review_form,
        "range": range(6),
    }

    return render(request, "review/create_review_and_ticket.html", context=context)

@login_required
def create_review(request, ticket_id):
    """
    view nous permettant de créer une review pour un ticket existant
    que ce soit le notre ou non

    Args:
        request (object): requete http
        ticket_id (str): l'id du ticket visé

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    ticket = get_object_or_404(models.Ticket, id=ticket_id)
    review_form = forms.ReviewForm()
    if request.method == "POST":
        review_form = forms.ReviewForm(request.POST)
        rating = request.POST.get("rating")
        if review_form.is_valid():
            review = review_form.save(commit=False)
            review.ticket = ticket
            review.rating = rating
            review.user = request.user
            review.save()
            return redirect("flux")
    context = {
        "review_form": review_form,
        "ticket": ticket,
        "range": range(6),
    }
    return render(request, "review/create_review.html", context=context)

@login_required
def edit_ticket(request, ticket_id):
    """
    view nous permettant de modifier un ticket que nous avons créé précédemment

    Args:
        request (object): requete http
        ticket_id (str): l'id du ticket visé

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    ticket = get_object_or_404(models.Ticket, id=ticket_id)
    if ticket.author != request.user:
        return redirect("display_posts")
    else:
        photo_url = ticket.photo.url
        edit_form = forms.TicketForm(instance=ticket)
        delete_form = forms.DeleteTicketReviewForm()
        if request.method == "POST":
            if "edit_ticket" in request.POST:
                photo = request.FILES.get("photo")
                ticket.photo = photo
                edit_form = forms.TicketForm(request.POST, instance=ticket)
                if edit_form.is_valid():
                    edit_form.save()
                    return redirect("display_posts")
            if "delete_ticket_or_review" in request.POST:
                delete_form = forms.DeleteTicketReviewForm(request.POST)
                if delete_form.is_valid():
                    ticket.delete()
                    return redirect("display_posts")

    context = {
        "photo_url": photo_url,
        "edit_form": edit_form,
        "delete_form": delete_form,
    }
    return render(request, "review/edit_ticket.html", context=context)

@login_required
def edit_review(request, review_id):
    """
    view nous permettant de modifier une review que l'on créée précédemment

    Args:
        request (object): requete http
        review_id (str): l'id de la review visée

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    review = get_object_or_404(models.Review, id=review_id)
    if review.user != request.user:
        return redirect("display_posts")
    else:
        edit_form = forms.ReviewForm(instance=review)
        delete_form = forms.DeleteTicketReviewForm()
        if request.method == "POST":
            if "edit_review" in request.POST:
                rating = request.POST.get("rating")
                review.rating = rating
                edit_form = forms.ReviewForm(request.POST, instance=review)
                if edit_form.is_valid():
                    edit_form.save()
                    return redirect("display_posts")
            if "delete_ticket_or_review" in request.POST:
                delete_form = forms.DeleteTicketReviewForm(request.POST)
                if delete_form.is_valid():
                    review.delete()
                    return redirect("display_posts")

    context = {
        "review": review,
        "edit_form": edit_form,
        "delete_form": delete_form,
        "range": range(6),
    }
    return render(request, "review/edit_review.html", context=context)

@login_required
def display_posts(request):
    """
    on affiche tous les posts triés de l'utilisateur
    avec la possibilité de les supprimer

    Args:
        request (object): requete http

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    tickets = models.Ticket.objects.filter(author=request.user)
    reviews = models.Review.objects.filter(user=request.user)
    delete_form = forms.DeleteTicketReviewForm()

    for ticket in tickets:
        if "delete_ticket_or_review" in request.POST:
            delete_form = forms.DeleteTicketReviewForm(request.POST)
            if delete_form.is_valid():
                ticket.delete()
                return redirect("display_posts")

    for review in reviews:
        if "delete_ticket_or_review" in request.POST:
            delete_form = forms.DeleteTicketReviewForm(request.POST)
            if delete_form.is_valid():
                review.delete()
                return redirect("display_posts")

    tickets_sorted = sorted(
        tickets, key=lambda instance: instance.date_created, reverse=True
    )
    reviews_sorted = sorted(
        reviews, key=lambda instance: instance.date_created, reverse=True
    )

    context = {
        "tickets": tickets_sorted,
        "reviews": reviews_sorted,
        "delete_form": delete_form,
    }
    return render(request, "review/display_posts.html", context=context)

def flux(request):
    """
    une view qui nous permet d'afficher tous tickets ou reviews de l'utilisateur
    et ceux des personnes qu'il suit

    Args:
        request (object): requete http

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    # Nos followers
    user_follow = authentication_models.User.objects.filter(
        followed_by__in=models.UserFollows.objects.filter(user=request.user)
    )

    # Toutes nos reviews ou celles de nos followers
    all_reviews = models.Review.objects.filter(
        Q(user__in=user_follow) | Q(user=request.user)
    )

    # Tous nos tickets et ceux de nos followers
    all_tickets = models.Ticket.objects.filter(
        Q(author__in=user_follow) | Q(author=request.user)
    ).exclude(review__in=all_reviews)

    all_unreviewed_tickets = all_tickets.exclude(review__in=all_reviews).annotate(
        state=Value("UNREVIEWED", CharField())
    )

    tickets_and_reviews = sorted(
        chain(all_unreviewed_tickets, all_reviews),
        key=lambda instance: instance.date_created,
        reverse=True,
    )

    paginator = Paginator(tickets_and_reviews, 6)
    page = request.GET.get("page")
    user = request.user

    page_obj = paginator.get_page(page)

    context = {
        "page_obj": page_obj,
        "user": user,
    }
    return render(request, "review/flux.html", context=context)

@login_required
def follow_users(request):
    """
    view nous permettant de s'abonner à d'autres utilisateurs
    on récupère aussi les utilisateurs qui sont abonnés à l'utilisateur connecté

    Args:
        request (object): requete http

    Returns:
        httpresponse: on retourne la requete http, le template visé avec les variables de gabarit
    """
    user_follows = models.UserFollows.objects.filter(user=request.user)
    user_followed = models.UserFollows.objects.filter(followed_user=request.user)
    if request.method == "POST":
        user = request.POST.get("username")
        try:
            user_to_follow = authentication_models.User.objects.get(username=user)
            if user_to_follow == request.user:
                messages.error(request, "Vous ne pouvez pas vous ajouter vous-même !")
                return redirect("follow_users")
            elif models.UserFollows.objects.filter(followed_user=user_to_follow):
                messages.error(request, "Vous suivez déjà cet utilisateur")
                return redirect("follow_users")
        except authentication_models.User.DoesNotExist:
            messages.error(request, "nom incorrect ou utilisateur inexistant")
            return redirect("follow_users")
        else:
            subscription = models.UserFollows(
                user=request.user, followed_user=user_to_follow
            )
            subscription.save()

    user = request.user

    context = {
        "user_follows": user_follows,
        "user_followed": user_followed,
        "user": user,
    }
    return render(request, "review/follow_users_form.html", context=context)

@login_required
def unsubscribe(request, user):
    """
    view permettant de se désabonner d'un utilisateur

    Args:
        request (object): requete http
        user (str): nom de l'utilisateur

    Returns:
        htttpresponse: on se redirige vers la page des followers
    """
    user_to_remove = authentication_models.User.objects.get(username=user)
    models.UserFollows.objects.get(followed_user_id=user_to_remove.id, user_id=request.user.id).delete()
    return redirect("follow_users")


class MinStack(object):
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []

    def push(self, x):
        """
        :type x: int
        :rtype: void
        """
        t = []
        t.append(x)
        if len(self.stack) == 0:
            t.append(x)
        else:
            if self.stack[-1][1] > x:
                t.append(x)
            else:
                t.append(self.stack[-1][1])
        self.stack.append(t)

    def pop(self):
        """
        :rtype: void
        """
        return self.stack.pop()[0]
    def top(self):
        """
        :rtype: int

        """
        if len(self.stack)== 0:
            return None

        return self.stack[-1][0]

    def getMin(self):
        """
        :rtype: int
        """
        return self.stack[-1][1]

# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
minStack = MinStack()

minStack.push(-2)
print(minStack.getMin())

minStack.push(0)
print(minStack.getMin())

minStack.push(-3)
print(minStack.getMin())

minStack.getMin()

print(minStack.getMin())
print(minStack.pop())
print(minStack.top())
print(minStack.getMin())


# Import monkdata.py file as a module
import monkdata as m
import dtree
import random
import numpy as np
import matplotlib.pyplot as plt
import drawtree_qt5 as draw

# ---- FUNCTIONS USED IN LAB1 ----
def partition(data, fraction):
    ldata = list(data)
    random.shuffle(ldata)
    breakPoint = int(len(ldata) * fraction)
    return ldata[:breakPoint], ldata[breakPoint:]

# --------------------------
# --------- START ----------
# --------------------------

print("-----START-----")

# ---- ASSIGNEMENT 0 -----
print("\n### Assignement 0")
print("some explication about the monk2 dataset less adapted to decision trees algos")

# ---- ASSIGNEMENT 1 -----
print("\n### Assignement 1")

# Calculate the entropy of each training datasets
entropy = [dtree.entropy(m.monk1), dtree.entropy(m.monk2), dtree.entropy(m.monk3)]
for i in range(len(entropy)):
    print(f"Entropy of monk{i+1}: {entropy[i]}")

# ---- ASSIGNEMENT 2 -----
print("\n### Assignement 2")
print("some remarks on values of entropies")

# ---- ASSIGNEMENT 3 -----
print("\n### Assignement 3")
information_gain = []
information_gain_monk1 = []
information_gain_monk2 = []
information_gain_monk3 = []

# Calculate the information gain for each attribute on each dataset
for attribute in m.attributes:
    information_gain_monk1.append(dtree.averageGain(m.monk1, attribute))
    information_gain_monk2.append(dtree.averageGain(m.monk2, attribute))
    information_gain_monk3.append(dtree.averageGain(m.monk3, attribute))
information_gain.append(information_gain_monk1)
information_gain.append(information_gain_monk2)
information_gain.append(information_gain_monk3)

# Display information gain for each attribute on each dataset
for i in range(len(information_gain)):
    print(f"--- dataset monk{i+1} Information gain ---")
    for j in range(len(information_gain[i])):
        print(f"A{j+1}: {information_gain[i][j]}")

# ---- ASSIGNEMENT 4 -----
print("\n### Assignement 4")
print("some analysis on values of information gain for datasets")

# ---- ASSIGNEMENT 5 -----
print("\n### Assignement 5")

# Personnal draw of the decision tree for monk1 on first two levels
# A5 is the attribute with the higher information gain -> {1, 2, 3, 4}
attribut_first_level = information_gain_monk1.index(max(information_gain_monk1))
tree_monk1 = []
for i in range(4):
    tree_monk1.append(dtree.select(m.monk1, m.attributes[4], i+1))

# Split (second level) using the attribute with the higher gain information
attributes_second_level = []
information_gain_second_level = []
for i in range(len(tree_monk1)):
    information_gain_subset = []
    for attribute in m.attributes:
        information_gain_subset.append(dtree.averageGain(tree_monk1[i], attribute))
    attribut_second_level = information_gain_subset.index(max(information_gain_subset))
    information_gain_second_level.append(max(information_gain_subset))
    attributes_second_level.append(attribut_second_level)
    second_subset = []
    for j in range(len(m.attributes[attribut_second_level].values)):
        second_subset.append(dtree.select(tree_monk1[i], m.attributes[attribut_second_level],j+1))
    tree_monk1[i] = second_subset

# Display personnal tree
tree_monk1_str = "--Personnal monk1 tree: "
tree_monk1_str += "A" + str(attribut_first_level+1) + "("
index_second_level = 0
for level1 in tree_monk1:
    print(information_gain_second_level[index_second_level])
    if information_gain_second_level[index_second_level]==0:
        tree_monk1_str += "+" if dtree.mostCommon(level1[1]) else "-"
    else:
        tree_monk1_str += "A" + str(attributes_second_level[index_second_level]+1) + "("
        for level2 in level1:
            tree_monk1_str += "+" if dtree.mostCommon(level2) else "-"
        tree_monk1_str += ")"
    index_second_level +=1
tree_monk1_str += ")"
print(tree_monk1_str)

# Display the ID3 tree (depth = 2)
print(f"--ID3 monk1 tree (depth2): {dtree.buildTree(m.monk1, m.attributes, 2)}\n")
print(f"--ID3 monk1 tree: {dtree.buildTree(m.monk1, m.attributes)}\n")
print(f"--ID3 monk3 tree: {dtree.buildTree(m.monk3, m.attributes)}\n")

# If you want to display using drawtree_qt5
# draw.drawTree(dtree.buildTree(m.monk1, m.attributes))
# draw.drawTree(dtree.buildTree(m.monk3, m.attributes))

# Build all tree using dtree on training set
print("--Check validity on training set:")
t_monk1 = dtree.buildTree(m.monk1, m.attributes)
print(f"t_monk1: {dtree.check(t_monk1, m.monk1)}")
t_monk2 = dtree.buildTree(m.monk2, m.attributes)
print(f"t_monk2: {dtree.check(t_monk2, m.monk2)}")
t_monk3 = dtree.buildTree(m.monk3, m.attributes)
print(f"t_monk3: {dtree.check(t_monk3, m.monk3)}")

# Build all tree using dtree on testing set
print("--Check validity on testing set:")
t_monk1_test = dtree.buildTree(m.monk1test, m.attributes)
print(f"t_monk1_test: {dtree.check(t_monk1, m.monk1test)} | {1-dtree.check(t_monk1, m.monk1test)}")
t_monk2_test = dtree.buildTree(m.monk2test, m.attributes)
print(f"t_monk2_test: {dtree.check(t_monk2, m.monk2test)} | {1-dtree.check(t_monk2, m.monk2test)}")
t_monk3_test = dtree.buildTree(m.monk3test, m.attributes)
print(f"t_monk3_test: {dtree.check(t_monk3, m.monk3test)} | {1-dtree.check(t_monk3, m.monk3test)}")

# ---- ASSIGNEMENT 6 -----
print("\n### Assignement 6")
print("some explanation of pruning from a bias variance trade-off perspective")

# ---- ASSIGNEMENT 7 -----
print("\n### Assignement 7")

datasets = [[m.monk1, m.monk1test], [m.monk3, m.monk3test]]

numberTry = 200
fractions = [0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.98]

fractions_score_test_mean = []
fractions_score_test_spread = []
fractions_score_training_mean = []

number_dataset =1
for dataset in datasets:
    fractions_score_test_mean_dataset = []
    fractions_score_test_spread_dataset = []
    fractions_score_training_dataset = []
    for fraction in fractions:
        # waiting message
        print(f"[MONK-{number_dataset}]Calculation for fraction {round(fraction, 2)} is running...")
        fraction_score_test = []
        fraction_score_training = []
        for i in range(numberTry):
            monktrain, monkval = partition(dataset[0], fraction)
            initial_tree = dtree.buildTree(monktrain, m.attributes)
            all_pruned_tree = dtree.allPruned(initial_tree)
            best_pruned_tree = all_pruned_tree[0]
            best_score = dtree.check(best_pruned_tree, monkval)
            for pruned_tree in all_pruned_tree:
                score = dtree.check(pruned_tree, monkval)
                if(score>best_score):
                    best_score = score
                    best_pruned_tree = pruned_tree
            score_test = dtree.check(best_pruned_tree, dataset[1])
            fraction_score_test.append(score_test)
            fraction_score_training.append(dtree.check(best_pruned_tree, dataset[0]))
        fractions_score_test_mean_dataset.append(np.mean(np.array(fraction_score_test)))
        fractions_score_training_dataset.append(np.mean(np.array(fraction_score_training)))
        fractions_score_test_spread_dataset.append(np.std(np.array(fraction_score_test), ddof=1))
    fractions_score_test_mean.append(fractions_score_test_mean_dataset)
    fractions_score_test_spread.append(fractions_score_test_spread_dataset)
    fractions_score_training_mean.append(fractions_score_training_dataset)
    print(f"----Calculation of MONK-{number_dataset} finised----")
    number_dataset = 3

# Display textual result
for indexDataset in range(len(datasets)):
    for i in range(len(fractions)):
        print(f"[MONK-{'1' if indexDataset==0 else '3'}] Fraction {fractions[i]}: mean = {fractions_score_test_mean[indexDataset][i]} | spread = {fractions_score_test_spread[indexDataset][i]}")

# Display results using plots
plt.subplot(2, 2, 1)
plt.plot(fractions, fractions_score_test_mean[0], label='mean score')
plt.title('[MONK-1] Mean score')
plt.xlabel('fraction')
plt.ylabel('score')

plt.subplot(2, 2, 2)
plt.plot(fractions, fractions_score_test_spread[0], label='spread score')
plt.title('[MONK-1] Spread of score')
plt.xlabel('fraction')
plt.ylabel('score')

plt.subplot(2, 2, 3)
plt.plot(fractions, fractions_score_test_mean[1], label='mean score')
plt.title('[MONK-3] Mean score')
plt.xlabel('fraction')
plt.ylabel('score')

plt.subplot(2, 2, 4)
plt.plot(fractions, fractions_score_test_spread[1], label='spread score')
plt.title('[MONK-3] Spread of score')
plt.xlabel('fraction')
plt.ylabel('score')

plt.tight_layout()
plt.show()

# plt.subplot(1, 2, 1)
# plt.plot(fractions, fractions_score_test_mean[0], label='score test set')
# plt.plot(fractions, fractions_score_training_mean[0], label='score training set')
# plt.title('[MONK-1] Score of test and training set')
# plt.xlabel('fraction')
# plt.ylabel('score')
# plt.legend()

# plt.subplot(1, 2, 2)
# plt.plot(fractions, fractions_score_test_mean[1], label='score test set')
# plt.plot(fractions, fractions_score_training_mean[1], label='score training set')
# plt.title('[MONK-3] Score of test and training set')
# plt.xlabel('fraction')
# plt.ylabel('score')
# plt.legend()

# plt.tight_layout()
# plt.show()

print("\n------END------")
# --------------------------
# --------- END ----------
# --------------------------


'''
Setup some utilities, very much related to our project of displaying figures
in Jupyter.
'''

__author__ = 'Alain Lichnewsky'
__license__ = 'MIT License'
__version__ = '1.0'

# Sys import
import sys, os, re
from abc import ABC

# Using pandas and numpy (NP happens in matplotlib)
import pandas as PAN
import numpy  as NP
import math

# Python programming
from itertools import cycle
from collections.abc import Iterable, Mapping, Callable

# My stuff
from lib.utilities import *

# Matplotlib
import matplotlib        as MPL
# Add color
from matplotlib import cm as CM
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
# Enable 3D
import mpl_toolkits.mplot3d.axes3d
from mpl_toolkits.mplot3d.axes3d import get_test_data

# reinitialize default matplotlib behaviour
svMPL_figsize = MPL.rcParams['figure.figsize']
MPL.rcParams['figure.figsize'] = [12, 10]

import matplotlib.pyplot as PLT

import seaborn as SNS
SNS.set(font_scale=1)

## Scikit_Learn ** Remains to be seen if I want to require sklearn on all applications
##              ** or if I need to modularize differently (TBD)
try:
    from sklearn import cluster
    import sklearn.preprocessing as SKPREPRO
    SKLEARN_AVAIL = True
except Exception as err:
    print ("Scikit Learn not available, some functionality may be unavailable")
    SKLEARN_AVAIL = False

##
##  See example of utilisation after the classes
##
class  figureFromFrame(object):
    """ Make a figure from a DataFrame;
        Keywords listed in defaultOpts are honored.

        Note that subplot spacing can be further adjusted by
        calling 'plt.subplots_adjust' with appropriate parameters,
        this can be done after figure generation.

    """
    defaultOpts = {"figsize":(8.0,6.0),"subplotIndex":1}

    # should we have a white list instead of a blacklist?
    excludeFiltered = ("subplots", 'subplotIndex', 'dateTranslate')
    def __init__(self, df, **kwdOpts):
        self._setDf( df, NZOnly = False)
        self.optd={}
        self.diagnosticsHash={}  #directory for hashing emitted diagnostics to emit once
                                 #for now see usage in method _doLineAttrs; currently
                                 #counting, still need to figure out how to use count!
        self.lines = None
        setDefaults(self.optd, kwdOpts, figureFromFrame.defaultOpts)

        optdFilter = { z[0]:z[1] for z in self.optd.items()
                                 if z[0] not in figureFromFrame.excludeFiltered }

        self.subplotIndex = self.optd["subplotIndex"]
        if "subplots" in  self.optd :
            f,s = PLT.subplots(**(self.optd["subplots"]), **optdFilter)
            self.fig = f
            self.subplots = s
        else:
            f,s = PLT.subplots(**optdFilter)
            self.fig = f
            self.subplots = s

        self._setSubplot()

        self.colSel = None        # Keep track of selected columns

        #print(f"in figureFromFrame.__init__: self.fig:{type(self.fig)}")
        #print(f"                           : self.subplots:{type(self.subplots)}")
        #print(f"                           : self.currSub:{type(self.currSub)}")
        #print(f"                           : self.subplotIndex:{self.subplotIndex}")

    def _setDf(self,df, NZOnly=True):
        if df is None:
            if  not NZOnly:
                self.df = None
        else:
              self.df   = df.copy()

    def setAttrs(self, **attrs):
        self._plotKwd(attrs, cols =  self.colSel)

    def __del__(self):
        # reinitialize default matplotlib behaviour
        MPL.rcParams['figure.figsize'] = svMPL_figsize

    def _setSubplot(self):
        if isinstance(self.subplots, NP.ndarray):
            pos = self.subplotIndex -1
            if (pos < 0) or (pos >= self.subplots.size):
              raise RuntimeError(f"pos={pos} not within bounds")
            # row by row numbering
            sz = self.subplots.shape[1]
            self.currSub =  self.subplots[ pos//sz, pos%sz ]
        else:
            self.currSub =  self.subplots

    def advancePlotIndex(self,incr=1):
         if isinstance(self.subplots, NP.ndarray):
             self.subplotIndex = 1 + (self.subplotIndex + (incr -1)) % self.subplots.size

    def _plotKwd(self,kwdOpts, cols=None):
        """ cols = list of columns to be put in legend, if None, all columns in df
                   are used
            kwdOpts: handle keyword parameters pertaining to
            - figure (x,y)labels, yscale, title, legend,
            - forward keyword parameters that pertain to lines to _doLineAttrs
            - general documentation (including options) at
              https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html
        """
        # plots an axis label
        if "xlabel" in kwdOpts:
           self.currSub.set_xlabel(kwdOpts["xlabel"])
        if "ylabel" in kwdOpts:
           self.currSub.set_ylabel(kwdOpts["ylabel"])

        title = kwdOpts.get("title",None)
        if  title is not None :
           self.currSub.set_title(title)

        if "yscale" in kwdOpts:
           self.currSub.set_yscale(kwdOpts["yscale"])

        self._doLineAttrs(kwdOpts)

        # sets our legend for our graph.
        if cols is None:
            cols= self.df.columns

        if kwdOpts.get("legend", None):
           self.currSub.legend(cols,loc='best') ;

    def _doLineAttrs(self,kwdOpts):
        """ handle keyword parameters pertaining to lines
            - linestyles are documented at:
               https://matplotlib.org/stable/gallery/lines_bars_and_markers/linestyles.html
            - markers at
              https://matplotlib.org/stable/api/markers_api.html#module-matplotlib.markers

        """
        def assignOpt( kwdOpts, clab, l):
            def memoDiagnose(copDir, diagn):
                "TBD: This function should move to a library and be tested"
                diagnHash = hash( (clab, frozenset(copDir.keys())) )
                if diagnHash not in self.diagnosticsHash:
                    print(diagn, file = sys.stderr)
                    self.diagnosticsHash[diagnHash]=1
                else:
                    self.diagnosticsHash[diagnHash] += 1

            if 'colOpts' in kwdOpts:
                copDir =  kwdOpts['colOpts']
                if ( isinstance(copDir, dict)
                     and any(map(lambda x: len(x)==0, copDir.values()))):
                    memoDiagnose(copDir, "Not a good idea to have empty colOpts entries")
                    return

                if  clab in  copDir:
                     PLT.setp(l,  ** copDir[clab])
                else:
                    memoDiagnose(copDir,
                                 f"In {type(self)}._doLineAttrs.assignOpt({type(clab)})"
                                 + f"\n\t{clab} not in {copDir.keys()}")

        cols = self.df.columns
        if self.lines is None:
            pass
        elif isinstance(self.lines,dict):
            for k in self.lines.keys():
                l = self.lines[k]
                assignOpt( kwdOpts, k , l)
        else:
            count = -1
            for l in self.lines:
                count += 1
                #p = PLT.getp(l, 'label')
                clab =    cols[count]
                assignOpt( kwdOpts, clab, l)

    def doPlot(self, df=None,  colOpts = {}, **kwdOpts):
        self. _setDf(df)
        if self.df is None:
            raise RuntimeError("By now you must have given me a DataFrame")
        self.preparePlot()
        colSel = self.df.columns

        postAttribs = ("yscale",)
        for c in colSel:
               if c in colOpts:
                    optd  = { k:v for (k,v) in colOpts[c].items() if k not in postAttribs}
                    poptd = { k:v for (k,v) in colOpts[c].items() if k  in postAttribs}
               else:
                    optd  = {}
                    poptd = {}

        self._setSubplot()
        self.lines = self.currSub.plot(self.df,**optd);
        self._plotKwd(kwdOpts)
        self._plotKwd(poptd)

    def doPlotBycol(self, df=None, colSel=None, colOpts = {}, **kwdOpts):
        self._setDf(df)
        self._setSubplot()
        if self.df is None:
            raise RuntimeError("By now you must have given me a DataFrame")

        self.preparePlot()
        if colSel is None:
           colSel = self.df.columns
        self.colSel = colSel

        chk = set(colSel)-set(self.df.columns)
        if len(chk)>0:
            raise RuntimeError(f"Unexpected col names in colSel={chk}")

        self.lines={}
        for c in colSel:
               if c in colOpts:
                    optd = colOpts[c]
               else:
                    optd = {}
               l = self.currSub.plot(self.df.loc[:,c], **optd);
               self.lines[c]=l
        self._plotKwd(kwdOpts, cols=colSel)

    def  preparePlot(self):
        pass

class  figureTSFromFrame(figureFromFrame):
    """Make a figure from a time series from a DataFrame;
          it is expected that the row index are dates in string.
          These are converted into the elapsed days from start of table, and represented
          in DateTime format.

          Keywords listed in defaultOpts are honored;
          - keyword 'dateTranslate' permits to iron out date format inconsistencies,
                      like when I found in loaded data an index:
                      "..., '2020-06-28', '2020-06-29', '27/06/2020', '28/06/2020', ...".

         Note that subplot spacing can be further adjusted by
         calling 'plt.subplots_adjust' with appropriate parameters,
         this can be done after figure generation.

    """
    defaultOpts = {"dateFmt":'%Y-%m-%d',
                   "dateTranslate": True}
    def __init__(self, df, **kwdOpts):
        figureFromFrame.__init__(self, df, **kwdOpts)
        setDefaults(self.optd, kwdOpts, figureTSFromFrame.defaultOpts)

    def  preparePlot(self):
        self._dtToElapsed()

    def _dtToElapsed(self):
        self.df.origIndex = self.df.index
        if self.optd["dateTranslate"]:
           trDates= list( map (  figureTSFromFrame._dateTranslator,  self.df.index ))
        else:
            trDates = self.df.index

        self.dt = PAN.to_datetime(trDates, format=self.optd["dateFmt"]  )
        self.elapsedDays = self.dt - self.dt[0]
        self.df.index = self.elapsedDays.days

    dateTranslatorRegexp = re.compile("^(\d{2})/(\d{2})/(\d{4})$")
    def _dateTranslator(dte):
        """ This is used to mitigate data format inconsistencies which have been found in
            practice, .... a more sophisticated scheme will be put in place in case such
            things continue to pop up.
        """
        try:
            mobj =  figureTSFromFrame. dateTranslatorRegexp.match(dte)
            if mobj:
               mg = mobj.groups()
               return mg[2] + "-" + mg[1] + "-" + mg[0]
            else:
                return dte
        except Exception as err:
            print(f"Unable to translate date {type(dte)}{dte}", file=sys.stderr)
            raise err

# Two examples of using this class are given below:
figureTSFromFrame.examples = """

##  Output and more details at https://github.com/AlainLich/COVID-Data

##  ------------------------------------------------------------  Example 2
##  painter = figureTSFromFrame(dm)
##  colOpts = {'dc_F': {"c":"r","marker":"v"},
##             'dc_M': {"c":"b","marker":"v"},
##             'rea_F': {"c":"r","marker":"o", "linestyle":"--"},
##             'rea_M': {"c":"b","marker":"o", "linestyle":"--"},
##             'rad_F': {"marker":"+"},
##             'rad_M': {"marker":"+"}
##            }
##  painter.doPlotBycol()
##  painter.setAttrs(colOpts = colOpts,
##                      xlabel  = f"Days since {painter.dt[0]}",
##                      title="Whole France\ / Hospital\n Male....",
##                 legend=True    )
##  display(meta_Hosp[[ "Colonne","Description_EN" ]])
##  ImgMgr.save_fig("FIG004")
##
##  ------------------------------------------------------------  Example 2
##  colOpts = {'dc':  {"c":"b","marker":"v"},
##             'rea': {"c":"r","marker":"o", "linestyle":"--"},
##             'rad':  {"marker":"^"},
##             'hosp': {"marker":"+"}
##            }
##
##  painter = figureTSFromFrame(None, subplots=subnodeSpec, figsize=(15,15))
##  for i in range(len(levAge)):
##      cat = ageClasses[i]
##      if cat < 90:
##          title = f"Age {cat-9}-{cat}"
##      else:
##          title = "Age 90+"
##
##      dfExtract = dhRAg.loc(axis=1)[:,cat]
##      # remove the now redundant information labeled 'cl_age90'
##      dfExtract.columns = dfExtract.columns.levels[0]
##      painter.doPlotBycol(dfExtract);
##      painter.setAttrs(colOpts = colOpts,
##                       xlabel  = f"Days since {painter.dt[0]}",
##                       title   = title,
##                       legend  = True    )
##
##
##      painter.advancePlotIndex()
##
##  PLT.subplots_adjust( bottom=0.1, top=0.9,
##                       wspace=0.4,  hspace=0.4)
##  ImgMgr.save_fig("FIG005")
##  ------------------------------------------------------------  END
"""

def subPlotShape(n,colFirst=True, maxCol=10):
    """This returns the shape for displaying n subwindows in a 2D array presentation
       for now, maxCol works only if colFirst=True.
       Preliminary, to be improved!
    """
    sm1=min( math.floor(math.sqrt(n) + 0.5), maxCol)
    sm2=math.ceil(n/sm1)
    if colFirst:
       return (sm1,sm2)
    else:
        return (sm2,sm1)

class FigFromBase(ABC):
    """
      Make composed figure, in a superposed or separate figures
    """
    def __init__(self,**kwargs):
        defaults = {'singleSubplot' : False,
                    'figsize': (8,4),
                    'title':"**",
                    'Do3d':False
                    }
        self.kwargs = defaults | kwargs
        if  self.kwargs['Do3d']:
           self.fig, ax1 = PLT.subplots(figsize = self.kwargs['figsize'])
           self.ax1 = self.fig.add_subplot(1, 1, 1, projection='3d')
        elif self.kwargs['singleSubplot']:
           self.fig, self.ax1 = PLT.subplots(1,1,figsize=self.kwargs['figsize'])
           self.ax2 = self.ax1
        else:
           self.fig, (self.ax1, self.ax2) = PLT.subplots(1,2,figsize=self.kwargs['figsize'])

    def runAdapter(self,**kwargs):
        if 'adapter' in kwargs:
            kwargs |= kwargs['adapter'](self, **kwargs)
            #print(f"After adapter kwargs.keys={kwargs.keys()}")

        return kwargs

class FigFromRegressionPlot(FigFromBase):
    """
      Makes a figure composed of a scatter map and a regression, either
      in 2 subplots or superposed if keyword arg 'singleSubplot' is True
    """

    def __init__(self,**kwargs):
        """
            Most keyword args can be overriden/complemented in methods
            Keyword args:
             - data: a Panda dataframe
             - xcol (rep. ycol) : name of column designation for x (resp. y) values
             - sizes: vector of sizes for representing the scatter plot markers
             - colors: vector of colors for scatter plot markers
             - robust: (default True) : use a robust fitting method
             - singleSubplot (default True) : superpose  plots
             - adapter: permits to pass a derivative of FigAdapter, which __call__ method
                        will return a dict used to modify or complement kwargs
        """
        defaults = {'robust' : True,
                    'singleSubplot' : True,
                    'figsize': (8,4),
                    'alpha': 0.5,
                    'title':"**FigFromRegression"}

        FigFromBase.__init__(self, ** defaults | kwargs)

    def __call__(self, **kwargs ):
        kwargs = self.kwargs | kwargs
        kwargs = self.runAdapter(**kwargs)

        xcol = kwargs['xcol']
        ycol = kwargs['ycol']
        robust = kwargs['robust']
        sizes = kwargs['sizes']
        colors = kwargs['colors']
        alpha =  kwargs['alpha']
        title = kwargs['title']

        data =  kwargs['data']

        SNS.regplot(data=data, x=xcol, y = ycol, scatter= False, robust=robust,
                    truncate=True, ax=self.ax1)

        plt=data.plot( x=xcol, y=ycol, s= sizes, c=colors, alpha=alpha,
                       kind='scatter',
                       title=title,
                       ax=self.ax2)

class FigFrom3DScatterPlot(FigFromBase):
    """
      Makes a figure as a 3D scatter plot, presenting attributes as color and
      size.
    """

    def __init__(self,**kwargs):
        """
            Most keyword args can be overriden/complemented in methods
            Keyword args:
             - data: a Panda dataframe
             - xcol (rep. ycol, zcol) : name of column designation for x (resp. y, z) values
             - sizes: vector of sizes for representing the scatter plot markers
             - colors: vector of colors for scatter plot markers
             - adapter: permits to pass a derivative of FigAdapter, which __call__ method
                        will return a dict used to modify or complement kwargs
        """
        defaults = {'singleSubplot' : True,
                    'figsize': (8,4),
                    'alpha': 0.5,
                    'title':None,
                    'Do3d':True}

        FigFromBase.__init__(self, ** defaults | kwargs)

    def __call__(self, **kwargs ):
        kwargs = self.kwargs | kwargs
        kwargs = self.runAdapter(**kwargs)

        xcol = kwargs['xcol']
        ycol = kwargs['ycol']
        zcol = kwargs['zcol']
        xlabel = kwargs.get('xlabel', 'x')
        ylabel = kwargs.get('ylabel', 'y')
        zlabel = kwargs.get('zlabel', 'z')

        data = kwargs['data']

        x=data.loc[:, xcol]
        y=data.loc[:, ycol]
        z=data.loc[:, zcol]

        sizes = kwargs['sizes']
        colors = kwargs['colors']
        alpha =  kwargs['alpha']
        title = kwargs['title']

        print(f"type colors:{type(colors)}", file=sys.stderr)

        self.ax1.scatter(x, y, z, c = colors, s = sizes, marker="o")

        self.ax1.set_xlabel(xlabel)
        self.ax1.set_ylabel(ylabel)
        self.ax1.set_zlabel(zlabel)

        if title is not None:
            self.ax1.set_title(title)

class FigAdapter(ABC):
    """
     Adapter class for FigFromRegressionPlot

     Keyword arguments:
         scaler: apply  preprocessor scaling to input data, the scaled data is only used
                 in adapter.
                 values: None (default) : no scaling
                         "standard"     : apply StandardScaler from sklearn.preprocessing

    """
    def __init__(self, **kwargs):
        self.kwargs = kwargs

    def __call__(self, figObj, figArgDict):
        return {}

    def dfNormalize(self, df):
        scalerSpec = self.kwargs.get("scaler", None)
        if scalerSpec is None:
            return df
        elif scalerSpec == "standard":
            scaler = SKPREPRO.StandardScaler()
            dfNorm = PAN.DataFrame(scaler.fit_transform(df.copy()))
            print (f"In {type(self)}.dfNormalize"+
                   f"returning\n{dfNorm.describe()}", file = sys.stderr)
            return dfNorm
        else:
            raise NotImplementedError(f"Bad scaler spec:{scalerSpec}")

class FigAdapter_KMeans(FigAdapter):
    """
     Adapter class for FigFromRegressionPlot, supporting data preparation by
     kmeans clustering

     Attributes: the following attributes are externally visible/usable
         kmeans : an sklearn.cluster.KMeans object, fit after the __call__ method's
                  execution
         kolors : proposed colors from colormap, based on values in self.k_means.labels_
                  whereas the colormap conforms to the parameter passed to __call__
         kwargs:  kwargs passed at class initialization, possibly modified henceforth
         k_means_fit : if True, the adapter will not fit, this means that the fit has been
                  made; this permits to (re)use an already fit adapter, or
                  by setting to False to cause a new fit. It is also possible that several
                  figures share an adapter, to display multiple aspects of the data.
                  ** TBD ** see if a more general is_fit attribute should be initialized
                            in __init__
         scaler: see in base class
    """
    def __init__(self, **kwargs):
        defaults = {
            'nbClusters':4,
            }
        FigAdapter.__init__(self,**( defaults|kwargs))
        self.k_means = None
        self.k_means_fit = False

    def __call__(self, figObj, **figArgDict):
        """
          kwargs:
            - figObj : a FigFromRegressionPlot object, the dataframe is extracted
                        by key 'data'
            - clusterCols : dataframe columns to be used for clustering
            - colormap : colormap to be used, defaults to 'brg' (see matplotlib colormaps)
        """
        print(f"figObj.kwargs['data'].shape = {figObj.kwargs['data'].shape}",
              file=sys.stderr)
        print(f"figArgDict keys={figArgDict.keys}", file= sys.stderr)

        df =self.dfNormalize( figObj.kwargs['data'])

        clusterCols = figArgDict.get('clusterCols',  df.columns)
        colormap = figArgDict.get('colormap')
        if clusterCols is None:
            raise RuntimeError("No default or value provided for clusterCols")
        if colormap is None:
            colormap = CM.get_cmap('brg', 32)

        if self.k_means is  None:
            nbClusters = self.kwargs['nbClusters']
            self.k_means = cluster.KMeans(n_clusters = nbClusters)

        dfExtract = df.loc[:,clusterCols]
        if not self.k_means_fit:
            if 'fitData' in self.kwargs:
                fitData = self.kwargs['fitData']
            else:
                print(f"Using all data for fitting, shape={df.shape}", file=sys.stderr)
                fitData = df

            self.k_means.fit(fitData)
            print(f"In {type(self)}.__call__: fitted j  KMeans classifier",
                      file=sys.stderr  )

            # "colors" keyword
            colors = figArgDict.get("colors",None)
            if colors is None:
                self.kolors=colormap((1+self.k_means.labels_)/(nbClusters+3))
            elif isinstance(colors, Callable):
                self.kolors=colors(self.k_means.labels_)
            else:
                raise RuntimeError(f"Wrong type for colors keyword arg:{type(colors)}")

            # "sizes" keyword
            sizes = figArgDict.get("sizes",None)
            if sizes is None:
                sizes = 30
            elif isinstance(sizes, Callable):
                sizes =sizes(self.k_means.labels_)
            elif isinstance(sizes, Iterable):
                pass
            else:
                raise RuntimeError(f"Wrong type for sizes keyword arg:{type(sizes)}")

        return {'sizes' : sizes,
                'colors': self.kolors
                }


import csv
import json
import os
from datetime import datetime, date
from os.path import join
from typing import List

from service.const import IN_PATH, OUT_PATH
from service.logging import log
from service.schema import PersonScheme, FlightScheme, FileDataSceme

@log("Данные из названия файла получены")
def get_data_from_filename(
        csv_path: str
) -> (str, int, date):
    """Вытаскивает информацию из названия файла, валидирует и упаковывает"""
    name_data = os.path.splitext(csv_path)[0].split('_')
    dep = name_data[2]
    flt = name_data[1]
    dt = datetime.strptime(name_data[0], '%Y%m%d').date()
    output = FileDataSceme(dep=dep, flt=flt, dt=dt)
    return output

@log("Информация из файла получена")
def get_persons_data_from_csv(
        csv_path: str
) -> List[PersonScheme]:
    """Вытаскивает информацию из тела файла, валидирует и упаковывает"""
    persons = []
    with open(join(IN_PATH, csv_path), 'r') as csvfile:
        reader = csv.DictReader(csvfile, delimiter=';')
        for row in reader:
            try:
                bdate = datetime.strptime(row.get('bdate'), '%d%b%y').date()
            except TypeError:
                raise ValueError("не указан день рождения пассажира")
            persons.append(
                PersonScheme(
                    bdate=bdate.isoformat(), num=row.get('num'),
                    surname=row.get('surname'), firstname=row.get('firstname')
                )
            )
    return persons

@log("Информация записана в json")
def write_output_data_to_json_file(
        csv_path: str,
        data: FlightScheme
) -> None:
    """Записывает json в одну строку"""
    file_path = join(OUT_PATH, os.path.splitext(csv_path)[0] + '.json')
    is_exist = os.path.exists(OUT_PATH)
    if not is_exist:
        os.makedirs(OUT_PATH)
    with open(file_path, 'w') as j:
        j.write(data.json())

@log("Информация записана в json")
def write_pretty_output_data_to_json_file(
        csv_path: str,
        data: FlightScheme
) -> None:
    """Записывает json красиво и удобно для прочтения людьми"""
    file_path = join(OUT_PATH, os.path.splitext(csv_path)[0] + '.json')
    is_exist = os.path.exists(OUT_PATH)
    if not is_exist:
        os.makedirs(OUT_PATH)
    with open(file_path, 'w') as j:
        json_data = data.dict()
        json.dump(json_data, j, indent=4)


def shift(number):
    return [number[-1]] + number[:-1]

def toNumber(numList):
    strList = [str(x) for x in numList]
    strList = int("".join(strList))
    return strList

def rotate(num):
    originalNum = num
    rotations = []
    numList = [int(x) for x in str(num)]
    for i in range(len(numList)-1):
        numList = shift(numList)
        rotations.append(toNumber(numList))
    return rotations

def checkIfPrime(num):
    prime = True
    if num > 1:
        upperValue = int(num ** 0.5) + 1
        for i in range(2,upperValue):
            if num % i == 0:
                prime = False
    else:
        prime = False
    return prime

def createPrimeList(num):
    primeNumbers = []
    lastNumber = 0
    count = 2

    while True:
        if count > num:
            break
        if checkIfPrime(count):
            primeNumbers.append(count)
        count += 1
        print(len(primeNumbers))

    return primeNumbers

primeNumbers = createPrimeList(1000000)

circularPrimes = []

for primeNum in primeNumbers:
    if primeNum < 10:
        circularPrimes.append(primeNum)
    else:
        rotations = rotate(primeNum)
        circular = True
        for rotation in rotations:
            if not checkIfPrime(rotation):
                circular = False
        if circular:
            circularPrimes.append(primeNum)

print(len(circularPrimes))


# scrape hackernews.com
# by number of votes

# using the library - 'beautiful soup"

import requests  # allows us initially to download the html
from bs4 import BeautifulSoup  # allows to use html and grab the data - in obj parser
import pprint  # print pretty

res = requests.get('https://news.ycombinator.com/news')
res2 = requests.get('https://news.ycombinator.com/news?p=2')
soup = BeautifulSoup(res.text, 'html.parser')
soup2 = BeautifulSoup(res2.text, 'html.parser')
links = soup.select('.titleline>a')  # using css selectors
subtext = soup.select('.subtext')
links2 = soup2.select('.titleline>a')  # using css selectors
subtext2 = soup2.select('.subtext')
# print(votes[0].get('id'))

mega_links = links+links2
mega_subtext = subtext + subtext2

def sort_stories_by_votes(hnlist):
    # sort the dictionary using lambda function
    return sorted(hnlist, key=lambda k: k['votes'], reverse=True)

def create_custom_hn(links, subtext):
    hn = []
    for idx, item in enumerate(links):
        title = item.getText()
        # None a s a default if no link found
        href = item.get('href', None)
        vote = subtext[idx].select('.score')
        if len(vote):
            points = int(vote[0].getText().replace(' points', ''))
            if points > int(99):
                hn.append({'title': title, 'link': href, 'votes': points})
    return sort_stories_by_votes(hn)

# pprint.pprint(create_custom_hn(links, subtext))

pprint.pprint(create_custom_hn(mega_links, mega_subtext))
# print(create_custom_hn(links, subtext))


from typing import Dict, List
from datamodel import OrderDepth, TradingState, Order

#this code will not execute any trades. It will just be inputted into the alg and will be used to download the data free of any intervention from our algorithm.
class Trader:
    products = ["DIVING_GEAR"]
    def run(self, state: TradingState) -> Dict[str, List[Order]]:
        """
        Only method required. It takes all buy and sell orders for all symbols as an input,
        and outputs a list of orders to be sent
        """
        # Initialize the method output dict as an empty dict
        result = {}

        # Iterate over all the keys (the available products) contained in the order depths
        skipTimeStamp = True
        for product in self.products:
            timestamp = state.timestamp
            order_depth: OrderDepth = state.order_depths[product]

            if len(order_depth.sell_orders) > 0:
                sell_orders = order_depth.sell_orders
                best_ask = min(order_depth.sell_orders.keys())
                best_ask_volume = order_depth.sell_orders[best_ask]

            if len(order_depth.buy_orders) != 0:
                buy_orders = order_depth.buy_orders
                best_bid = max(order_depth.buy_orders.keys())
                best_bid_volume = order_depth.buy_orders[best_bid]

            spread = best_ask - best_bid
            if skipTimeStamp:
                skipTimeStamp = False
                print(f', {product}, {best_ask}, {best_ask_volume}, {best_bid}, {best_bid_volume}, {spread}')
            else:
                print(f'{timestamp} , {product}, {best_ask}, {best_ask_volume}, {best_bid}, {best_bid_volume}, {spread}')

            print(f'{timestamp}, {state.observations}')

        return result


""" Example for using the SGP30 with CircuitPython and the Adafruit library"""

import time
import busio
import adafruit_sgp30
import board
import neopixel
import adafruit_pm25

pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2, auto_write=False)
i2c_bus = busio.I2C(board.SCL, board.SDA, frequency=100000)

def color_chase_all(color, wait):
    for i in range(10):
        pixels[i] = color
        time.sleep(wait)
        pixels.show()
    time.sleep(0.5)

def color_chase_1(color, idx, wait):
    pixels[idx] = color
    time.sleep(wait)
    pixels.show()
    time.sleep(0.1)

RED = (255, 0, 0)
GREEN = (0, 255, 0)
OFF = (0, 0, 0)

# Create library object on I2C port
sgp30 = adafruit_sgp30.Adafruit_SGP30(i2c_bus)

print("SGP30 serial #", [hex(i) for i in sgp30.serial])

sgp30.iaq_init()
# co2eq_base, tvoc_base = sgp30.baseline_eCO2, sgp30.baseline_TVOC
# sgp30.set_iaq_baseline(co2eq_base, tvoc_base)

elapsed_sec = 0
reset_pin = None
uart = busio.UART(board.TX, board.RX, baudrate=9600)
pm25 = adafruit_pm25.PM25_UART(uart, reset_pin)

while True:
    print("eCO2 = %d ppm \t TVOC = %d ppb" % (sgp30.eCO2, sgp30.TVOC))
    print("Raw H2 = %d \t Raw Ethanol = %d" % (sgp30.H2, sgp30.Ethanol))

    color_chase_1(OFF, 0, 0.1)
    if sgp30.TVOC < 10:
        color_chase_1(RED, 0, 0.1)  # Increase the number to slow down the color chase
    else:
        color_chase_1(GREEN, 0, 0.1)

    time.sleep(1)
    elapsed_sec += 1
    if elapsed_sec > 10:
        elapsed_sec = 0
        print(
            "**** Baseline values: eCO2 = 0x%x, TVOC = 0x%x"
            % (sgp30.baseline_eCO2, sgp30.baseline_TVOC)
        )

    try:
        aqdata = pm25.read()
        # print(aqdata)
    except RuntimeError:
        print("Unable to read from sensor, retrying...")
        continue

    print()
    print("Concentration Units (standard)")
    print("---------------------------------------")
    print(
        "PM 1.0: %d\tPM2.5: %d\tPM10: %d"
        % (aqdata["pm10 standard"], aqdata["pm25 standard"], aqdata["pm100 standard"])
    )
    print("Concentration Units (environmental)")
    print("---------------------------------------")
    print(
        "PM 1.0: %d\tPM2.5: %d\tPM10: %d"
        % (aqdata["pm10 env"], aqdata["pm25 env"], aqdata["pm100 env"])
    )
    print("---------------------------------------")
    print("Particles > 0.3um / 0.1L air:", aqdata["particles 03um"])
    print("Particles > 0.5um / 0.1L air:", aqdata["particles 05um"])
    print("Particles > 1.0um / 0.1L air:", aqdata["particles 10um"])
    print("Particles > 2.5um / 0.1L air:", aqdata["particles 25um"])
    print("Particles > 5.0um / 0.1L air:", aqdata["particles 50um"])
    print("Particles > 10 um / 0.1L air:", aqdata["particles 100um"])
    print("---------------------------------------")

    color_chase_1(OFF, 9, 0.1)
    if aqdata["pm25 standard"] < 50:
        color_chase_1(RED, 9, 0.1)
    else:
        color_chase_1(GREEN, 9, 0.1)