from rclpy.node import Node
from sensor_msgs.msg import Range
from std_msgs.msg import Float32

from rcl_interfaces.msg import SetParametersResult

# from brping import Ping1D
import importlib
module_name = "ping_sonar_ros.ping-python.brping.ping1d"
module = importlib.import_module(module_name)

class Ping1dComponent(Node):
  def __init__(self):
    super().__init__("ping1d_node")
    self.publisher_ = self.create_publisher(Range, "/ping1d/range", 10)
    self.dist_pub_ = self.create_publisher(Float32, "/ping1d/data", 10)
    self.speed_pub_ = self.create_publisher(Float32, "/ping1d/param/speed", 10)
    self.interval_pub_ = self.create_publisher(Float32, "/ping1d/param/interval", 10)
    self.gain_pub_ = self.create_publisher(Float32, "/ping1d/param/gain", 10)
    self.mode_pub_ = self.create_publisher(Float32, "/ping1d/param/mode", 10)
    self.timer_ = self.create_timer(0.1, self.range_callback)

    ### Declare ROS 2 Parameter
    self.declare_parameter('speed', 1450000)  # 1550000 mm/s 1550 m/s
    self.speed_:float = self.get_parameter('speed').value
    self.declare_parameter('interval_num', 100)
    self.interval_num_:float = self.get_parameter('interval_num').value
    self.declare_parameter('gain_num', 1) # int 0 - 6
    self.gain_num_:int = self.get_parameter('gain_num').value
    self.declare_parameter('scan_start', 100) # default 100 [mm] range(30 to 200)
    self.scan_start_:float = self.get_parameter('scan_start').value
    self.declare_parameter('scan_lenght', 3000) # default 2000 [mm] range(2000 to 10000)
    self.scan_lenght_:float = self.get_parameter('scan_lenght').value
    self.declare_parameter('mode_auto', 0) # default 0: manual mode, 1: auto mode
    self.mode_auto_:int = self.get_parameter('mode_auto').value

    self.param_handler_ptr_ = self.add_on_set_parameters_callback(self.set_param_callback)

    ### Make a new Ping
    self.port = "/dev/ttyUSB0"
    self.baudrate = 115200
    self.ping = module.Ping1D()
    self.ping.connect_serial(self.port, self.baudrate)

    if self.ping.initialize() is False:
      print("Failed to initialize Ping!")
      exit(1)

    ### Set Initial parameter
    # self.id = self.ping.get_device_id()
    self.ping.set_speed_of_sound(self.speed_)
    self.ping.set_ping_interval(self.interval_num_)
    self.ping.set_gain_setting(self.gain_num_)
    self.ping.set_range(self.scan_start_, self.scan_lenght_)
    self.ping.set_mode_auto(self.mode_auto_)

  def range_callback(self):
    # distance: Units: mm; The current return distance determined for the most recent acoustic measurement.\n
    # confidence: Units: %; Confidence in the most recent range measurement.\n
    # transmit_duration: Units: us; The acoustic pulse length during acoustic transmission/activation.\n
    # ping_number: The pulse/measurement count since boot.\n
    # scan_start: Units: mm; The beginning of the scan region in mm from the transducer.\n
    # scan_length: Units: mm; The length of the scan region.\n
    # gain_setting: The current gain setting. 0: 0.6, 1: 1.8, 2: 5.5, 3: 12.9, 4: 30.2, 5: 66.1, 6: 144\n
    ### Comment or Uncomment below
    # data = self.ping.get_distance()
    # print("data:%d\n", data)

    # distance: Units: mm; Distance to the target.\n
    # confidence: Units: %; Confidence in the distance measurement.\n
    simple_data = self.ping.get_distance_simple()
    # print("simple data:%d\n", simple_data)

    # scan_start: Units: mm; The beginning of the scan range in mm from the transducer.\n
    # scan_length: Units: mm; The length of the scan range.\n
    range_data = self.ping.get_range()
    # print("scan_start: %s\tscan_length: %s " % (range_data["scan_start"], range_data["scan_length"]))

    # gain_setting: The current gain setting. 0: 0.6, 1: 1.8, 2: 5.5, 3: 12.9, 4: 30.2, 5: 66.1, 6: 144\n
    gain = self.ping.get_gain_setting()
    # print("gain:%d\n", gain)

    # speed_of_sound: Units: mm/s; The speed of sound in the measurement medium. ~1,500,000 mm/s for water.\n
    speed_sound = self.ping.get_speed_of_sound()
    # print("speed_of_sound: %s\n" % (speed_sound["speed_of_sound"]))

    # firmware_version_major: Firmware major version.\n
    # firmware_version_minor: Firmware minor version.\n
    # voltage_5: Units: mV; Device supply voltage.\n
    # ping_interval: Units: ms; The interval between acoustic measurements.\n
    # gain_setting: The current gain setting. 0: 0.6, 1: 1.8, 2: 5.5, 3: 12.9, 4: 30.2, 5: 66.1, 6: 144\n
    # mode_auto: The current operating mode of the device. 0: manual mode, 1: auto mode\n
    ### Comment or Uncomment below
    # general = self.ping.get_general_info()
    # print("general:%d\n", general)

    # ping_interval: Units: ms; The minimum interval between acoustic measurements. The actual interval may be longer.\n
    interval = self.ping.get_ping_interval()
    # print("interval:%d\n", interval)

    mode_auto = self.ping.get_mode_auto()
    # print("mode_auto:%d\n", mode_auto)

    ### ROS 2 data publisher
    range_msg = Range()
    range_msg.header.stamp = self.get_clock().now().to_msg()
    range_msg.header.frame_id = "range_link"
    range_msg.radiation_type = Range.ULTRASOUND
    range_msg.field_of_view = 0.1 # [rad]
    range_msg.min_range = float(range_data["scan_start"]/1000) # [m]
    range_msg.max_range = float(range_data["scan_length"]/1000) # [m]
    range_msg.range = float(simple_data["distance"]/1000) # [m]
    self.publisher_.publish(range_msg)
    self.get_logger().info("Publishing range: {}".format(range_msg.range))

    dist_msg = Float32()
    speed_msg = Float32()
    interval_msg = Float32()
    gain_msg = Float32()
    mode_msg = Float32()
    dist_msg.data = float(simple_data["distance"]/1000)
    speed_msg.data = float(speed_sound["speed_of_sound"]/1000)
    interval_msg.data = float(interval["ping_interval"])
    gain_msg.data = float(gain["gain_setting"])
    mode_msg.data = float(mode_auto["mode_auto"])
    self.dist_pub_.publish(dist_msg)
    self.speed_pub_.publish(speed_msg)
    self.interval_pub_.publish(interval_msg)
    self.gain_pub_.publish(gain_msg)
    self.mode_pub_.publish(mode_msg)

  def set_param_callback(self, params):
        result = SetParametersResult(successful=True)
        for param in params:
            if param.name == 'speed':
                self.speed_ = param.value
                self.get_logger().info('Updated speed value: %f' % self.speed_)
                self.ping.set_speed_of_sound(self.speed_)
            if param.name == 'interval_num':
                self.interval_num_ = param.value
                self.get_logger().info('Updated interval_num value: %f' % self.interval_num_)
                self.ping.set_ping_interval(self.interval_num_)
            if param.name == 'gain_num':
                self.gain_num_ = param.value
                self.get_logger().info('Updated gain_num value: %f' % self.gain_num_)
                self.ping.set_gain_setting(self.gain_num_)
            if param.name == 'scan_start':
                self.scan_start_ = param.value
                self.get_logger().info('Updated scan_start value: %f' % self.scan_start_)
                self.ping.set_range(self.scan_start_, self.scan_lenght_)
            if param.name == 'scan_lenght':
                self.scan_lenght_ = param.value
                self.get_logger().info('Updated scan_lenght value: %f' % self.scan_lenght_)
                self.ping.set_range(self.scan_start_, self.scan_lenght_)
            if param.name == 'mode_auto':
                self.mode_auto_ = param.value
                self.get_logger().info('Updated mode_auto value: %f' % self.mode_auto_)
                self.ping.set_mode_auto(self.mode_auto_)
        return result


import datetime
from datetime import date

from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required

from app import db
from app.invoices.forms import FilterForm, InvoiceForm, ItemForm
from app.models import Company, Invoice, InvoiceType, Item, Roles
from app.utils import roles_required

invoices = Blueprint('invoices', __name__)

@invoices.route('/invoice/create', methods=['GET', 'POST'])
@login_required
@roles_required([Roles.ACCOUNTANT.value])
def create_invoice():
    form = InvoiceForm()

    if request.method == 'GET':
        form.issue_date.data = date.today()  # .strftime('%Y-%m-%d')
        form.due_date.data = date.today()

    if form.validate_on_submit():
        company = Company.query.get_or_404(1)  # we have only one company (id 1)
        new_invoice = Invoice(issue_date=form.issue_date.data,
                              due_date=form.due_date.data,
                              payment_form=form.payment_form.data,
                              type=form.type.data,
                              invoice_buyer=form.buyer.data,
                              invoice_author=current_user,
                              invoice_company=company)
        new_invoice.create_serial_number()
        db.session.add(new_invoice)

        total_sum = 0
        for item in form.items.data:
            new_item = Item(**item)
            new_item.total_price = new_item.count * new_item.price
            total_sum += new_item.total_price
            db.session.add(new_item)
            new_invoice.items.append(new_item)

        new_invoice.total_sum = total_sum
        db.session.commit()
        flash('Your invoice has been created!', 'success')
        return redirect(url_for('invoices.invoice', invoice_id=new_invoice.id))

    return render_template('create_invoice.html', title='Create Invoice', form=form)

@invoices.route('/invoice/<int:invoice_id>', methods=['GET'])
@login_required
@roles_required([Roles.ACCOUNTANT.value])
def invoice(invoice_id):
    """Show the details of a invoice"""
    bill = Invoice.query.get_or_404(invoice_id)
    return render_template('invoice.html', invoice=bill)

@invoices.route('/invoice', methods=['GET', 'POST'])
@login_required
@roles_required([Roles.ACCOUNTANT.value])
def search_invoices():
    search = FilterForm()
    if request.method == 'POST':
        return list_invoices()
    return render_template('search_invoices.html', filter=search)

@invoices.route('/invoice/search', methods=['POST'])
@login_required
@roles_required([Roles.ACCOUNTANT.value])
def list_invoices():
    def _filter(q, it):
        """Filter Query by Invoice Type.

        :param q: SQLAlchemy Query
        :param it: Invoice Type
        :return: List of Invoices in the filtered Query
        """
        if it == InvoiceType.All.value[0]:  # it == 'All'
            q = q.order_by(Invoice.id.desc())
        else:
            q = q.filter(Invoice.type == it) \
                .order_by(Invoice.id.desc())
        return q.all()

    search = request.form

    date_from = search['date_from']
    date_till = search['date_till']

    if date_from:
        date_from = datetime.datetime.strptime(search['date_from'], '%Y-%m-%d')
    if date_till:
        date_till = datetime.datetime.strptime(search['date_till'], '%Y-%m-%d')
    invoice_type = int(search['invoice_type'])

    query = Invoice.query

    if not date_from and not date_till:  # no dates
        results = _filter(query, invoice_type)
    elif date_from and not date_till:  # date_from only
        query = query.filter(date_from <= Invoice.issue_date)
        results = _filter(query, invoice_type)
    elif not date_from and date_till:  # date_till only
        query = query.filter(date_till <= Invoice.issue_date)
        results = _filter(query, invoice_type)
    else:  # both dates
        query = query \
            .filter(date_from <= Invoice.issue_date) \
            .filter(date_till >= Invoice.issue_date)
        results = _filter(query, invoice_type)

    if not results:
        flash('No results found!', 'warning')
        return redirect(url_for('invoices.search_invoices'))
    else:
        # display results
        return render_template('list_invoices.html', invoices=results)

@invoices.route('/invoice/<int:invoice_id>/update', methods=['GET', 'POST'])
@login_required
@roles_required([Roles.ACCOUNTANT.value])
def update_invoice(invoice_id):
    current_invoice: Invoice = Invoice.query.get_or_404(invoice_id)
    form = InvoiceForm(request.form)
    if form.validate_on_submit():
        current_invoice.issue_date = form.issue_date.data
        current_invoice.due_date = form.due_date.data
        current_invoice.payment_form = form.payment_form.data
        current_invoice.type = form.type.data
        current_invoice.invoice_buyer = form.buyer.data

        for item in current_invoice.items:
            Item.query.filter_by(id=item.id).delete()

        total_sum = 0
        for item in form.items.data:
            new_item = Item(**item)
            new_item.total_price = new_item.count * new_item.price
            total_sum += new_item.total_price
            db.session.add(new_item)
            current_invoice.items.append(new_item)

        current_invoice.total_sum = total_sum

        db.session.commit()
        flash('Your invoice has been updated!', 'success')
        return redirect(url_for('invoices.invoice', invoice_id=invoice_id))
    elif request.method == 'GET':
        form.issue_date.data = current_invoice.issue_date
        form.due_date.data = current_invoice.due_date
        form.payment_form.data = current_invoice.payment_form
        form.type.data = current_invoice.type
        form.buyer.data = current_invoice.invoice_buyer

        current_item: Item
        for current_item in current_invoice.items:
            item = ItemForm()
            item.desc = current_item.desc
            item.count = current_item.count
            item.price = current_item.price
            item.unit = current_item.unit
            item.vat = current_item.vat

            form.items.append_entry(item)

    return render_template('create_invoice.html', title='Update Invoice', form=form)

@invoices.route('/invoice/<int:invoice_id>/delete', methods=['POST'])
@login_required
@roles_required([Roles.ACCOUNTANT.value])
def delete_invoice(invoice_id):
    bill = Invoice.query.get_or_404(invoice_id)
    db.session.delete(bill)
    db.session.commit()
    flash('Your post has been deleted!', 'success')
    return redirect(url_for('invoices.search_invoices'))


import re
import time

from bs4 import BeautifulSoup
import requests
import pandas as pd
import streamlit as st
import matplotlib.pyplot as plt
import seaborn as sns
import streamlit.components.v1 as components

st.title('Dream job Finder')
st.write('<style>footer{visibility: hidden;}</style>', unsafe_allow_html=True)

job_name = st.text_input('Enter your dream job', placeholder='for ex: data analyst')
job_name = job_name.lower().replace(' ', '-')
baseURL = 'https://www.reed.co.uk'
jobs_baseURL = f'{baseURL}/jobs/{job_name}-jobs'

response = requests.get(jobs_baseURL)
# print(response)

soup = BeautifulSoup(response.text, "html.parser")
job_cards = soup.find_all("article", class_=re.compile('job-result'))

columns = ['Title', 'Posted-On', 'Company', 'Salary', 'Min Salary', 'Max Salary', 'Salary based on', 'Location',
           'Remote/Office', 'Type', 'Time', 'More Info']
job_df = pd.DataFrame(data=None, columns=columns)

def get_min_max_salary(salary_text, term):
    if len(salary_text.split('-')) == 2:
        minsalary = salary_text.split('-')[0].strip()
        maxsalary = salary_text.split('-')[1].split(term)[0].strip()
    else:
        minsalary = salary_text.split(term)[0].strip()
        maxsalary = salary_text.split(term)[0].strip()
    return minsalary, maxsalary

for i, job_card in enumerate(job_cards):
    job_title = job_card.find("h3", class_='title').a
    job_posted_by = job_card.find("div", class_='posted-by')
    job_salary = job_card.find("li", class_="salary")
    job_location = job_card.find("li", class_="location")
    job_remote = job_card.find("li", class_="remote")
    job_time = job_card.find("li", class_="time")

    job_title_text = job_title if job_title is None else job_title.get_text().strip()
    job_posted_by_text = job_posted_by if job_posted_by is None else job_posted_by.get_text().strip()
    job_posted_by_text = job_posted_by_text.split('by')[0].split('Posted')[1].strip()
    job_company_text = job_posted_by if job_posted_by is None else job_posted_by.a.get_text().strip()
    job_salary_text = job_salary if job_salary is None else job_salary.get_text().strip()
    job_location_text = job_location if job_location is None else job_location.get_text().strip()
    job_location_text = job_location_text.split('\n')[0].strip()
    job_remote_text = job_remote if job_remote is None else job_remote.get_text().strip()
    job_time_text = job_time if job_time is None else job_time.get_text().strip()
    job_type_text = job_time_text if job_time_text is None else job_time_text.split(',')[0].strip()
    job_time_text = job_time_text if job_time_text is None else job_time_text.split(',')[1].strip()

    job_moreinfo_link = baseURL + job_title['href'] if job_title['href'].startswith('/') else job_title['href']

    if 'per day' in job_salary_text:
        salary_based_on = 'per day'
        min_salary, max_salary = get_min_max_salary(job_salary_text, salary_based_on)
    elif 'per annum' in job_salary_text:
        salary_based_on = 'per annum'
        min_salary, max_salary = get_min_max_salary(job_salary_text, salary_based_on)
    elif 'per hour' in job_salary_text:
        salary_based_on = 'per hour'
        min_salary, max_salary = get_min_max_salary(job_salary_text, salary_based_on)
    else:
        # this is for competitive/ Salary negotiable text for salary
        min_salary = None
        max_salary = None
        salary_based_on = None

    list_df = [job_title_text, job_posted_by_text, job_company_text, job_salary_text, min_salary, max_salary,
               salary_based_on, job_location_text, job_remote_text, job_type_text, job_time_text, job_moreinfo_link]
    # temp_df = pd.DataFrame([list_df], columns=columns)
    # job_df = job_df.append(temp_df, ignore_index=True)

    job_df.loc[i, :] = list_df

# print(job_df.head())

job_df_copy = job_df.copy()
job_df_copy['Remote/Office'] = job_df_copy['Remote/Office'].fillna('Work from Office')

# st.dataframe(job_df_copy)
# number of columns having null values
# st.write(job_df_copy.isna().sum())

job_df_copy.dropna(inplace=True)
job_df_copy.drop(columns=['Posted-On', 'Salary'], inplace=True)

job_df_copy['Min Salary'] = job_df_copy['Min Salary'].apply(lambda x: x[1:].replace(',', '')).astype(float)

job_df_copy['Max Salary'] = job_df_copy['Max Salary'].apply(lambda x: x[1:].replace(',', '')).astype(float)

job_df_copy['Mean Salary'] = (job_df_copy['Min Salary'] + job_df_copy['Max Salary']) / 2
job_df_copy[['Min Salary', 'Max Salary', 'Mean Salary']] = job_df_copy[
    ['Min Salary', 'Max Salary', 'Mean Salary']].astype(int)

st.write(job_df_copy['Min Salary'].mean(), job_df_copy['Max Salary'].mean(),
         (job_df_copy['Min Salary'].mean() + job_df_copy['Max Salary'].mean()) / 2, job_df_copy['Mean Salary'].mean())
st.dataframe(job_df_copy)

col1, col2, col3, col4 = st.columns(4)
with col1:
    st.metric(label='Total Jobs', value=job_df_copy.shape[0])
with col2:
    st.metric(label='Max Salary per annum',
              value=job_df_copy.loc[job_df_copy['Salary based on'].isin(['per annum'])]['Max Salary'].max())
with col3:
    st.metric(label='Max Salary per day',
              value=job_df_copy.loc[job_df_copy['Salary based on'].isin(['per day'])]['Max Salary'].max())
with col4:
    st.metric(label='Max Salary per hour',
              value=job_df_copy.loc[job_df_copy['Salary based on'].isin(['per hour'])]['Max Salary'].max())

fig = plt.figure(figsize=(10, 3))
plt.title('Type vs Remote/Office')
sns.countplot(y='Type', data=job_df_copy, hue='Remote/Office')
st.pyplot(fig)

fig = plt.figure(figsize=(10, 3))
plt.title('Type vs Salary based on')
sns.countplot(y='Type', data=job_df_copy, hue='Salary based on')
st.pyplot(fig)

fig = plt.figure(figsize=(10, 3))
plt.title('Type vs Location')
plt.xticks(rotation=90)
sns.countplot(hue='Type', data=job_df_copy, x='Location')
st.pyplot(fig)

fig = plt.figure(figsize=(10, 3))
plt.title('Salary based on vs Location')
plt.xticks(rotation=90)
sns.countplot(hue='Salary based on', data=job_df_copy, x='Location')
st.pyplot(fig)

# fig = plt.figure(figsize=(10, 3))
# plt.title('Type vs Remote/Office')
# sns.barplot(x='Max Salary',y='Location', data=job_df_copy)
# st.pyplot(fig)

# per_annum_salary = job_df_copy[['Location', 'Mean Salary', 'Salary based on']].groupby('Salary based on')
# st.write(per_annum_salary.mean())
st.dataframe(job_df_copy['Location'].value_counts(sort=False))

data_Mean = job_df_copy[job_df_copy['Salary based on'].isin(['per annum'])].groupby('Location')
st.write(data_Mean.mean().sort_values(by='Mean Salary'))
data_Mean = data_Mean.mean().sort_values(by='Mean Salary')
data_Mean = data_Mean.join(job_df_copy['Location'].value_counts())
data_Mean.rename(columns={'Location': 'No of Jobs'}, inplace=True)

data_Mean.sort_values(by='No of Jobs', inplace=True, ascending=False)
data_Mean.reset_index(inplace=True)
data_Mean
# pd.merge(data_Mean, job_df_copy['Location'].value_counts(), on = "Location", how = "left")


import jax.numpy as jnp
import pytest

from moll.metrics import euclidean

from .._online_add import (
    _add_point,
    _finalize_updates,
    _needless_point_idx,
    update_points,
)

# Test finalize_updates

@pytest.mark.parametrize(
    "array, expected",
    [
        ([-1], [-1]),
        ([2], [2]),
        ([-1, -1, -1], [-1, -1, -1]),
        ([3, 3, 3], [-1, -1, 3]),
        ([1, 2, 3], [1, 2, 3]),
        ([1, 1, 2, 2, 3, 3], [-1, 1, -1, 2, -1, 3]),
        ([1, 2, 2, 3, 3, 3], [1, -1, 2, -1, -1, 3]),
        ([3, 2, 1], [3, 2, 1]),
        ([3, 3, -1, 2, 2, -1, 1], [-1, 3, -1, -1, 2, -1, 1]),
    ],
)
def test_finalize_updates(array, expected):
    array = jnp.array(array)
    expected = jnp.array(expected)
    output_array = _finalize_updates(array)
    assert jnp.all(output_array == expected)

# Test needless point search

@pytest.mark.parametrize(
    "array, expected",
    [
        ([0, 0.1, 1], 1),
        ([0, 0, 1], 0),
        ([0, 0, 0, 1], 0),
        ([(0.1, 0.1), (0, 0), (1, 1)], 0),
    ],
)
@pytest.mark.parametrize(
    "dist_fn",
    [
        euclidean,
        lambda x, y: euclidean(x, y) - 10,  # negative distance is ok
    ],
)
def test_find_needless_point(array, expected, dist_fn):
    array = jnp.array(array)
    # exp potential is used to treat negative distances
    idx = _needless_point_idx(array, dist_fn, lambda d: jnp.exp(-d))
    assert idx == expected

# Test add points

@pytest.fixture
def X():
    return jnp.array(
        [
            [0, 0],
            [1, 1],
            [2, 2],
            [3, 3],
            [4, 4],
        ],
        dtype=jnp.float32,
    )

@pytest.mark.parametrize(
    "similarity_fn",
    [
        euclidean,
        lambda x, y: euclidean(x, y) + 10,
        lambda x, y: euclidean(x, y) - 10,
    ],
)
def test_add_point(X, similarity_fn):
    x = jnp.array([4.3, 4.3])
    X_copy = X.copy()
    X_updated, updated_idx = _add_point(
        x=x,
        X=X,
        similarity_fn=similarity_fn,
        potential_fn=lambda d: jnp.exp(-d),
        k_neighbors=5,
        n_valid_points=5,
        threshold=-jnp.inf,
    )
    assert updated_idx >= 0
    assert updated_idx == 4
    assert (X_copy[:4] == X_updated[:4]).all()
    assert (X_updated[4] == x).all()

@pytest.mark.parametrize(
    "xs, acc_mask",
    [
        (
            [[4.3, 4.3], [4.2, 4.2], [4.1, 4.1]],
            [True, False, False],
        ),
        (
            [[4.1, 4.1], [4.2, 4.2], [4.3, 4.3]],
            [False, False, True],
        ),
    ],
)
def test_update_points(X, xs, acc_mask):
    xs = jnp.array(xs)
    acc_mask = jnp.array(acc_mask)
    X_copy = X.copy()

    X_updated, updated_idxs, acceptance_mask, n_appended, n_updated = update_points(
        X=X,
        xs=xs,
        similarity_fn=euclidean,
        potential_fn=lambda d: d**-1,
        k_neighbors=5,
        n_valid=5,
        threshold=0.0,
    )

    assert (acceptance_mask == acc_mask).all()
    assert (X_copy[:3] == X_updated[:3]).all()
    idx = jnp.argmax(acc_mask)
    assert (X_updated[4] == xs[idx]).all()


import os

import click
import pandas as pd
from sklearn.model_selection import train_test_split

@click.command("split")
@click.option("--input_dir")
def split_data(input_dir):
    X = pd.read_csv(os.path.join(input_dir, "data_normalized.csv"))
    y = pd.read_csv(os.path.join(input_dir, "target.csv"))
    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.3, random_state=123)

    X_train.to_csv(os.path.join(input_dir, "train_data.csv"), index=False)
    y_train.to_csv(os.path.join(input_dir, "train_target.csv"), index=False)
    X_val.to_csv(os.path.join(input_dir, "val_data.csv"), index=False)
    y_val.to_csv(os.path.join(input_dir, "val_target.csv"), index=False)

if __name__ == '__main__':
    split_data()


import numpy as np
from scipy.sparse import vstack
from sklearn.preprocessing import OneHotEncoder

FOLDS_COUNT = 5

def read_dataset(n=None):
    xs = []
    ys = []
    i = 0
    with open("dataset.txt") as dataset_file:
        for line in dataset_file:
            if ':' in line:
                current_movie = line.split(":")[0]
            else:
                user_id, raw_mark, _ = line.split(",")
                xs.append((user_id, current_movie))
                ys.append(int(raw_mark))
            if n is not None:
                i += 1
                if i >= n:
                    break
    encoder = OneHotEncoder(categories='auto', sparse=True)
    encoder.fit(xs)
    return encoder.transform(xs), np.array(ys).reshape(-1, 1), encoder

def split_data_to_fold(xs, ys, fold_index):
    fold_size = xs.shape[0] // FOLDS_COUNT

    train_xs = vstack([xs[:fold_index * fold_size, :], xs[fold_size * (fold_index + 1):, :]])
    train_ys = np.vstack([ys[:fold_index * fold_size, :], ys[fold_size * (fold_index + 1):, :]])

    test_xs = xs[fold_index * fold_size:(fold_index + 1) * fold_size]
    test_ys = ys[fold_index * fold_size:(fold_index + 1) * fold_size]

    return train_xs, train_ys, test_xs, test_ys
    # return xs[:fold_size * 4], ys[:fold_size * 4], xs[fold_size * 4:], ys[fold_size * 4:]

def kek(xs, ys, fold_index):
    fold_size = xs.shape[0] // FOLDS_COUNT
    return xs[:, fold_size * 4], ys[:, fold_size * 4], xs[:, fold_size * 4:], ys[:, fold_size * 4:]


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

import tempfile
from itertools import islice
from pathlib import Path
import numpy as np
from tempfile import TemporaryDirectory

import pytest
from crystals import Crystal, Atom, __version__
from crystals.writers import CIF_HEADER

try:
    import ase
except ImportError:
    WITH_ASE = False
else:
    WITH_ASE = True

@pytest.mark.skipif(not WITH_ASE, reason="ASE not installed or importable")
@pytest.mark.parametrize("name", islice(Crystal.builtins, 10))
def test_ase_atoms_construction(name):
    """Test that ase_atoms returns without error"""
    crystal = Crystal.from_database(name)
    to_ase = crystal.to_ase()
    assert len(crystal) == len(to_ase)

@pytest.mark.skipif(not WITH_ASE, reason="ASE not installed or importable")
@pytest.mark.parametrize("name", islice(Crystal.builtins, 10))
def test_ase_atoms_back_and_forth(name):
    """Test conversion to and from ase Atoms"""
    crystal = Crystal.from_database(name)
    to_ase = crystal.to_ase()
    crystal2 = Crystal.from_ase(to_ase)

    # ase has different handling of coordinates which can lead to
    # rounding beyond 1e-3. Therefore, we cannot compare directly sets
    # assertSetEqual(set(crystal), set(crystal2))
    assert len(crystal) == len(crystal2)

@pytest.mark.parametrize("name", Crystal.builtins)
def test_cif_writer_idempotence(name):
    """Test that conversion to CIF of a structure loaded from CIF is idempotent."""
    # Testing on all built-in structure assures us that corner cases
    # are taken care of.
    cryst = Crystal.from_database(name)
    with tempfile.TemporaryDirectory() as temp_dir:
        f = Path(temp_dir) / "temp.cif"
        cryst.to_cif(f)
        cryst2 = Crystal.from_cif(f)
        assert cryst == cryst2

def test_cif_writer_writes_version():
    """Test that the `crystals` version is contained in the CIF header."""
    # See https://github.com/LaurentRDC/crystals/issues/14
    assert f"`crystals` {__version__}" in CIF_HEADER

def test_supercell_preserved_in_cif():
    """See issue #13."""
    a = np.asfarray([3, 0.2, 0])
    b = np.asfarray([0.4, 8, 0])
    c = np.asfarray([0, 0, 9])

    dimer = Crystal(
        unitcell=[Atom("C", coords=(0.5, 0, 0)), Atom("C", coords=(0, 0, 0))],
        lattice_vectors=[a * 2, b, c],
    )
    with TemporaryDirectory() as tmpdir:
        dimer.to_cif(Path(tmpdir) / "dimer.cif")
        from_file = Crystal.from_cif(Path(tmpdir) / "dimer.cif")

    assert set(tuple(atm.coords_fractional) for atm in dimer.unitcell) == set(
        tuple(atm.coords_fractional) for atm in from_file.unitcell
    )

@pytest.mark.parametrize("name", Crystal.builtins)
def test_vasp_writer_idempotence(name):
    """Test that conversion to VASP of a structure loaded from VASP is idempotent."""
    # Testing on all built-in structure assures us that corner cases
    # are taken care of.
    cryst = Crystal.from_database(name)
    with tempfile.TemporaryDirectory() as temp_dir:
        f = Path(temp_dir) / "temp.POSCAR"
        cryst.to_poscar(f)
        cryst2 = Crystal.from_poscar(f)
        assert cryst == cryst2


# To run this code, first edit config.py with your configuration
#
#!/usr/bin/python
# -*- coding: utf-8 -*-
import tweepy
import string

import sqlite3
import time

import config
import sqliteOperations

class MyListener(tweepy.StreamListener):
    """Custom StreamListener for streaming data."""

    def on_data(self, data):
        try:
            sqliteOperations.twitterCreateSqliteTable(data);
            return True
        except BaseException as e:
            config.logger.error("Error on_data: %s" % str(e))
            time.sleep(5)
        return True

    def on_error(self, status):
        config.logger.error(status)
        return True

def startTwitterStreamToDb():
    config.logger.info(config.STEP_1_QUERY)
    auth = tweepy.OAuthHandler(config.CONSUMER_KEY, config.CONSUMER_SECRET)
    auth.set_access_token(config.ACCESS_TOKEN, config.ACCESS_SECRET)
    api = tweepy.API(auth)

    twitter_stream = tweepy.Stream(auth, MyListener())
    twitter_stream.filter(languages=["tr"],track=[config.STEP_1_QUERY])


from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('about/', views.about, name='about'),
    path('travels/', views.travels_index, name='index'),
    path('travels/<int:travel_id>/', views.travels_detail, name='detail'),
    path('travels/create/', views.TravelCreate.as_view(), name='travels_create'),
    path('travels/<int:pk>/update/', views.TravelUpdate.as_view(), name='travels_update'),
    path('travels/<int:pk>/delete/', views.TravelDelete.as_view(), name='travels_delete'),
    path('travels/<int:travel_id>/add_checking/', views.add_checking, name='add_checking'),

    # Checklist Model
    path('checklists/', views.checklists_index, name = 'checklists_index'),
    path('checklists/<int:pk>/', views.ChecklistDetail.as_view(), name='checklists_detail'),
    path('checklists/create/', views.ChecklistCreate.as_view(), name='checklists_create'),
    path('checklists/<int:pk>/update/', views.ChecklistUpdate.as_view(), name='checklists_update'),
    path('checklists/<int:pk>/delete/', views.ChecklistDelete.as_view(), name='checklists_delete'),

    # M:M
    path('travels/<int:travel_id>/assoc_checklist/<int:checklist_id>/', views.assoc_checklist, name='assoc_checklist'),
    path('travels/<int:travel_id>/unassoc_checklist/<int:checklist_id>/', views.unassoc_checklist, name='unassoc_checklist'),

    # Signup URL
    path('account/signup/', views.signup, name='signup')
]


#: All available test module types.

from .internals.modules.modules_l23.module_l23_base import ModuleL23
from .internals.modules.modules_l23.family_d import (
    MOdin1G3S2PT,
    MOdin1G3S6P,
    MOdin1G3S6PE,
    MOdin1G3S6P_b
)
from .internals.modules.modules_l23.family_e import (
    MOdin10G3S2PCU,
    MOdin10G3S6PCU,
    MOdin10G5S6PCU,
    MOdin10G5S6PCU_b,
    MOdin5G4S6PCU,
)
from .internals.modules.modules_l23.family_f import (
    MOdin10G1S12P,
    MOdin10G1S2P,
    MOdin10G1S2P_b,
    MOdin10G1S2P_c,
    MOdin10G1S2P_d,
    MOdin10G1S2PT,
    MOdin10G1S6P,
    MOdin10G1S6P_b,
)
from .internals.modules.modules_l23.family_g import (
    MLoki100G3S1P,
    MLoki100G3S1P_b,
    MLoki100G3S1PSE,
)
from .internals.modules.modules_l23.family_h import MLoki100G5S1P
from .internals.modules.modules_l23.family_i import MLoki100G5S2P
from .internals.modules.modules_l23.family_j import MThor100G5S4P
from .internals.modules.modules_l23.family_k import MThor400G7S1P
from .internals.modules.modules_l23.family_l import (
    MThor400G7S1P_b,
    MThor400G7S1P_c,
    MFreya800G1S1P_a,
    MFreya800G1S1P_b,
    MFreya800G1S1POSFP_a,
    MFreya800G4S1P_a,
    MFreya800G4S1POSFP_a,
)
from .internals.modules.modules_l23.family_m import MOdin1G3S6PT1RJ45
from .internals.modules.modules_l23.family_n import MOdin40G2S2P
from .internals.modules.modules_l23.family_combi import (
    MOdin10G4S2PCombi,
    MOdin10G4S2PCombi_b,
)

from .internals.modules.module_l23ve import ModuleL23VE
from .internals.modules.module_chimera import ModuleChimera
from .internals.modules.module_l47 import ModuleL47
from .internals.modules.module_l47ve import ModuleL47VE

import typing

GenericL23Module = typing.Union[
        "MOdin1G3S6P",
        "MOdin1G3S6P_b",
        "MOdin1G3S6PE",
        "MOdin1G3S2PT",
        "MOdin5G4S6PCU",
        "MOdin10G5S6PCU",
        "MOdin10G5S6PCU_b",
        "MOdin10G3S6PCU",
        "MOdin10G3S2PCU",
        "MOdin10G1S2P",
        "MOdin10G1S2P_b",
        "MOdin10G1S2P_c",
        "MOdin10G1S6P",
        "MOdin10G1S6P_b",
        "MOdin10G1S2PT",
        "MOdin10G1S2P_d",
        "MOdin10G1S12P",
        "MOdin40G2S2P",
        "MLoki100G3S1P",
        "MLoki100G3S1P_b",
        "MLoki100G3S1PSE",
        "MLoki100G5S1P",
        "MLoki100G5S2P",
        "MThor100G5S4P",
        "MThor400G7S1P",
        "MThor400G7S1P_b",
        "MThor400G7S1P_c",
        "MFreya800G1S1P_a",
        "MFreya800G1S1P_b",
        "MFreya800G1S1POSFP_a",
        "MFreya800G4S1P_a",
        "MFreya800G4S1POSFP_a",
        "MOdin1G3S6PT1RJ45",
        "MOdin10G4S2PCombi",
        "MOdin10G4S2PCombi_b",
    ]

GenericAnyModule = typing.Union[
    GenericL23Module,
    "ModuleL23VE",
    "ModuleChimera",
    "ModuleL47",
    "ModuleL47VE",
]

__all__ = (
    "ModuleL23",
    "MOdin1G3S6P",
    "MOdin1G3S6P_b",
    "MOdin1G3S6PE",
    "MOdin1G3S2PT",
    "MOdin5G4S6PCU",
    "MOdin10G5S6PCU",
    "MOdin10G5S6PCU_b",
    "MOdin10G3S6PCU",
    "MOdin10G3S2PCU",
    "MOdin10G1S2P",
    "MOdin10G1S2P_b",
    "MOdin10G1S2P_c",
    "MOdin10G1S6P",
    "MOdin10G1S6P_b",
    "MOdin10G1S2PT",
    "MOdin10G1S2P_d",
    "MOdin10G1S12P",
    "MOdin40G2S2P",
    "MLoki100G3S1P",
    "MLoki100G3S1P_b",
    "MLoki100G3S1PSE",
    "MLoki100G5S1P",
    "MLoki100G5S2P",
    "MThor100G5S4P",
    "MThor400G7S1P",
    "MThor400G7S1P_b",
    "MThor400G7S1P_c",
    "MFreya800G1S1P_a",
    "MFreya800G1S1P_b",
    "MFreya800G1S1POSFP_a",
    "MFreya800G4S1P_a",
    "MFreya800G4S1POSFP_a",
    "MOdin1G3S6PT1RJ45",
    "MOdin10G4S2PCombi",
    "MOdin10G4S2PCombi_b",
    "ModuleL23VE",
    "ModuleChimera",
    "ModuleL47",
    "ModuleL47VE",
    "GenericL23Module",
    "GenericAnyModule",
)


import sqlite3

connection = sqlite3.connect('chapter_6.db')

def create_books_table():
    try:
        cursor = connection.cursor()
        cursor.execute('''CREATE TABLE books
                        (title text, author text, genre text, year integer)''')
        connection.commit()
        print("Table created successfully")
    except sqlite3.OperationalError:
        print("Table already exists")

def seed_books_table():
    try:
        cursor = connection.cursor()
        cursor.execute('''INSERT INTO books VALUES ("The Giver", "Lois Lowry", "young adult", 1993)''')
        cursor.execute('''INSERT INTO books VALUES ("The Handmaid's Tale", "Margaret Atwood", "dystopian", 1985)''')
        cursor.execute('''INSERT INTO books VALUES ("The Hitchhiker's Guide to the Galaxy", "Douglas Adams",
        "comedy", 1979)''')
        connection.commit()
        print("Table seeded successfully")
    except sqlite3.OperationalError:
        print("Unable to seed table")

def create_book():
    title = input("Enter the title of the book: ")
    author = input("Enter the author of the book: ")
    genre = input("Enter the genre of the book: ")
    year = input("Enter the year the book was published: ")
    try:
        cursor = connection.cursor()
        cursor.execute('''INSERT INTO books VALUES (?, ?, ?, ?)''', (title, author, genre, year))
        connection.commit()
        print("Book added successfully")
    except sqlite3.OperationalError:
        print("Unable to add book")

def read_book():
    title = input("Enter the title of the book: ")
    try:
        cursor = connection.cursor()
        cursor.execute('''SELECT * FROM books WHERE title = ?''', (title,))
        book = cursor.fetchone()
        print(book)
    except sqlite3.OperationalError:
        print("Unable to retrieve book")

def update_book():
    title = input("Enter the title of the book: ")
    author = input("Enter the author of the book: ")
    genre = input("Enter the genre of the book: ")
    year = input("Enter the year the book was published: ")
    try:
        cursor = connection.cursor()
        cursor.execute('''UPDATE books SET author = ?, genre = ?, year = ? WHERE title = ?''',
                       (author, genre, year, title))
        connection.commit()
        print("Book updated successfully")
    except sqlite3.OperationalError:
        print("Unable to update book")

def delete_book():
    title = input("Enter the title of the book: ")
    try:
        cursor = connection.cursor()
        cursor.execute('''DELETE FROM books WHERE title = ?''', (title,))
        connection.commit()
        print("Book deleted successfully")
    except sqlite3.OperationalError:
        print("Unable to delete book")

def read_all_books_titles():
    try:
        cursor = connection.cursor()
        cursor.execute('''SELECT title FROM books''')
        books = cursor.fetchall()
        print(books)
    except sqlite3.OperationalError:
        print("Unable to retrieve books")

def select_crud_action():
    print("1. Create a book")
    print("2. Read a book")
    print("3. Read all book")
    print("4. Update a book")
    print("5. Delete a book")
    print("6. Exit")
    return input("What would you like to do? ")

def main():
    while True:
        action = select_crud_action()
        if action == "1":
            create_book()
        elif action == "2":
            read_book()
        elif action == "3":
            read_all_books_titles()
        elif action == "4":
            update_book()
        elif action == "5":
            delete_book()
        elif action == "6":
            break
        else:
            print("Invalid input")
    connection.close()

main()


from asyncio import CancelledError
import logging as lg

from typing import AsyncGenerator

from meow.app.config import conf
from meow.app.instances.databases import dbs
from meow.models.infra.locks import RedisLock

from redis.exceptions import LockError

from meow.models.local.event.final_proceedings.contribution_model import ContributionData
from meow.models.local.event.final_proceedings.proceedings_data_model import FinalProceedingsConfig, ProceedingsData

from meow.services.local.event.final_proceedings.collecting_contributions_and_files import (
    collecting_contributions_and_files)
from meow.services.local.event.final_proceedings.collecting_sessions_and_attachments import (
    collecting_sessions_and_attachments)

from meow.services.local.event.common.adapting_final_proceedings import adapting_final_proceedings
from meow.services.local.event.common.validate_proceedings_data import validate_proceedings_data

from meow.services.local.event.final_proceedings.concat_contribution_papers import concat_contribution_papers
from meow.services.local.event.final_proceedings.copy_contribution_papers import copy_contribution_papers
from meow.services.local.event.final_proceedings.copy_contribution_slides import copy_contribution_slides
from meow.services.local.event.final_proceedings.copy_event_attachments import copy_event_attachments

from meow.services.local.event.final_proceedings.download_contributions_slides import download_contributions_slides
from meow.services.local.event.final_proceedings.download_event_attachments import download_event_attachments
from meow.services.local.event.final_proceedings.download_contributions_papers import download_contributions_papers

from meow.services.local.event.final_proceedings.generate_contribution_references import (
    generate_contribution_references)
from meow.services.local.event.final_proceedings.generate_contributions_groups import generate_contributions_groups
from meow.services.local.event.final_proceedings.generate_contribution_doi import generate_dois
from meow.services.local.event.final_proceedings.build_doi_payloads import build_doi_payloads
from meow.services.local.event.final_proceedings.manage_duplicates import manage_duplicates

from meow.services.local.event.final_proceedings.link_static_site import (
    clean_static_site, link_static_site)
from meow.services.local.event.final_proceedings.read_papers_metadata import read_papers_metadata
from meow.services.local.event.final_proceedings.write_papers_metadata import write_papers_metadata

from meow.services.local.event.final_proceedings.hugo_plugin.hugo_final_proceedings_plugin import (
    HugoFinalProceedingsPlugin)
from meow.models.local.event.final_proceedings.client_log import ClientLog, ClientLogSeverity
from meow.app.errors.service_error import ProceedingsError

logger = lg.getLogger(__name__)

async def event_final_proceedings(event: dict, cookies: dict, settings: dict,
                                  config: FinalProceedingsConfig) -> AsyncGenerator:
    """ """

    try:
        event_id: str = event.get('id', '')

        if not event_id or event_id == '':
            raise BaseException('Invalid event id')

        async with acquire_lock(event_id) as lock:

            logger.debug(f"acquire_lock -> {lock.name}")

            async for r in _event_final_proceedings(event, cookies, settings, config, lock):
                yield r

            logger.debug(f"release_lock -> {lock.name}")

    except GeneratorExit:
        logger.error("Generator Exit")
    except CancelledError:
        logger.error("Task Cancelled")
    except LockError as le:
        logger.error("Lock error", exc_info=True)
        raise le
    except ProceedingsError as pe:
        async for r in handle_proceedings_error(pe):
            yield r
    except BaseException as be:
        logger.error("Generic error", exc_info=True)
        raise be

def acquire_lock(key: str) -> RedisLock:
    """ Create event lock """

    redis_lock = RedisLock(
        redis=dbs.redis_client,
        name=conf.REDIS_EVENT_LOCK_KEY(key),
        timeout=conf.REDIS_LOCK_TIMEOUT_SECONDS,
        sleep=0.5,
        blocking=True,
        blocking_timeout=conf.REDIS_LOCK_BLOCKING_TIMEOUT_SECONDS,
        thread_local=True,
    )

    return redis_lock

async def extend_lock(lock: RedisLock) -> RedisLock:
    """ Reset lock timeout (conf.REDIS_LOCK_TIMEOUT_SECONDS) """

    await lock.reacquire()
    return lock

async def _event_final_proceedings(event: dict, cookies: dict, settings: dict,
                                   config: FinalProceedingsConfig, lock: RedisLock) -> AsyncGenerator:
    """ """

    logger.info('event_final_proceedings - create_final_proceedings')

    """ """

    def filter_contributions_pubblicated(c: ContributionData) -> bool:
        if config.include_only_qa_green_contributions:
            return c.is_included_in_proceedings
        return c.is_included_in_prepress

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='collecting_sessions_and_attachments',
        text="Collecting sessions and attachments"
    ))

    # Bloccante

    [sessions, attachments] = await collecting_sessions_and_attachments(event, cookies, settings)

    # log number of sessions and attachments
    yield dict(type='log', value=ClientLog(
        severity=ClientLogSeverity.INFO,
        message=f'Found {len(sessions)} sessions.'
    ))

    yield dict(type='log', value=ClientLog(
        severity=ClientLogSeverity.INFO,
        message=f'Found {len(attachments)} attachments.'
    ))

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='collecting_contributions_and_files',
        text="Collecting contributions and files"
    ))

    # Bloccante

    [contributions] = await collecting_contributions_and_files(event, sessions, cookies, settings)

    # log number of contributions
    yield dict(type='log', value=ClientLog(
        severity=ClientLogSeverity.INFO,
        message=f'Found {len(contributions)} contributions.'
    ))

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='adapting_final_proceedings',
        text="Adapting final proceedings"
    ))

    # Bloccante

    final_proceedings = await adapting_final_proceedings(event, sessions, contributions, attachments, cookies, settings)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='clean_static_site',
        text='Clean Static site'
    ))

    await clean_static_site(final_proceedings, cookies, settings, config)

    """ """

    try:

        await extend_lock(lock)

        yield dict(type='progress', value=dict(
            phase='download_event_attachments',
            text="Download event attachments"
        ))

        # Bloccante

        await download_event_attachments(final_proceedings, cookies, settings)

    except Exception as ex:
        logger.error(ex, exc_info=True)

        # Produzione logs

        # Produzione result
        yield dict(type='result', value=dict(
            # metadata=metadata,
            # errors=errors
        ))

        # Se l'errore è bloccante
        return

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='download_contributions_papers',
        text="Download Contributions Papers"
    ))

    # Bloccante

    [final_proceedings, papers_data] = await download_contributions_papers(final_proceedings, cookies, settings,
                                                                           filter_contributions_pubblicated)

    # log number of files
    yield dict(type='log', value=ClientLog(
        severity=ClientLogSeverity.INFO,
        message=f'Downloaded {len(papers_data)} papers.'
    ))

    """ """

    if config.include_event_slides:

        await extend_lock(lock)

        yield dict(type='progress', value=dict(
            phase='download_contributions_slides',
            text="Download Contributions Slides"
        ))

        # Bloccante

        [final_proceedings, slides_data] = await download_contributions_slides(final_proceedings,
                                                                               cookies, settings)

        # log number of files
        yield dict(type='log', value=ClientLog(
            severity=ClientLogSeverity.INFO,
            message=f'Downloaded {len(slides_data)} slides.'
        ))

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='read_papers_metadata',
        text='Read Papers Metadata'
    ))

    # Bloccante

    await read_papers_metadata(final_proceedings, cookies, settings,
                               filter_contributions_pubblicated)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='validate_contributions_papers',
        text='Validate Contributions Papers'
    ))

    # Bloccante il processo di validazione
    # Mentre il risultato della validazione
    # è bloccante se strict_pdf_check

    [metadata, errors] = await validate_proceedings_data(final_proceedings, cookies, settings,
                                                         filter_contributions_pubblicated)

    if len(errors) > 0:
        if config.strict_pdf_check:

            yield dict(type='log', value=ClientLog(
                severity=ClientLogSeverity.ERROR,
                message='Errors when validating proceedings data.'
            ))

            yield dict(type='result', value=dict(
                metadata=metadata,
                errors=errors
            ))

            return

        else:
            yield dict(type='log', value=ClientLog(
                severity=ClientLogSeverity.WARNING,
                message='Errors when validating proceedings data.'
            ))

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='extract_contribution_references',
        text='Extract Contribution References'
    ))

    # Bloccante

    await generate_contribution_references(final_proceedings, cookies, settings, config,
                                           filter_contributions_pubblicated)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='generate_dois',
        text='Generate DOIs'
    ))

    # Bloccante

    await generate_dois(final_proceedings, cookies, settings, config,
                        filter_contributions_pubblicated)

    """ """

    if config.generate_doi_payload:

        await extend_lock(lock)

        yield dict(type='progress', value=dict(
            phase='generate_doi_payloads',
            text='Generate DOI payloads'
        ))

        # Bloccante

        # generation of payloads for DOIs
        await build_doi_payloads(final_proceedings)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='manage_duplicates',
        text='Managing duplicates'
    ))

    # Bloccante

    await manage_duplicates(final_proceedings, settings)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='write_papers_metadata',
        text='Write Papers Metadata'
    ))

    # Bloccante

    await write_papers_metadata(final_proceedings, cookies, settings, filter_contributions_pubblicated)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='generate_contributions_groups',
        text='Generate Contributions Groups'
    ))

    await generate_contributions_groups(final_proceedings, cookies, settings)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='concat_contribution_papers',
        text='Concat Contributions Papers'
    ))

    await concat_contribution_papers(final_proceedings, cookies, settings, config, filter_contributions_pubblicated)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='generate_site_pages',
        text='Generate Site Pages'
    ))

    plugin = HugoFinalProceedingsPlugin(
        final_proceedings, cookies, settings, config)

    await plugin.run_prepare()
    await plugin.run_build()

    """ """

    await extend_lock(lock)

    logger.info('event_final_proceedings - copy_event_attachments')

    yield dict(type='progress', value=dict(
        phase='copy_event_pdf',
        text='Copy event PDF'
    ))

    await copy_event_attachments(final_proceedings, cookies, settings)
    await copy_contribution_papers(final_proceedings, cookies, settings, filter_contributions_pubblicated)

    if config.include_event_slides:
        await copy_contribution_slides(final_proceedings, cookies, settings)

    """ """

    # await extend_lock(lock)

    # yield dict(type='progress', value=dict(
    #     phase='clean_static_site_2',
    #     text='Clean Static site'
    # ))

    # await clean_pdf_cache(final_proceedings, cookies, settings, config)

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='generate_final_proceedings',
        text='Generate Final Proceedings'
    ))

    await plugin.generate()

    """ """

    await extend_lock(lock)

    yield dict(type='progress', value=dict(
        phase='link_static_site',
        text='Link Static site'
    ))

    await link_static_site(final_proceedings, cookies, settings, config)

    """ """

    await extend_lock(lock)

    logger.info('event_final_proceedings - get_final_proceedings')

    result = await get_final_proceedings(final_proceedings)

    yield result

async def get_final_proceedings(final_proceedings: ProceedingsData) -> dict:
    """ """

    event_code = final_proceedings.event.id
    event_name = final_proceedings.event.name
    event_title = final_proceedings.event.title
    event_path = final_proceedings.event.path

    return dict(
        type='result',
        value=dict(
            event_code=event_code,
            event_name=event_name,
            event_title=event_title,
            event_path=event_path
        )
    )

async def handle_proceedings_error(error: ProceedingsError):
    """ Handle proceedings error """

    yield dict(type='log', value=ClientLog(
        severity=ClientLogSeverity.ERROR,
        message=str(error)
    ))

    # stop generation
    yield dict(type='result', value=dict())

    raise error


import copy
import random
import sys
from typing import List
import json
import pygame
from collections import deque
from itertools import permutations
from GraphAlgoInterface import GraphAlgoInterface
from GraphInterface import GraphInterface
from DiGraph import DiGraph
from Node import Node
from Edge import Edge

class GraphAlgo(GraphAlgoInterface):
    def __init__(self, graph=None):
        if graph:
            self.__graph = graph
        else:
            self.__graph = DiGraph()

    def get_graph(self) -> GraphInterface:
        """
        :return: the directed graph on which the algorithm works on.
        """
        return self.__graph

    def load_from_json(self, file_name: str) -> bool:
        """
        Loads a graph from a json file.
        @param file_name: The path to the json file
        @returns True if the loading was successful, False o.w.
        """

        nodes = []
        edges = []
        try:
            with open(file_name) as f:
                graph_json = json.load(f)

            for node in graph_json['Nodes']:
                nodes.append(Node(node["id"], node.get("pos")))

            for edge in graph_json['Edges']:
                edges.append(Edge(edge["src"], edge["dest"], edge["w"]))

            self.__graph = DiGraph(nodes, edges)
            return True
        except Exception as e:
            return False

    def save_to_json(self, file_name: str) -> bool:
        """
        Saves the graph in JSON format to a file
        @param file_name: The path to the out file
        @return: True if the save was successful, False o.w.
        """
        graph_json = {"Nodes": {}, "Edges": {}}
        for k, node in self.__graph.get_all_v().items():
            graph_json["Nodes"].update({"id": k, "pos": node.location})
        for edge in self.__graph.all_edges:
            graph_json["Edges"].update({"src": edge.src, "w": edge.weight, "dest": edge.dest})

        with open(file_name, 'w') as f:
            json.dump(graph_json, f)

    def shortest_path(self, id1: int, id2: int) -> (float, list):
        """
        Returns the shortest path from node id1 to node id2 using Dijkstra's Algorithm
        @param id1: The start node id
        @param id2: The end node id
        @return: The distance of the path, a list of the nodes ids that the path goes through
        Example:
#      >>> from GraphAlgo import GraphAlgo
#       >>> g_algo = GraphAlgo()
#        >>> g_algo.addNode(0)
#        >>> g_algo.addNode(1)
#        >>> g_algo.addNode(2)
#        >>> g_algo.addEdge(0,1,1)
#        >>> g_algo.addEdge(1,2,4)
#        >>> g_algo.shortestPath(0,1)
#        (1, [0, 1])
#        >>> g_algo.shortestPath(0,2)
#        (5, [0, 1, 2])
        Notes:
        If there is no path between id1 and id2, or one of them dose not exist the function returns (float('inf'),[])
        More info:
        https://en.wikipedia.org/wiki/Dijkstra's_algorithm
        """
        # init distences list
        distance_nodes = {k: (float('inf'), []) for k, v in self.__graph.get_all_v().items()}
        distance_nodes[id1] = (0, [id1])
        visited = []
        pq = deque([])
        pq.append((0, id1))

        while pq:
            # get unvisited node from queue
            (dist, current_vertex) = pq.popleft()
            visited.append(current_vertex)

            for neighbor_id, neighbor in self.__graph.neighbors(current_vertex):
                distance = neighbor.weight
                if neighbor_id not in visited:
                    old_cost = distance_nodes[neighbor_id][0]
                    new_cost = distance_nodes[current_vertex][0] + distance
                    if new_cost < old_cost:
                        pq.append((new_cost, neighbor_id))
                        # add to the path the neibor
                        path = copy.copy(distance_nodes[current_vertex][1])
                        path.append(neighbor_id)
                        distance_nodes[neighbor_id] = (new_cost, path)\
                            if distance_nodes[current_vertex][1] else (new_cost, [neighbor_id])
        distance = distance_nodes[id2][0]
        path = distance_nodes[id2][1]
        return distance, path

    def TSP(self, node_lst: List[int]) -> (List[int], float):
        """
        Finds the shortest path that visits all the nodes in the list
        :param node_lst: A list of nodes id's
        :return: A list of the nodes id's in the path, and the overall distance
        """
        min_cost = sys.maxsize
        path_list = []
        next_permutation = permutations(node_lst)
        for permutation in next_permutation:
            current_path_cost = 0
            for i in range(len(node_lst)):
                current = permutation[i]
                previous = permutation[i-1]
                if self.__graph.all_in_edges_of_node(current).get(previous):
                    current_path_cost += self.__graph.all_in_edges_of_node(current)[previous].weight
                else:
                    current_path_cost = sys.maxsize
            if current_path_cost < min_cost:
                min_cost = current_path_cost
                path_list = permutation
        return list(path_list), min_cost

    def centerPoint(self) -> (int, float):
        """
        Finds the node that has the shortest distance to it's farthest node.
        :return: The nodes id, min-maximum distance
        """
        min_max_dist = sys.maxsize
        # go over all possible starting nodes
        for node_src in self.__graph.get_all_v():
            max_dist = 0
            # go over all possible ending nodes
            for node_dst in self.__graph.get_all_v():
                if node_src != node_dst:
                    # get the shortest path from start to end
                    dist, path = self.shortest_path(node_src, node_dst)
                    # get the forthest distence from start to a end node
                    if dist > max_dist:
                        max_dist = dist
            # get the smallest forthest distance
            if max_dist < min_max_dist:
                min_max_dist = max_dist
                min_max_id = node_src
        return min_max_id, min_max_dist

    def plot_graph(self) -> None:
        """
        Plots the graph.
        If the nodes have a position, the nodes will be placed there.
        Otherwise, they will be placed in a random but elegant manner.
        @return: None
        """
        _quit = False
        pygame.init()
        screen = pygame.display.set_mode()

        for edge in self.__graph.all_edges:  # drawing lines
            start_node_location_x, start_node_location_y = (self.__graph.get_all_v().get(edge.src).location[0],
                                                            self.__graph.get_all_v().get(edge.src).location[
                                                                1]) if self.__graph.get_all_v().get(
                edge.src).location else (random.randint(a=1, b=1000), random.randint(a=1, b=1000))
            dest_node_location_x, dest_node_location_y = (self.__graph.get_all_v().get(edge.dest).location[0],
                                                          self.__graph.get_all_v().get(edge.dest).location[
                                                              1]) if self.__graph.get_all_v().get(
                edge.dest).location else (random.randint(a=1, b=1000), random.randint(a=1, b=1000))
            start = (start_node_location_x, start_node_location_y)
            end = (dest_node_location_x, dest_node_location_y)
            pygame.draw.aaline(screen, (255, 255, 255), start, end, 1)
        while not _quit:
            pygame.display.flip()


import requests
from speakers import Speakers

class SpeechKitAdapter(object):
    """Класс SpeechKitAdapter реализует получение аудио от сервиса Yandex SpeechKit

    Основное применение - получение аудио от сервиса YSK

    Атрибуты
    --------
    folder_id
        символьный идентификатор рабочего каталога в сервисах cloud.yandex.ru
    api_key
        символьный идентификатор ключа АПИ для сервисов cloud.yandex.ru
    t2sbot
        объект класса TGText2SpeechBot (из tg_bot.py)

    Методы
    ------
    def synthesize(self, text, userinfo):
        отправляет запрос на синтез речи из переданного текста

    async def getAudio(self, chatid, text, asyncinfo, fileid):
        асинхронное получение аудио
    """

    def __init__(self, folder_id, api_key, t2sbot):
        self.__speakersinfo = Speakers()
        self.__folder_id = folder_id
        self.__api_key = api_key
        self.__t2sbot = t2sbot

    def synthesize(self, text, userinfo):
        """Метод для получения синтезированной речи от сервиса cloud.yandex.ru
        Вход: текст для синтеза, объект UserCfg (из usercfg.py)
        Выход: итерируемый объект
        Задача: синтезироваать речь
        """

        url = "https://tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
        headers = {"Authorization": "Api-Key " + self.__api_key}
        data = {
            "text": text,
            "lang": userinfo.getLang(),
            "folderId": self.__folder_id,
            "speed": userinfo.getSpeed(),
            "voice": self.__speakersinfo.getSpeakerId(userinfo.getLang(), userinfo.getSex()),
        }

        with requests.post(url, headers=headers, data=data, stream=True) as resp:
            if resp.status_code != 200:
                raise RuntimeError("Invalid response received: code: %d, message: %s" % (resp.status_code, resp.text))

            for chunk in resp.iter_content(chunk_size=None):
                yield chunk

    async def getAudio(self, chatid, text, asyncinfo, fileid):
        """Метод для формирования
        Вход: идентификатор чата, текст, набор параметров смещения,
            идентификатор файла
        Выход: пусто
        Задача: сохранить полученное аудио
        """

        asyncid = asyncinfo["asyncid"]
        uniqueid = asyncinfo["uniqueid"]
        offset = asyncinfo["offset"]
        userinfo = self.__t2sbot.getuserinfo(chatid)
        audiofile = "synthesizes/%d_%d_%d.ogg" % (chatid, asyncid, fileid)
        with open(audiofile, "wb") as f:
            try:
                shift = offset + uniqueid
                for audio_content in self.synthesize(text[offset:shift], userinfo):
                    f.write(audio_content)
                f.close()
                userinfo.getAsyncMgr().registerUniqueId(asyncid, uniqueid)
                await self.__t2sbot.onReceivedFile(chatid, asyncid, uniqueid)

            except RuntimeError:
                self.__t2sbot.bot.send_message(chatid, "Похоже что волшебная палочка сломалась :(")


#!/usr/bin/python3

import http.server
import json
import os.path

from server import UploadToDriveServer

script_path = os.path.abspath(__file__)
script_dir = os.path.dirname(script_path)

def read_client_secret():
	client_name = 'client_secret.json'
	client_path = os.path.join(script_dir, client_name)
	with open(client_path, 'r') as f:
		client = json.load(f)
	assert client is not None and 'installed' in client
	client = client['installed']
	return client

def write_refresh_token(refresh_token):
	refresh_name = 'refresh_token.txt'
	refresh_path = os.path.join(script_dir, refresh_name)
	with open(refresh_path, mode='w') as f:
		f.write(refresh_token + '\n')

client = read_client_secret()

assert 'client_id' in client
print('=== client id ===')
print(client['client_id'])
print()

assert 'client_secret' in client
print('=== client secret ===')
print(client['client_secret'])
print()

address = ('localhost', 46568)
print('=== server url ===')
print('http://{:s}:{:d}/init'.format(*address))
print()

print('Navigate to the page above and follow the instructions.')
print('To kill the server press Ctrl+C on this window.')
print()

server = http.server.HTTPServer(address, UploadToDriveServer)
server.client = client
server.callback = write_refresh_token
try:
	server.serve_forever()
except KeyboardInterrupt:
	print()
	server.server_close()


import enum
from typing import List, Optional, Tuple

_STATE_VARIABLE_PATH_PREFIX = "@"
_STATE_VARIABLE_PATH_SEPARATOR = "."

_ARM_TYPE_NODE_NAME = "ArmPart"
_FT_TYPE_NODE_NAME = "ForceTorqueSensorPart"
_ADIO_TYPE_NODE_NAME = "ADIOPart"
_GRIPPER_TYPE_NODE_NAME = "GripperPart"
_RANGEFINDER_TYPE_NODE_NAME = "RangefinderPart"

_SAFETY_TYPE_NODE_NAME = "Safety"

# Arm part related nodes.
_SENSED_POSITION_NODE_NAME = "sensed_position"
_SENSED_VELOCITY_NODE_NAME = "sensed_velocity"
_SENSED_ACCELERATION_NODE_NAME = "sensed_acceleration"
_SENSED_TORQUE_NODE_NAME = "sensed_torque"
_BASE_TWIST_TIP_SENSED_NODE_NAME = "base_twist_tip_sensed"
_BASE_LINEAR_VELOCITY_TIP_SENSED_NODE_NAME = "base_linear_velocity_tip_sensed"
_BASE_ANGULAR_VELOCITY_TIP_SENSED_NODE_NAME = "base_angular_velocity_tip_sensed"
_CURRENT_CONTROL_MODE_NODE_NAME = "current_control_mode"

# Force torque sensor part related nodes.
_WRENCH_NODE_NAME = "wrench_at_tip"
_FORCE_MAGNITUDE_NODE_NAME = "force_magnitude_at_tip"
_TORQUE_MAGNITUDE_NODE_NAME = "torque_magnitude_at_tip"

# Simple gripper part related nodes.
_GRIPPER_STATUS_NODE_NAME = "sensed_state"
_GRIPPER_OPENING_WIDTH_NODE_NAME = "opening_width"

# ADIO part related nodes.
_DIGITAL_INPUT_NODE_NAME = "di"
_DIGITAL_OUTPUT_NODE_NAME = "do"
_ANALOG_INPUT_NODE_NAME = "ai"

# Rangefinder part related nodes.
_RANGEFINDER_DISTANCE_NODE_NAME = "distance"

# Safety part related nodes.
_ENABLE_BUTTON_STATUS_NODE_NAME = "enable_button_status"

class _StateVariablePathBuilder:
  """Helps building state variable paths by adding nodes that construct in the end the complete path.

  A state variable path is used to address fields in the robot part status such
  as
  joint positions or force values.
  The order of adding nodes is the order of nodes in the path.
  An example path looks as follows: `@arm.L1ArmPart.sensed_position[0]`
  """

  def __init__(self):
    self._nodes: list[Tuple[str, Optional[int]]] = []

  def add_node_with_index(
      self, node_name: str, index: int
  ) -> "_StateVariablePathBuilder":
    """Adds a single node with the given `node_name` and an array index to the path.

    Args:
      node_name: Name of the node.
      index: Index in the array to address.

    Returns:
      Itself for convenient path building using a fluent interface.
    """
    self._nodes.append((node_name, index))
    return self

  def add_nodes(self, node_names: List[str]) -> "_StateVariablePathBuilder":
    """Adds multiple nodes with the given `node_names` to the path.

    Args:
      node_names: List of node names.

    Returns:
      Itself for convenient path building using a fluent interface.
    """
    for node_name in node_names:
      self._nodes.append((node_name, None))
    return self

  def build(self) -> str:
    """Builds the final state variable path string based on the previous add-calls.

    Returns:
      The final state variable path in the format:
      {_STATE_VARIABLE_PATH_PREFIX}<first_node>{_STATE_VARIABLE_PATH_SEPARATOR}<...more
      nodes>{_STATE_VARIABLE_PATH_SEPARATOR}<last_node>.

      A single node consists of the node name and an optional array index: e.g.
      my_field[123]
    """
    if not self._nodes:
      raise ValueError("No path nodes were added. Cannot build a path!")

    node_strings = []
    for node_name, node_index in self._nodes:
      node_string = node_name
      if node_index is not None:
        node_string += "[%d]" % node_index
      node_strings.append(node_string)
    return _STATE_VARIABLE_PATH_PREFIX + str(
        _STATE_VARIABLE_PATH_SEPARATOR
    ).join(node_strings)

class StateVariablePath:
  """Groups all state variable path generator functions."""

  class Arm:
    """Groups all state variable path generator functions for the arm part."""

    @classmethod
    def sensed_position(
        cls,
        part_name: str,
        joint_index: int,
    ) -> str:
      """Generates a state variable path for a single sensed joint position.

      Field type: double

      Args:
        part_name: Name of the arm part.
        joint_index: Joint to address.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _ARM_TYPE_NODE_NAME])
          .add_node_with_index(_SENSED_POSITION_NODE_NAME, joint_index)
          .build()
      )

    @classmethod
    def sensed_velocity(
        cls,
        part_name: str,
        joint_index: int,
    ) -> str:
      """Generates a state variable path for a single sensed joint velocity.

      Field type: double

      Args:
        part_name: Name of the arm part.
        joint_index: Joint to address.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _ARM_TYPE_NODE_NAME])
          .add_node_with_index(_SENSED_VELOCITY_NODE_NAME, joint_index)
          .build()
      )

    @classmethod
    def sensed_acceleration(
        cls,
        part_name: str,
        joint_index: int,
    ) -> str:
      """Generates a state variable path for a single sensed joint acceleration.

      Field type: double

      Args:
        part_name: Name of the arm part.
        joint_index: Joint to address.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _ARM_TYPE_NODE_NAME])
          .add_node_with_index(_SENSED_ACCELERATION_NODE_NAME, joint_index)
          .build()
      )

    @classmethod
    def sensed_torque(
        cls,
        part_name: str,
        joint_index: int,
    ) -> str:
      """Generates a state variable path for a single sensed joint torque.

      Field type: double

      Args:
        part_name: Name of the arm part.
        joint_index: Joint to address.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _ARM_TYPE_NODE_NAME])
          .add_node_with_index(_SENSED_TORQUE_NODE_NAME, joint_index)
          .build()
      )

    class TwistDimension(enum.Enum):
      """Helper enum to map a twist dimension onto an array index.

      X,Y,Z map to the linear velocity and RX, RY, RZ map to the angular
      velocities of the twist.
      """

      X = 0
      Y = 1
      Z = 2
      RX = 3
      RY = 4
      RZ = 5

    @classmethod
    def base_twist_tip_sensed(
        cls,
        part_name: str,
        twist_dimension: TwistDimension,
    ) -> str:
      """Generates a state variable path for a single sensed twist entry.

      The twist is calculated for the tip in the robot's base frame based on the
      sensed joint velocities.

      Field type: double

      Args:
        part_name: Name of the arm part.
        twist_dimension: Twist dimension to specify the value of the twist array
          to address.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _ARM_TYPE_NODE_NAME])
          .add_node_with_index(
              _BASE_TWIST_TIP_SENSED_NODE_NAME, twist_dimension.value
          )
          .build()
      )

    @classmethod
    def base_linear_velocity_tip_sensed(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the Cartesian linear (translational) velocity magnitude (Euclidean or l^2-Norm) of the arm tip.

      Field type: double

      Args:
        part_name: Name of the arm part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([
              part_name,
              _ARM_TYPE_NODE_NAME,
              _BASE_LINEAR_VELOCITY_TIP_SENSED_NODE_NAME,
          ])
          .build()
      )

    @classmethod
    def base_angular_velocity_tip_sensed(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the Cartesian angular (rotational) velocity magnitude (Euclidean or l^2-Norm) of the arm tip.

      Field type: double

      Args:
        part_name: Name of the arm part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([
              part_name,
              _ARM_TYPE_NODE_NAME,
              _BASE_ANGULAR_VELOCITY_TIP_SENSED_NODE_NAME,
          ])
          .build()
      )

    @classmethod
    def current_control_mode(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the currently used control mode.

      The value corresponds to the values of the enum
         :intrinsic.icon.proto.part_status_pb2.PartControlMode.

      Field type: int64

      Args:
        part_name: Name of the arm part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes(
              [part_name, _ARM_TYPE_NODE_NAME, _CURRENT_CONTROL_MODE_NODE_NAME]
          )
          .build()
      )

  class ForceTorque:
    """Groups all state variable path generator functions for the force-torque sensor part."""

    class WrenchDimension(enum.Enum):
      """Helper enum to map a wrench dimension onto an array index.

      X,Y,Z map to the forces and RX, RY, RZ map to the torques of the wrench.
      """

      X = 0
      Y = 1
      Z = 2
      RX = 3
      RY = 4
      RZ = 5

    @classmethod
    def wrench_at_tip(
        cls,
        part_name: str,
        wrench_dimension: WrenchDimension,
    ) -> str:
      """Generates a state variable path for a single wrench value sensed at the force torque sensor in the frame of the arm tip.

      Field type: double

      Args:
        part_name: Name of the force torque sensor part.
        wrench_dimension: Wrench dimension to specify the value of the twist
          array to address.

      Returns:
        Generated state variable path string.
      """

      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _FT_TYPE_NODE_NAME])
          .add_node_with_index(_WRENCH_NODE_NAME, wrench_dimension.value)
          .build()
      )

    @classmethod
    def force_magnitude_at_tip(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the magnitude (Euclidean or l^2-Norm) of the **force** sensed at the force torque sensor in the frame of the arm tip.

      Field type: double

      Args:
        part_name: Name of the force torque sensor part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes(
              [part_name, _FT_TYPE_NODE_NAME, _FORCE_MAGNITUDE_NODE_NAME]
          )
          .build()
      )

    @classmethod
    def torque_magnitude_at_tip(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the magnitude (Euclidean or l^2-Norm) of the **torque** sensed at the force torque sensor in the frame of the arm tip.

      Field type: double

      Args:
        part_name: Name of the force torque sensor part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes(
              [part_name, _FT_TYPE_NODE_NAME, _TORQUE_MAGNITUDE_NODE_NAME]
          )
          .build()
      )

  class Gripper:
    """Groups all state variable path generator functions for the gripper part."""

    @classmethod
    def status(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the opening status of the gripper.

      The enum values in this field are reported as integer values but
      correspond to the proto enum
      intrinsic.icon.proto.part_status_pb2.GripperState.SensedState.

      Field type: int

      Args:
        part_name: Name of the gripper part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes(
              [part_name, _GRIPPER_TYPE_NODE_NAME, _GRIPPER_STATUS_NODE_NAME]
          )
          .build()
      )

    @classmethod
    def opening_width(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the opening width of the gripper.

      Field type: double

      Args:
        part_name: Name of the gripper part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([
              part_name,
              _GRIPPER_TYPE_NODE_NAME,
              _GRIPPER_OPENING_WIDTH_NODE_NAME,
          ])
          .build()
      )

  class ADIO:
    """Groups all state variable path generator functions for the ADIO (Analog and Digital Inputs and Outputs) part."""

    @classmethod
    def digital_input(
        cls,
        part_name: str,
        block_name: str,
        signal_index: int,
    ) -> str:
      """Generates a state variable path for the status of a digital input of the signal at `signal_index` in block `block_name`.

      Field type: bool

      Args:
        part_name: Name of the adio part.
        block_name: Name of the signal block.
        signal_index: Index in the block.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes(
              [part_name, _ADIO_TYPE_NODE_NAME, _DIGITAL_INPUT_NODE_NAME]
          )
          .add_node_with_index(block_name, signal_index)
          .build()
      )

    @classmethod
    def digital_output(
        cls,
        part_name: str,
        block_name: str,
        signal_index: int,
    ) -> str:
      """Generates a state variable path for the status of a digital output of the signal at `signal_index` in block `block_name`.

      Field type: bool

      Args:
        part_name: Name of the adio part.
        block_name: Name of the signal block.
        signal_index: Index in the block.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes(
              [part_name, _ADIO_TYPE_NODE_NAME, _DIGITAL_OUTPUT_NODE_NAME]
          )
          .add_node_with_index(block_name, signal_index)
          .build()
      )

    @classmethod
    def analog_input(
        cls,
        part_name: str,
        block_name: str,
        signal_index: int,
    ) -> str:
      """Generates a state variable path for the status of an analog input of the signal at `signal_index` in block `block_name`.

      Field type: double

      Args:
        part_name: Name of the adio part.
        block_name: Name of the signal block.
        signal_index: Index in the block.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([part_name, _ADIO_TYPE_NODE_NAME, _ANALOG_INPUT_NODE_NAME])
          .add_node_with_index(block_name, signal_index)
          .build()
      )

  class RangeFinder:
    """Groups all state variable path generator functions for the rangefinder part."""

    @classmethod
    def distance(
        cls,
        part_name: str,
    ) -> str:
      """Generates a state variable path for the sensed distance of the rangefinder.

      Field type: double

      Args:
        part_name: Name of the rangefinder part.

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([
              part_name,
              _RANGEFINDER_TYPE_NODE_NAME,
              _RANGEFINDER_DISTANCE_NODE_NAME,
          ])
          .build()
      )

  class Safety:
    """Groups all state variable path generator functions for the safety signals."""

    @classmethod
    def enable_button_status(cls) -> str:
      """Generates a state variable path for the state of the enable safety button.

      The enum values in this field are reported as integer values but
      correspond to the proto enum
      intrinsic.icon.proto.safety_status_pb2.ButtonStatus.

      Field type: int

      Returns:
        Generated state variable path string.
      """
      return (
          _StateVariablePathBuilder()
          .add_nodes([
              _SAFETY_TYPE_NODE_NAME,
              _ENABLE_BUTTON_STATUS_NODE_NAME,
          ])
          .build()
      )


from typing import List

import allure
from assertpy import assert_that, soft_assertions
from selene import be
from selene.core.entity import Element
from selenium.webdriver.common.keys import Keys

from data.color_data import Color
from pages.incident_card.base_container import BaseContainer
from selene_custom import query
from utils.service_utils import get_background_color, get_outline_color

class BaseBranch(BaseContainer):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._list_item = self.element.ss('//div[contains (@class, "incident-content__question-list-item")]')
        self._link = self.element.s('//a')
        self._button = lambda button: self._element.s(f'//button[contains (text(), "{button}")]')
        self._answer_buttons = self.element.ss('.//div[contains (@class, "answer-list")]/button')
        self._elements_for_assert = [
            self._list_item,
        ]

    @allure.step('Проверка контента уточняющих вопросов')
    def assure_content(self, incident_content: List):
        content_items_ui = [item.get(query.text) for item in self._list_item]
        with soft_assertions():
            for item in incident_content:
                assert_that(content_items_ui).contains(item)

    @allure.step('Выбор ответов')
    def choose_answers(self, buttons: List):
        for button in buttons:
            self._button(button).click()
        return self

    @staticmethod
    @allure.step('Проверка кнопка активна')
    def _check_button_is_active(button: Element):
        assert_that(button.with_(timeout=10).get(query.class_value)).contains('active')
        assert_that(get_background_color(button)).is_equal_to(Color.BLUE)

    @allure.step('Проверка ответов')
    def check_answers_active_buttons(self, buttons: List):
        with soft_assertions():
            for button in buttons:
                self._check_button_is_active(button=self._button(button))

    @allure.step('Проверка фокуса на ответе')
    def assure_answer_in_focus(self, answer_number: int):
        assert_that(get_outline_color(self._answer_buttons[answer_number - 1])).is_equal_to(Color.OUTLINE_COLOR_BLUE)

    @allure.step('Выбрать первый ответ на котором фокус')
    def choose_first_answer_with_focus_by_keyboard(self):
        self._answer_buttons[0].press(Keys.SPACE)
        return self

    @allure.step('Проверка: ответ выбран')
    def assure_answer_is_selected(self, answer_number: int):
        self._check_button_is_active(self._answer_buttons[answer_number - 1])

    @allure.step('Проверка заголовка ветки')
    def assure_branch_title(self, branch_title):
        assert_that(self._link.get(query.text)).contains(branch_title)

    @allure.step('Проверка: ветка отображается')
    def assure_branch_is_visible(self):
        assert_that(self.element.matching(be.visible)).is_true()

    @allure.step('Проверка: ветка не отображается')
    def assure_branch_is_not_visible(self):
        assert_that(self.element.matching(be.not_.visible)).is_true()

class FirstBranch(BaseBranch):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._keyboard_combinations = [Keys.ALT, '1']

class SecondBranch(BaseBranch):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._keyboard_combinations = [Keys.ALT, '2']

class ThirdBranch(BaseBranch):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._keyboard_combinations = [Keys.ALT, '3']


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#------------------------------------------------------------------------------
# Author : Enoch Luis S Catuncan
# Date Created : October 15th 2022
#------------------------------------------------------------------------------
"""
This module contains the Player sprite. The player class takes type,
windowSize, FPS and BPM as parameters. Type determines whether it is the blue
or orange circle, windowSize is the size of the display window, FPS is the
frames per second and BPM is the Beats Per Minute.
"""
#------------------------------------------------------------------------------
import math # Used for circular motion of circles
#------------------------------------------------------------------------------
import pygame
#------------------------------------------------------------------------------

class Player(pygame.sprite.Sprite):
    def __init__(self, type, windowSize, FPS, BPM):
        super().__init__()
        # Set up blue or orange circle sprite
        if type == "Blue":
            self.image = pygame.image.load(
                "assets/images/blue_circle.png").convert_alpha()
            self.rect = self.image.get_rect(
                center=(windowSize[0]//2 + 100, windowSize[1]//2))
            self.moveState = "Move"
            # Set starting position of circular motion to right
            self.angle = (1/2)*math.pi
            # Set center of circular motion to center of other circle
            self.circMotionCenter = (windowSize[0]//2, windowSize[1]//2)
        else:
            self.image = pygame.image.load(
                "assets/images/orange_circle.png").convert_alpha()
            self.rect = self.image.get_rect(
                center=(windowSize[0]//2, windowSize[1]//2))
            self.moveState = "Fixed"
            # Set starting position of circular motion to left
            self.angle = (3/2)*math.pi
            # Set center of circular motion to center of other circle
            self.circMotionCenter = (windowSize[0]//2 + 100, windowSize[1]//2)
        self.radius = 100
        # (2*math.pi)/FPS to make full rotation in 1 second
        # Around 1 rotation for 100 BPM
        # Positive rotationPerSecond is clockwise rotation
        self.FPS = FPS
        self.rotationPerSecond = ((2*math.pi)/(self.FPS)) * (BPM/100)
        # Set up mask for collision detection
        self.mask = pygame.mask.from_surface(self.image)

    # Moves the circle in circular motion
    def move(self):
        if self.moveState == "Move":
            # Clockwise movement by reducing angle
            # Anti-clockwise movement by increasing angle
            self.angle -= self.rotationPerSecond
            # Uniform circular motion
            self.rect.center = \
            (self.circMotionCenter[0] + (self.radius*math.sin(self.angle)),
            self.circMotionCenter[1] + (self.radius*math.cos(self.angle)))

    # Snaps the moving circle to the next tile
    def snapToTile(self, nextTile):
        # Distance from current center to tile center using pythagorean theorem
        distanceToTile = \
        ((nextTile.rect.center[1] - self.rect.center[1])**2
        + (nextTile.rect.center[0] - self.rect.center[0])**2)**(1/2)
        # Calculate change in angle using SOHCAHTOA and set new angle
        self.angle = (self.angle - 2*math.asin(distanceToTile/(2*self.radius))
        % (2*math.pi))
        # Place the circle on the middle of the tile
        self.rect.center = nextTile.rect.center
        self.moveState = "Fixed"

    # Calculates score
    def getScore(self, nextTile):
        # Calculate distance from circle's center to tile center
        distanceToTile = \
        ((nextTile.rect.center[1] - self.rect.center[1])**2
        + (nextTile.rect.center[0] - self.rect.center[0])**2)**(1/2)
        # Score system
        if distanceToTile <= 24:
            return "Perfect"
        else:
            return "Far"

    # For the fixed player, update center of circular motion and
    # starting position of the circular motion relative to moving circle
    def updateCircularMotionCenter(self, otherCircle):
        self.circMotionCenter = otherCircle.rect.center
        if self.moveState == "Fixed":
            # Set the starting circular position of fixed circle to opposite
            # the other circle's circular position
            self.angle = (otherCircle.angle + math.pi)

    # Update circle properties if there is a modifier tile
    def modifierChanges(self, nextTile):
        # If modifier tile is speed change
        if nextTile.modifier == "S":
            # Calculate new rotations per second
            if self.rotationPerSecond < 0:
                self.rotationPerSecond = -(((2*math.pi)/(self.FPS))
                * (nextTile.modifierBPM/100))
            else:
                self.rotationPerSecond = (((2*math.pi)/(self.FPS))
                * (nextTile.modifierBPM/100))
        # If modifier tile is reverse direction
        if nextTile.modifier == "R":
            # Reverse direction of rotation
            self.rotationPerSecond = -self.rotationPerSecond

    # Updates circular movement of circle
    def update(self, otherCircle):
        self.move()
        self.updateCircularMotionCenter(otherCircle)


import telebot

class TelegramInterface:

    USERS = [182023875]
    TOKEN = '5609539827:AAFAaxW9yLc4VIL84yEkXFZmPJoJfkffu_o'

    def __init__(self):
        self.bot = telebot.TeleBot(self.TOKEN)
        self.register_handlers(self.bot)
        self.bot.polling(none_stop=True, interval=1)

    def register_handlers(self, bot):
        users = self.USERS

        @bot.message_handler(func=lambda message: message.chat.id not in users)
        def unregistered_user(message):
            bot.send_message(message.chat.id, "Access denied")

        @bot.callback_query_handler(func=lambda call: True)
        def callback_worker(call):
            if call.data == "ON":
                bot.send_message(call.message.chat.id, 'Boiler power on confirmed')
            if call.data == "OFF":
                bot.send_message(call.message.chat.id, 'Boiler power off confirmed')

        @bot.message_handler(content_types=['text'])
        def cmd_handler(message):
            if message.text == '/boiler':
                keyboard = telebot.types.InlineKeyboardMarkup()
                key_on = telebot.types.InlineKeyboardButton(text='Turn on', callback_data='ON')
                keyboard.add(key_on)
                key_off = telebot.types.InlineKeyboardButton(text='Turn off', callback_data='OFF')
                keyboard.add(key_off)
                bot.send_message(message.from_user.id, text='Set boiler power', reply_markup=keyboard)
            else:
                bot.send_message(message.from_user.id, 'Unknown cmd')

if __name__ == '__main__':

    ti = TelegramInterface()

    while True:
        pass


import json
import random
import unittest
from datetime import datetime
from pymongo import MongoClient
from apps.basic_resource import server
from apps.basic_resource.documents import Article

class ResourceGetListFilters(unittest.TestCase):
    """
    Test if an HTTP GET request on a listview with filters gives the
    right response.
    """

    @classmethod
    def setUpClass(cls):

        cls.app = server.app.test_client()
        cls.mongo_client = MongoClient()

        # Test filters on all field types:
        cls.matching_values = {
            # StringField
            'text': "This text should match",

            # BoolField
            'publish': 1,

            # DateTimeField
            'publish_date': datetime(2010, 10, 5),

            # IntField
            'order': 333,

            # FloatField
            'version': 2.5,

            # LongField
            'serial_number': 4581951951031539524,

            # ListField
            'tags': ['matching_tag1', 'matching_tag2']
        }

        matching_articles = [
            {
                'title': "The first one",
                'text': cls.matching_values['text'],
                'publish': True,
                'publish_date': cls.matching_values['publish_date'],
                'order': cls.matching_values['order'],
                'version': cls.matching_values['version'],
                'serial_number': cls.matching_values['serial_number'],
                'tags': cls.matching_values['tags'],
                'top_comment': {}
            },
            {
                'title': "A sixt one",
                'text': cls.matching_values['text'],
                'publish': True,
                'publish_date': cls.matching_values['publish_date'],
                'order': cls.matching_values['order'],
                'version': cls.matching_values['version'],
                'serial_number': cls.matching_values['serial_number'],
                'tags': cls.matching_values['tags'],
                'top_comment': {}
            }
        ]

        non_matching_articles = []

        for i in range(100):

            # one divergent parameter should exclude the article
            exclude_match = random.choice((
                'text', 'publish', 'publish_date', 'order', 'version',
                'serial_number', 'tags'
            ))

            title = "Non matching article #{}".format(i)

            if exclude_match == 'text':
                text = "Non matching text #{}".format(i)
            else:
                text = cls.matching_values['text']

            if exclude_match == 'publish':
                publish = False
            else:
                publish = True

            if exclude_match == 'publish_date':
                publish_date = datetime(
                    random.randint(1950, 2000),
                    random.randint(1, 12),
                    random.randint(1, 27)
                )
            else:
                publish_date = cls.matching_values['publish_date']

            if exclude_match == 'order':
                order = random.randint(0, 100)
            else:
                order = cls.matching_values['order']

            if exclude_match == 'version':
                version = float('1.{}'.format(random.randint(0, 9)))
            else:
                version = cls.matching_values['version']

            if exclude_match == 'serial_number':
                serial_number = random.randint(
                    1000000000000000000, 2000000000000000000
                )
            else:
                serial_number = cls.matching_values['serial_number']

            if exclude_match == 'tags':
                tags = ['nonmatching_tag1', 'nonmatching_tag2']
            else:
                tags = cls.matching_values['tags']

            non_matching_articles.append({
                'title': title,
                'text': text,
                'publish': publish,
                'publish_date': publish_date,
                'order': order,
                'version': version,
                'serial_number': serial_number,
                'tags': tags,
                'top_comment': {}
            })

        # Load some initial data for this test case
        initial_data = matching_articles + non_matching_articles

        for article in initial_data:
            Article(**article).save()

        params = {}

        for key, value in cls.matching_values.items():
            if key == 'publish_date':
                params[key] = value.isoformat()
            elif key == 'tags':
                params[key] = ','.join(value)
            else:
                params[key] = unicode(value)

        query_string = '?{}'.format(
            '&'.join([
                '{}={}'.format(key, value)
                for key, value in params.items()
            ])
        )

        cls.response = cls.app.get('/articles/{}'.format(query_string))

    @classmethod
    def tearDownClass(cls):
        cls.mongo_client.unittest_monkful.article.remove()

    def test_status_code(self):
        """
        Test if the response status code is 200.
        """
        self.assertEqual(self.response.status_code, 200)

    def test_content_type(self):
        """
        Test if the content-type header is 'application/json'.
        """
        self.assertEqual(
            self.response.headers['content-type'],
            'application/json'
        )

    def test_json(self):
        """
        Test if the response data is valid JSON.
        """
        try:
            json.loads(self.response.data)
        except:
            self.fail("Response is not valid JSON.")

    def test_results(self):
        """
        Test if the results match the filters.
        """

        response_data = json.loads(self.response.data)
        self.assertEqual(len(response_data), 2)

        for article in response_data:
            for key, value in self.matching_values.items():

                if key == 'publish_date':
                    value = value.isoformat()

                self.assertEqual(article[key], value)