# ----------------------------------------------------------------------------#
# Imports
# ----------------------------------------------------------------------------#
import sys
import json
import dateutil.parser
import babel
from flask import (
    Flask,
    render_template,
    request,
    Response,
    flash,
    redirect,
    url_for)
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
import logging
from logging import Formatter, FileHandler
from flask_wtf import Form
from forms import *
from flask_migrate import Migrate

from config import SQLALCHEMY_DATABASE_URI

# ----------------------------------------------------------------------------#
# App Config.
# ----------------------------------------------------------------------------#

app = Flask(__name__)
moment = Moment(app)
app.config.from_object('config')
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

migrate = Migrate(app, db)
current_time = datetime.now()

# ----------------------------------------------------------------------------#
# Models.
# ----------------------------------------------------------------------------#

class Venue(db.Model):
    __tablename__ = 'venue'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    city = db.Column(db.String(120), nullable=False)
    state = db.Column(db.String(120), nullable=False)
    address = db.Column(db.String(120))
    phone = db.Column(db.String(120))
    image_link = db.Column(db.String(500))
    facebook_link = db.Column(db.String(120))
    website = db.Column(db.String(120))
    genres = db.Column(db.ARRAY(db.String(120)))
    seeking_talent = db.Column(db.Boolean, nullable=False, default=False)
    seeking_description = db.Column(db.String(500), default=None)
    shows = db.relationship('Show', backref='venue', lazy=True)

    def __init__(self, name, city, state, address, phone, genres, image_link=None, facebook_link=None, website=None,
                 seeking_talent=False, seeking_description=None):
        self.name = name
        self.city = city
        self.state = state
        self.address = address
        self.phone = phone
        self.image_link = image_link
        self.facebook_link = facebook_link
        self.website = website
        self.genres = genres
        self.seeking_talent = seeking_talent
        self.seeking_description = seeking_description

    def venue_data(self):
        return {
            "id": self.id,
            "name": self.name,
            "num_upcoming_shows": len([show.id for show in self.shows if show.start_time > current_time]),
        }

    def __repr__(self):
        return f'<class {self.__class__.__name__} {self.id} {self.name}>'

class Artist(db.Model):
    __tablename__ = 'artist'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    city = db.Column(db.String(120), nullable=False)
    state = db.Column(db.String(120), nullable=False)
    phone = db.Column(db.String(120))
    genres = db.Column(db.ARRAY(db.String(120)))
    image_link = db.Column(db.String(500))
    facebook_link = db.Column(db.String(120))
    website = db.Column(db.String(120))
    seeking_venue = db.Column(db.Boolean, nullable=False, default=False)
    seeking_description = db.Column(db.String(1000), default=None)
    shows = db.relationship('Show', backref='artist', lazy=True)

    def __init__(self, name, city, state, phone, genres, image_link=None, facebook_link=None, website=None,
                 seeking_venue=False, seeking_description=None):
        self.name = name
        self.city = city
        self.state = state
        self.phone = phone
        self.genres = genres
        self.image_link = image_link
        self.facebook_link = facebook_link
        self.website = website
        self.seeking_venue = seeking_venue
        self.seeking_description = seeking_description

    def __repr__(self):
        return f'<class {self.__class__.__name__} {self.id} {self.name}>'

class Show(db.Model):
    __tablename__ = 'show'

    id = db.Column(db.Integer, primary_key=True)
    venue_id = db.Column(db.Integer, db.ForeignKey('venue.id'), nullable=False)
    artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'), nullable=False)
    start_time = db.Column(db.DateTime, nullable=False)

    def __init__(self, venue_id, artist_id, start_time):
        self.venue_id = venue_id
        self.artist_id = artist_id
        self.start_time = start_time

    def artist_details(self):
        return {
            'artist_id': self.venue_id,
            'artist_name': self.artist.name,
            'artist_image_link': self.artist.image_link,
            'start_time': str(self.start_time)
        }

    def venue_details(self):
        return {
            'venue_id': self.venue_id,
            'venue_name': self.venue.name,
            'venue_image_link': self.venue.image_link,
            'start_time': str(self.start_time)
        }

    def show_details(self):
        return {
            "venue_id": self.venue_id,
            "venue_name": self.venue.name,
            "artist_id": self.artist_id,
            "artist_name": self.artist.name,
            "artist_image_link": self.artist.image_link,
            "start_time": str(self.start_time)
        }

    def __repr__(self):
        return f'<class {self.__class__.__name__} {self.id}>'

# ----------------------------------------------------------------------------#
# Filters.
# ----------------------------------------------------------------------------#

def format_datetime(value, format='medium'):
    date = dateutil.parser.parse(value)
    if format == 'full':
        format = "EEEE MMMM, d, y 'at' h:mma"
    elif format == 'medium':
        format = "EE MM, dd, y h:mma"
    return babel.dates.format_datetime(date, format)

app.jinja_env.filters['datetime'] = format_datetime

# ----------------------------------------------------------------------------#
# Controllers.
# ----------------------------------------------------------------------------#

@app.route('/')
def index():
    return render_template('pages/home.html')

#  Venues
#  ----------------------------------------------------------------

@app.route('/venues')
def venues():
    venues = Venue.query.group_by(Venue.id, Venue.state, Venue.city).all()
    venue_state_and_city = ""
    data = []

    # loop through venues to check for upcoming shows, city, states and venue information
    for venue in venues:
        if venue_state_and_city == venue.city + venue.state:
            data[len(data) - 1]["venues"].append(venue.venue_data())
        else:
            venue_state_and_city = venue.city + venue.state
            data.append({
                "city": venue.city,
                "state": venue.state,
                "venues": [venue.venue_data()]
            })
    return render_template('pages/venues.html', areas=data)

@app.route('/venues/search', methods=['POST'])
def search_venues():
    search_term = request.form.get('search_term', '')
    # Below is the search query which returns list of all matched venues
    venues_list = Venue.query.filter(Venue.name.ilike('%' + search_term + '%')).all()
    response = {
        "count": len(venues_list),
        "data": [venue.venue_data() for venue in venues_list]
    }
    return render_template('pages/search_venues.html', results=response, search_term=search_term)

@app.route('/venues/<int:venue_id>')
def show_venue(venue_id):
    venue = Venue.query.get(venue_id)
    upcoming_shows = [show.artist_details() for show in venue.shows if show.start_time >= current_time]
    past_shows = [show.artist_details() for show in venue.shows if show.start_time < current_time]
    data = {
        "id": venue.id,
        "name": venue.name,
        "genres": venue.genres,
        "address": venue.address,
        "city": venue.city,
        "state": venue.state,
        "phone": venue.phone,
        "website": venue.website,
        "facebook_link": venue.facebook_link,
        "seeking_talent": venue.seeking_talent,
        "seeking_description": venue.seeking_description,
        "image_link": venue.image_link,
        "past_shows": past_shows,
        "upcoming_shows": upcoming_shows,
        "past_shows_count": len(past_shows),
        "upcoming_shows_count": len(upcoming_shows),
    }
    return render_template('pages/show_venue.html', venue=data)

#  Create Venue
#  ----------------------------------------------------------------

@app.route('/venues/create', methods=['GET'])
def create_venue_form():
    form = VenueForm()
    return render_template('forms/new_venue.html', form=form)

@app.route('/venues/create', methods=['POST'])
def create_venue_submission():
    # TODO: insert form data as a new Venue record in the db, instead
    # TODO: modify data to be the data object returned from db insertion
    error = False
    try:
        form_data = request.form
        seeking_talent_data = True if form_data.get("seeking_talent") == "True" else False
        if not seeking_talent_data:
            seeking_description_data = None
        else:
            seeking_description_data = form_data.get("seeking_description")
        new_venue = Venue(
            name=form_data.get("name"),
            city=form_data.get("city"),
            state=form_data.get("state"),
            address=form_data.get("address"),
            phone=form_data.get("phone"),
            genres=form_data.getlist("genres"),
            facebook_link=form_data.get("facebook_link"),
            image_link=form_data.get("image_link"),
            website=form_data.get("website"),
            seeking_talent=seeking_talent_data,
            seeking_description=seeking_description_data
        )
        db.session.add(new_venue)
        db.session.commit()
    except:
        error = True
        db.session.rollback()
        print(sys.exc_info())
    finally:
        db.session.close()

    if error:
        flash('An error occurred. Venue ' + form_data.get("name") + ' could not be listed.')
    else:
        flash('Venue ' + request.form['name'] + ' was successfully listed!')
        return render_template('pages/home.html')

@app.route('/venues/<venue_id>', methods=['DELETE'])
def delete_venue(venue_id):
    # TODO: Complete this endpoint for taking a venue_id, and using
    # SQLAlchemy ORM to delete a record. Handle cases where the session commit could fail.
    try:
        venue = Venue.query.get(venue_id)
        venue_name = venue.name
        db.session.delete(venue)
        db.session.commit()
        flash('Venue ' + venue_name + ' was successfully deleted!')
    except:
        db.session.rollback()
        print(sys.exc_info())
    finally:
        db.session.close()
    # BONUS CHALLENGE: Implement a button to delete a Venue on a Venue Page, have it so that
    # clicking that button delete it from the db then redirect the user to the homepage
    return render_template('pages/home.html')

#  Artists
#  ----------------------------------------------------------------
@app.route('/artists')
def artists():
    data = [{"id": artist.id, "name": artist.name} for artist in Artist.query.all()]
    return render_template('pages/artists.html', artists=data)

@app.route('/artists/search', methods=['POST'])
def search_artists():
    search_term = request.form.get('search_term', '')
    req_artist_list = Artist.query.filter(Artist.name.ilike("%" + search_term + "%")).all()
    # Note: There is no point in giving "num_upcoming_shows" data in response. so, didn't add that data in response
    response = {
        "count": len(req_artist_list),
        "data": [{"id": artist.id, "name": artist.name} for artist in req_artist_list]
    }
    return render_template('pages/search_artists.html', results=response, search_term=search_term)

@app.route('/artists/<int:artist_id>')
def show_artist(artist_id):
    artist = Artist.query.get(artist_id)
    upcoming_shows = [show.venue_details() for show in artist.shows if show.start_time >= current_time]
    past_shows = [show.venue_details() for show in artist.shows if show.start_time < current_time]

    data = {
        "id": artist.id,
        "name": artist.name,
        "genres": artist.genres,
        "city": artist.city,
        "state": artist.state,
        "phone": artist.phone,
        "website": artist.website,
        "facebook_link": artist.facebook_link,
        "seeking_venue": artist.seeking_venue,
        "seeking_description": artist.seeking_description,
        "image_link": artist.image_link,
        "past_shows": past_shows,
        "upcoming_shows": upcoming_shows,
        "past_shows_count": len(past_shows),
        "upcoming_shows_count": len(upcoming_shows),
    }
    return render_template('pages/show_artist.html', artist=data)

#  Update
#  ----------------------------------------------------------------
@app.route('/artists/<int:artist_id>/edit', methods=['GET'])
def edit_artist(artist_id):
    form = ArtistForm()
    artist_data = Artist.query.get(artist_id)
    artist = {
        "id": artist_data.id,
        "name": artist_data.name,
        "genres": artist_data.genres,
        "city": artist_data.city,
        "state": artist_data.state,
        "phone": artist_data.phone,
        "website": artist_data.website,
        "facebook_link": artist_data.facebook_link,
        "seeking_venue": artist_data.seeking_venue,
        "seeking_description": artist_data.seeking_description,
        "image_link": artist_data.image_link
    }
    return render_template('forms/edit_artist.html', form=form, artist=artist)

@app.route('/artists/<int:artist_id>/edit', methods=['POST'])
def edit_artist_submission(artist_id):
    # TODO: take values from the form submitted, and update existing
    # artist record with ID <artist_id> using the new attributes
    error = False
    try:
        data = request.form
        seeking_venue_data = True if data.get("seeking_venue") == "True" else False
        if not seeking_venue_data:
            seeking_description_data = None
        else:
            seeking_description_data = data.get("seeking_description")
        artist = Artist.query.get(artist_id)
        artist.name = data.get("name")
        artist.genres = data.getlist("genres")
        artist.city = data.get("city")
        artist.state = data.get("state")
        artist.phone = data.get("phone")
        artist.website = data.get("website")
        artist.facebook_link = data.get("facebook_link")
        artist.image_link = data.get("image_link")
        artist.seeking_venue = seeking_venue_data
        artist.seeking_description = seeking_description_data
        db.session.commit()
    except:
        error = True
        db.session.rollback()
        print(sys.exc_info())
    finally:
        db.session.close()

    if error:
        flash('An error occurred while updating ' + request.form['name'])
        return redirect(url_for('show_artist', artist_id=artist_id))
    else:
        flash('Artist ' + request.form['name'] + ' was successfully updated!')
        return redirect(url_for('show_artist', artist_id=artist_id))

@app.route('/venues/<int:venue_id>/edit', methods=['GET'])
def edit_venue(venue_id):
    form = VenueForm()
    venue_data = Venue.query.get(venue_id)
    venue = {
        "id": venue_data.id,
        "name": venue_data.name,
        "genres": venue_data.genres,
        "address": venue_data.address,
        "city": venue_data.city,
        "state": venue_data.state,
        "phone": venue_data.phone,
        "website": venue_data.website,
        "facebook_link": venue_data.facebook_link,
        "seeking_talent": venue_data.seeking_talent,
        "seeking_description": venue_data.seeking_description,
        "image_link": venue_data.image_link
    }
    return render_template('forms/edit_venue.html', form=form, venue=venue)

@app.route('/venues/<int:venue_id>/edit', methods=['POST'])
def edit_venue_submission(venue_id):
    # TODO: take values from the form submitted, and update existing
    # venue record with ID <venue_id> using the new attributes
    error = False
    try:
        venue = Venue.query.get(venue_id)
        form_data = request.form
        seeking_talent_data = True if form_data.get("seeking_talent") == "True" else False
        if not seeking_talent_data:
            seeking_description_data = None
        else:
            seeking_description_data = form_data.get("seeking_description")
        print("form_data", form_data)
        venue.name = form_data.get("name")
        venue.city = form_data.get("city")
        venue.state = form_data.get("state")
        venue.address = form_data.get("address")
        venue.phone = form_data.get("phone")
        venue.genres = form_data.getlist("genres")
        venue.facebook_link = form_data.get("facebook_link")
        venue.image_link = form_data.get("image_link")
        venue.website = form_data.get("website")
        venue.seeking_talent = seeking_talent_data
        venue.seeking_description = seeking_description_data
        db.session.commit()
    except:
        error = True
        db.session.rollback()
        print(sys.exc_info())
    finally:
        db.session.close()

    if error:
        flash('An error occurred while updating ' + request.form['name'])
        return redirect(url_for('show_venue', venue_id=venue_id))
    else:
        flash('Venue ' + request.form['name'] + ' was successfully updated!')
        return redirect(url_for('show_venue', venue_id=venue_id))

#  Create Artist
#  ----------------------------------------------------------------

@app.route('/artists/create', methods=['GET'])
def create_artist_form():
    form = ArtistForm()
    return render_template('forms/new_artist.html', form=form)

@app.route('/artists/create', methods=['POST'])
def create_artist_submission():
    # called upon submitting the new artist listing form
    # TODO: insert form data as a new Venue record in the db, instead
    # TODO: modify data to be the data object returned from db insertion
    error = False
    try:
        form_data = request.form
        seeking_venue_data = True if form_data.get("seeking_venue") == "True" else False
        if not seeking_venue_data:
            seeking_description_data = None
        else:
            seeking_description_data = form_data.get("seeking_description")
        new_artist = Artist(
            name=form_data.get("name"),
            city=form_data.get("city"),
            state=form_data.get("state"),
            phone=form_data.get("phone"),
            genres=form_data.getlist("genres"),
            image_link=form_data.get("image_link"),
            website=form_data.get("website"),
            seeking_venue=seeking_venue_data,
            seeking_description=seeking_description_data
        )
        db.session.add(new_artist)
        db.session.commit()
    except:
        error = True
        db.session.rollback()
        print(sys.exc_info())
    finally:
        db.session.close()

    if error:
        flash('An error occurred. Artist ' + form_data.get("name") + ' could not be listed.')
        return render_template('pages/home.html')
    else:
        flash('Artist ' + form_data.get("name") + ' was successfully listed!')
        return render_template('pages/home.html')

#  Shows
#  ----------------------------------------------------------------

@app.route('/shows')
def shows():
    data = [show.show_details() for show in Show.query.order_by(Show.start_time.desc()).all()]
    return render_template('pages/shows.html', shows=data)

@app.route('/shows/create')
def create_shows():
    # renders form. do not touch.
    form = ShowForm()
    return render_template('forms/new_show.html', form=form)

@app.route('/shows/create', methods=['POST'])
def create_show_submission():
    # called to create new shows in the db, upon submitting new show listing form
    # TODO: insert form data as a new Show record in the db, instead
    error = False
    try:
        form = ShowForm()
        form_data = request.form
        artist = Artist.query.get(form_data.get('artist_id'))
        if not artist:
            flash(f"Artist with given id {form_data.get('artist_id')} not exists!!!")
            return redirect('/shows/create')
        venue = Venue.query.get(form_data.get('venue_id'))
        if not venue:
            flash(f"Venue with given id {form_data.get('venue_id')} not exists!!!")
            return redirect('/shows/create')
        new_show = Show(
            venue_id=form_data.get('venue_id'),
            artist_id=form_data.get('artist_id'),
            start_time=form_data.get('start_time')
        )
        db.session.add(new_show)
        db.session.commit()
        # on successful db insert, flash success
        flash('Show was successfully listed!')
    except:
        error = True
        db.session.rollback()
        print(sys.exc_info())
    finally:
        db.session.close()

    if error:
        flash('An error occurred. Show could not be listed.')
    return render_template('pages/home.html')

@app.errorhandler(404)
def not_found_error(error):
    return render_template('errors/404.html'), 404

@app.errorhandler(500)
def server_error(error):
    return render_template('errors/500.html'), 500

if not app.debug:
    file_handler = FileHandler('error.log')
    file_handler.setFormatter(
        Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')
    )
    app.logger.setLevel(logging.INFO)
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.info('errors')

# ----------------------------------------------------------------------------#
# Launch.
# ----------------------------------------------------------------------------#

# Default port:
if __name__ == '__main__':
    app.run()

# Or specify port manually:
'''
if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)
'''


import requests
from bs4 import BeautifulSoup

class nameToUid(object):
    def __init__(self, cookies):
        self.cookies = cookies

    def transfer(self, name):
        search_url = 'https://weibo.cn/search/user/?keyword={}'.format(name)
        response = requests.post(search_url, cookies=self.cookies)
        soup = BeautifulSoup(response.content, 'html.parser')
        url = ''
        for tr in soup.find_all('table'):
            for td in tr.find_all('a'):
                username =  td.get_text().strip()
                if username.lower() == name.lower():
                    url = td.get('href').split('?')[0]
                    break
        return url


import customtkinter
import webbrowser
import asyncio
from threading import Thread

from src import paths
from src.gecko_pricer import GeckoPricer
from gui.main_window.tools_window import ToolsWindow
from gui.main_window.settings_window import SettingsWindow
from utils.gas_price import GasPrice, get_eth_mainnet_gas_price

from PIL import Image

class SidebarFrame(customtkinter.CTkFrame):
    def __init__(
            self,
            master,
            **kwargs
    ):
        super().__init__(master, **kwargs)
        self.master = master

        self.tools_window = None
        self.settings_window = None

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure((0, 1, 2, 4, 5, 6, 7, 8), weight=0)
        self.grid_rowconfigure(9, weight=1)
        self.grid(
            row=0,
            column=0,
            sticky="nsw"
        )
        self.tabview = customtkinter.CTkTabview(
            self,
            width=400,
            height=840,
            bg_color="transparent"
        )
        logo_image = customtkinter.CTkImage(
            light_image=Image.open(paths.LIGHT_MODE_LOGO_IMG),
            dark_image=Image.open(paths.DARK_MODE_LOGO_IMG),
            size=(150, 90)
        )
        self.logo_label = customtkinter.CTkLabel(
            self,
            image=logo_image,
            text=""
        )
        self.logo_label.grid(
            row=0,
            column=0,
            padx=20,
            pady=(20, 10)
        )
        self.tools_button = customtkinter.CTkButton(
            self,
            text="Tools",
            command=self.tools_button_event,
            font=customtkinter.CTkFont(size=12, weight="bold")
        )
        self.tools_button.grid(
            row=1,
            column=0,
            padx=25,
            pady=(10, 20),
            sticky="w"
        )

        self.settings_button = customtkinter.CTkButton(
            self,
            text="Settings",
            font=customtkinter.CTkFont(size=12, weight="bold"),
            command=self.settings_button_event
        )
        self.settings_button.grid(
            row=2,
            column=0,
            padx=25,
            pady=(0, 20),
            sticky="w"
        )

        # REFRESH BUTTON
        self.refresh_image = customtkinter.CTkImage(
            light_image=Image.open(f"{paths.GUI_DIR}/images/refresh_button.png"),
            dark_image=Image.open(f"{paths.GUI_DIR}/images/refresh_button.png"),
            size=(20, 20)
        )
        self.refresh_image_active = customtkinter.CTkImage(
            light_image=Image.open(f"{paths.GUI_DIR}/images/refresh_button_active.png"),
            dark_image=Image.open(f"{paths.GUI_DIR}/images/refresh_button_active.png"),
            size=(20, 20)
        )
        self.refresh_button = customtkinter.CTkButton(
            self,
            image=self.refresh_image,
            command=self.refresh_price_table_event,
            hover=False,
            text="- refresh data",
            bg_color='transparent',
            fg_color='transparent',
            width=5,
            text_color='gray58',

        )
        self.refresh_button.grid(
            row=4,
            column=0,
            padx=(18, 0),
            pady=(0, 2),
            sticky="w"
        )

        self.price_frame = PriceFrame(
            self,
            grid={
                "row": 3,
                "column": 0,
                "padx": 20,
                "pady": 0,
                "sticky": "w"
            },
        )

        self.appearance_mode_label = customtkinter.CTkLabel(
            self,
            text="Appearance Mode:",
            anchor="w")
        self.appearance_mode_label.grid(
            row=9,
            column=0,
            padx=20,
            pady=(0, 80),
            sticky="s"
        )
        self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(
            self,
            values=["Dark", "Light", "System"],
            command=self.change_appearance_mode_event
        )
        self.appearance_mode_optionemenu.grid(
            row=9,
            column=0,
            padx=20,
            pady=(0, 50),
            sticky="s"
        )

        link_font = customtkinter.CTkFont(
            size=12,
            underline=True
        )
        self.github_button = customtkinter.CTkButton(
            self,
            text="v1.1.0 Github origin",
            font=link_font,
            width=140,
            anchor="c",
            text_color="grey",
            fg_color='transparent',
            hover=False,
            command=self.open_github
        )
        self.github_button.grid(
            row=9,
            column=0,
            padx=20,
            pady=(0, 10),
            sticky="s"
        )

    def set_refresh_image(self, state: bool):
        if state:
            self.refresh_button.configure(image=self.refresh_image_active, text="- refreshing...")
        else:
            self.refresh_button.configure(image=self.refresh_image, text="- refresh data")

    def refresh_price_table_event(self):
        self.refresh_button.configure(text="Refreshing...")
        self.price_frame.set_gas_data()
        self.refresh_button.configure(text="- refresh data")

    def change_appearance_mode_event(self, new_appearance_mode: str):
        customtkinter.set_appearance_mode(new_appearance_mode)

    def open_github(self):
        webbrowser.open("https://github.com/frankmurrey/starknet_drop_helper")

    def add_new_module_tab(
            self,
            module_name: str
    ):
        """
        Add new module tab to the tabview
        :param module_name: tab name
        :return:
        """
        self.master.modules_frame.tabview.add(module_name.title())
        self.master.modules_frame.tabview.set(module_name.title())

    def tools_button_event(self):
        geometry = "450x900+1505+100"
        if self.winfo_screenwidth() <= 1600:
            geometry = "450x450+1050+100"

        if self.tools_window is None or not self.tools_window.winfo_exists():
            self.tools_window = ToolsWindow(self)
            self.tools_window.geometry(geometry)
            self.tools_window.resizable(False, False)
        else:
            self.tools_window.focus()

    def settings_button_event(self):
        geometry = "450x900+1505+100"
        if self.winfo_screenwidth() <= 1600:
            geometry = "450x600+1050+100"

        if self.settings_window is None or not self.settings_window.winfo_exists():
            self.settings_window = SettingsWindow(self)
            self.settings_window.geometry(geometry)
            self.settings_window.resizable(False, False)
        else:
            self.settings_window.focus()

class PriceFrame(customtkinter.CTkFrame):
    def __init__(
            self,
            master: any,
            grid: dict,
            **kwargs
    ):
        super().__init__(master, **kwargs)

        self.master: SidebarFrame = master

        self.grid(**grid)
        self.grid_columnconfigure((0, 1,), weight=1, uniform="uniform")
        self.grid_rowconfigure((0, 1, 2, 3), weight=0)

        # STARK GAS
        self.stark_gas_price_label = customtkinter.CTkLabel(
            self,
            text="Stark Gas:",
            font=customtkinter.CTkFont(size=12, weight="bold"),
        )
        self.stark_gas_price_label.grid(
            row=0,
            column=0,
            padx=(10, 0),
            pady=2,
            sticky="w"
        )

        self.stark_gas_price_value_label = customtkinter.CTkLabel(
            self,
            text="N/A",
            font=customtkinter.CTkFont(size=12, weight="bold"),
        )
        self.stark_gas_price_value_label.grid(
            row=0,
            column=1,
            padx=(10, 0),
            pady=(0, 2),
            sticky="w"
        )

        # L1 ETH GAS
        self.l1_eth_gas_price_label = customtkinter.CTkLabel(
            self,
            text="ETH Gas:",
            font=customtkinter.CTkFont(size=12, weight="bold"),
        )
        self.l1_eth_gas_price_label.grid(
            row=1,
            column=0,
            padx=(10, 0),
            pady=2,
            sticky="w"
        )

        self.l1_eth_gas_price_value_label = customtkinter.CTkLabel(
            self,
            text="N/A",
            font=customtkinter.CTkFont(size=12, weight="bold"),
        )

        self.l1_eth_gas_price_value_label.grid(
            row=1,
            column=1,
            padx=(10, 0),
            pady=(0, 2),
            sticky="w"
        )

        # ETH PRICE
        self.eth_price_label = customtkinter.CTkLabel(
            self,
            text="ETH Price:",
            font=customtkinter.CTkFont(size=12, weight="bold"),
        )
        self.eth_price_label.grid(
            row=2,
            column=0,
            padx=(10, 0),
            pady=2,
            sticky="w"
        )

        self.eth_price_value_label = customtkinter.CTkLabel(
            self,
            text="N/A",
            font=customtkinter.CTkFont(size=12, weight="bold"),
        )
        self.eth_price_value_label.grid(
            row=2,
            column=1,
            padx=(10, 0),
            pady=(0, 2),
            sticky="w"
        )
        self.set_gas_data()

    def fetch_gas_data(self) -> tuple[str, str, str]:
        stark_gp = GasPrice(block_number='pending')

        loop = asyncio.get_event_loop()
        stark_gas_price = loop.run_until_complete(stark_gp.get_stark_block_gas_price())

        if stark_gas_price is None:
            stark_gas_price = "N/A"
        else:
            stark_gas_price = round(stark_gas_price / 10 ** 9, 2)

        l1_gas_price = get_eth_mainnet_gas_price('https://rpc.ankr.com/eth')
        if l1_gas_price is None:
            l1_gas_price = "N/A"

        eth_price = GeckoPricer.get_simple_price_of_token_sync("ethereum")
        if eth_price is None:
            eth_price = "N/A"

        return str(stark_gas_price), str(l1_gas_price), str(eth_price)

    def set_gas_data(self):

        def _(loop):
            asyncio.set_event_loop(loop)
            self.master.set_refresh_image(True)
            try:
                stark_gas_price, l1_gas_price, eth_price = self.fetch_gas_data()
                self.stark_gas_price_value_label.configure(text=stark_gas_price)
                self.l1_eth_gas_price_value_label.configure(text=l1_gas_price)
                self.eth_price_value_label.configure(text=eth_price)
                self.master.set_refresh_image(False)
            except RuntimeError as e:
                self.master.set_refresh_image(False)

        Thread(
            target=_,
            args=(asyncio.get_event_loop(), ),
            name="gas_price_thread"
        ).start()


from pynput.keyboard import Listener, Controller
from pynput.keyboard import Key, KeyCode
from typing import Union, List, Tuple
from enum import Enum
import time
from SleepCountdown.SleepCountdown import sleep_countdown
import pickle
import serial

KeyState = Enum("KeyState", "Pressed Released")

KEY_UP_ARROW = 0xDA
KEY_DOWN_ARROW = 0xD9
KEY_LEFT_ARROW = 0xD8
KEY_RIGHT_ARROW = 0xD7
KEY_ESC = 0xB1

"""

"""

def int_to_bytes(x: int) -> bytes:
    return x.to_bytes((x.bit_length() + 7) // 8, 'big')

class RecordKeys:
    def __init__(self):
        self._last_action_time = time.time()
        self._curr_pressed_keys = dict()
        self._recorded_keys = []

    def on_press(self, key: Union[KeyCode, Key]):
        if key in self._curr_pressed_keys:  # key is already pressed, no need to do anything
            return

        print(key)

        self._curr_pressed_keys[key] = time.time()
        self._recorded_keys.append((key, KeyState.Pressed, time.time() - self._last_action_time))
        self._last_action_time = time.time()

    def on_release(self, key: Union[KeyCode, Key]):
        del self._curr_pressed_keys[key]
        self._recorded_keys.append((key, KeyState.Released, time.time() - self._last_action_time))
        self._last_action_time = time.time()

        if key == Key.esc:
            return False  # stop the listener

    def record(self) -> List[Tuple[Union[KeyCode, Key], KeyState, float]]:
        with Listener(on_press=self.on_press, on_release=self.on_release) as listener:
            listener.join()

        return self._recorded_keys

def send_print(serial_port: serial.Serial, data):
    serial_port.write(data)
    print(int.from_bytes(data, 'big'))

def parse_key(key: Union[KeyCode, Key]) -> bytes:
    if isinstance(key, KeyCode):
        return str(key).replace("'", '').encode()

    if key == Key.up:
        return int_to_bytes(KEY_UP_ARROW)

    elif key == Key.down:
        return int_to_bytes(KEY_DOWN_ARROW)

    elif key == Key.left:
        return int_to_bytes(KEY_LEFT_ARROW)

    elif key == Key.right:
        return int_to_bytes(KEY_RIGHT_ARROW)

    elif key == Key.space:
        return b' '

    elif key == Key.esc:
        return int_to_bytes(KEY_ESC)

    else:
        raise ValueError("Only characters and arrows")

def send_actions(recorded_keys: List[Tuple[Union[KeyCode, Key], KeyState, float]], serial_port: serial.Serial):
    to_send: bytes

    for action in recorded_keys:
        send_print(serial_port, parse_key(action[0]))
        send_print(serial_port, int_to_bytes(action[1].value))
        send_print(serial_port, (int(action[2] * 1000000)).to_bytes(4, 'big', signed=False) + b'\x00')  # + b'\x00'
        print()

def save_object(obj, filename):
    with open(filename, 'wb') as output:  # Overwrites any existing file.
        pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)

def main():
    time.sleep(0.5)
    print("Start")

    recorded_keys = RecordKeys().record()
    print(recorded_keys)

    save_object(recorded_keys, 'recorded_keys.pkl')

    print("Done record, now do action")

    ser = serial.Serial('COM4')

    sleep_countdown(2)

    send_actions(recorded_keys, ser)

if __name__ == '__main__':
    main()


#!/usr/bin/env python
# coding: utf-8

# In[1]:

#------------------------------------------------------
#             Start The Project
#------------------------------------------------------

# In[2]:

#------------------------------------------------------
#             Import Required Libary
#------------------------------------------------------
import math
import numpy  as np
import pandas as pd
import time   as ti
import statsmodels.api as sm
import seaborn as sns
import matplotlib.pyplot as plt
sns.set()
from scipy.sparse.csgraph import laplacian
from sklearn.cluster import KMeans
from sklearn.metrics import accuracy_score
from sklearn.metrics.cluster import normalized_mutual_info_score
from sklearn.metrics import mutual_info_score
from scipy.stats import entropy
import networkx as nx
from sklearn.neighbors import NearestNeighbors
#------------------------------------------------------

# In[3]:

#------------------------------------------------------
#             Define For Select Row Of Matrix
#------------------------------------------------------
def Index_Select(matrix, i):
    return [row[i] for row in matrix]
#------------------------------------------------------

# In[4]:

#------------------------------------------------------
#             Calculate Count Of Cluster
#------------------------------------------------------
def Cluster_Count(Main_Labels):

    input_list=Main_Labels
    l1 = []
    count = 0
    for item in input_list:
        if item not in l1:
            count += 1
            l1.append(item)
    Cluster_Count=count
    return Cluster_Count
#------------------------------------------------------

# In[5]:

#------------------------------------------------------
#             Definishion K_Means Algoritm (Clustering)
#------------------------------------------------------
def K_Means_Clustering(Data_Set,Count_Of_Cluster):

    kmeans = KMeans(Count_Of_Cluster)
    kmeans.fit(Data_Set)
    identified_clusters = kmeans.fit_predict(Data_Set)
    kmeans=pd.DataFrame(identified_clusters, index= None)
    kmeans_Label=np.matrix(kmeans)
    return kmeans_Label
#------------------------------------------------------

# In[6]:

#------------------------------------------------------
#             Definishion accuracy
#------------------------------------------------------
def Acc(Main_Labels,K_Labels):

    P=Main_Labels
    Q=np.array(K_Labels).ravel().tolist()

    return accuracy_score(P,Q)
#------------------------------------------------------

# In[7]:

#------------------------------------------------------
#             Definishion normalized mutualinformation
#------------------------------------------------------
def NMI(Main_Labels,K_Labels):

    P=Main_Labels
    Q=np.array(K_Labels).ravel().tolist()
    I_PQ=mutual_info_score(P,Q)
    H_P=entropy(P)
    H_Q=entropy(Q)

    return I_PQ/((H_P*H_Q)**(1/2))
#------------------------------------------------------

# In[8]:

#------------------------------------------------------
#             Definision D in MFFS Article
#------------------------------------------------------
def D_Value(K,W):
    Matrix=np.matrix(W)
    S=np.dot(W.T,W)
    S_List=[]
    for i in range(K):
        S_List.append(S[i][i])
    diag=np.diag(S_List)
    D=(diag**(1/2))
    return D
#------------------------------------------------------

# In[9]:

#------------------------------------------------------
#             Definision MFFS Algoritm
#------------------------------------------------------
def MFFS(X,K,Steps,Alpha,Break_Value):

    #-----------
    #Inter Parametr And Set  Need Value
    #-----------
    X                   =  np.array(Main_Data_Set)
    Y                   =  np.array(Main_Data_Set)
    Row_Number          =  len(X)
    Column_Number       =  len(X[0])
    W                   =  np.random.rand(Column_Number,K)
    H                   =  np.random.rand(K,Column_Number)
    W_Final_Norm        =  []
    W_Final_Norm_Index  =  []
    F_List              =  []
    F_Steps_List        =  []
    #-----------
    #End
    #-----------

    #-----------
    #Start Algoritm  For Update
    #-----------
    Start=ti.time()
    for i in range(Steps):

        #-----------
        #  Set D
        #-----------
        D=D_Value(K,W)
        #-----------

        #-----------
        #  Set W
        #-----------
        W=np.dot(W,np.linalg.inv(D))
        #-----------

        #-----------
        #  Set H
        #-----------
        H=np.dot(D,H)
        #-----------

        #-----------
        #  Update W
        #-----------
        W_UP=np.dot(np.dot(X.T,X),H.T) + Alpha*W
        W_DOWN=np.dot(np.dot(np.dot(np.dot(X.T,X),W),H),H.T) + Alpha*(np.dot(np.dot(W,W.T),W))
        W=W*(W_UP/W_DOWN)
        #-----------

        #-----------
        #  Update H
        #-----------
        H_UP=(np.dot(np.dot(W.T,X.T),X))
        H_DOWN=np.dot(np.dot(np.dot(np.dot(W.T,X.T),X),W),H)
        H=H*(H_UP/H_DOWN)
        #-----------

        #-----------
        # Calculate Error(E=X-XWH)
        #-----------
        Error=np.linalg.norm(X-(np.dot(np.dot(X,W),H)))
        #-----------

        #-----------
        #  Calculate F Function in MFFS Article
        #-----------
        F_Part_1= (1/2)*((np.linalg.norm(X-np.dot(np.dot(X,W),H)))**2)
        F_Part_2=(Alpha/4)*((np.linalg.norm(np.dot(W,W.T)-Error))**2)
        F=F_Part_1+F_Part_2
        F_List.append(F)
        F_Steps_List.append(i)
        #-----------

        #-----------
        # Define If For Break
        #-----------
        if Error<=Break_Value:
            break
        #-----------
    #-----------
    #End Algoritm  For Update
    #-----------

    #-----------
    #  Calculate Norm OF W And Sort Index And Norm
    #-----------
    for i in range(0,Column_Number):

        #-----------
        # Append Norm And Index To List
        #-----------
        W_Norm          = np.linalg.norm(W[i])
        W_Final_Norm.append(W_Norm)
        W_Final_Norm_Index.append(i+1)

    #-----------
    #  Sort W List By Norm Value
    #-----------
    W_Final_Norm         = np.array(W_Final_Norm)
    W_Final_Norm_Index   = np.array(W_Final_Norm_Index)
    W_Norm_Index         = np.array([[W_Final_Norm],[W_Final_Norm_Index]])
    W_Norm_Index         = W_Norm_Index.T
    W_Norm_Index         = np.matrix(W_Norm_Index)
    W_Sorted             = W_Norm_Index[np.argsort(W_Norm_Index.A[:, 0])]
    W_Sorted             = np.array(W_Sorted)
    Final_Index          = Index_Select(W_Sorted,1)
    Final_Index.reverse()
    W_Sorted             = np.array(W_Sorted)
    Final_Norm           = Index_Select(W_Sorted,0)
    Final_Norm.reverse()
    #-----------
    #End
    #-----------

    #-----------
    #Select Need Dimension Of Main Dataset  And Show
    #-----------
    Dimension_Index_List =[]
    Final_Index_List     =[]
    for i in range(K):
        My_Index=int(Final_Index[i]-1)
        Dimension_Index_List.append(My_Index)
        Final_Index_List.append(int(Final_Index[i]))
    Data_Set_Main    = np.array(Y.T)
    Selected_Column  = Data_Set_Main[Dimension_Index_List]
    return Selected_Column.T
    #-----------
    #End
    #-----------

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

# In[10]:

#------------------------------------------------------
#     Definision For Return MFFS Dataset With Multi K
#------------------------------------------------------
def Multi_MFFS(K):
    Data_Set=MFFS(Main_Data_Set,K,Steps,Alpha,Break_Value)
    return  Data_Set
#------------------------------------------------------

# In[11]:

#------------------------------------------------------
#     Definision For Return Multi MFFS
#------------------------------------------------------
def Data_Sets_MFFS(K):
    return Multi_MFFS(K)
#------------------------------------------------------

# In[12]:

#------------------------------------------------------
#             Definision KNN Algorim
#------------------------------------------------------
def KNN(Matrix_Graph,K,Kind):
    knn = NearestNeighbors(algorithm='auto',  n_neighbors=K, p=2);
    knn.fit(Matrix_Graph);
    distances, indices = knn.kneighbors(Matrix_Graph);
    if Kind==0:
        return distances
    if Kind==1:
        return  indices
#------------------------------------------------------

# In[13]:

#------------------------------------------------------
#             Definision W In SLSDR Article
#------------------------------------------------------
def W(X,K,sigma):
    n=len(X);
    K=5
    W = np.zeros((n, n));
    distances =KNN(X,K,0)
    indices   =KNN(X,K,1)
    for i in range(n):
        b=indices[i];
        for j in range(K):
            W[i,b[j]] = math.exp(-((distances[i,j])**2)/(sigma**2));
            W[b[j],i] = math.exp(-((distances[i,j])**2)/(sigma**2));
    return W
#------------------------------------------------------

# In[14]:

#------------------------------------------------------
#             Definision For  U_Value Function
#------------------------------------------------------
def Chech_Zero(Number):
    return max(Number,10**(-8))
#------------------------------------------------------

# In[15]:

#------------------------------------------------------
#             Calculate Diagonal Of Matrix
#------------------------------------------------------
def Diagonal_Matrix(First_Matrix):
    D_Norm_List=[]
    for i in range(0,len(First_Matrix)):
                   D_Norm= np.linalg.norm(First_Matrix[i])
                   D_Norm_List.append(D_Norm)
    return np.diag(D_Norm_List)
#------------------------------------------------------

# In[16]:

#------------------------------------------------------
#             Definision U in SLSDR Article
#------------------------------------------------------
def U_Value(X,V,S):
    E=X-(np.dot(X,np.dot(S,V)))
    E_Norm_List=[]
    for i in range(0,len(E)):
        U_Norm          = np.linalg.norm(E[i])
        U_ii=1/ Chech_Zero(U_Norm)
        E_Norm_List.append(U_ii)
    return np.diag(E_Norm_List)
#------------------------------------------------------

# In[17]:

#------------------------------------------------------
#          Definision SLSDR Algoritm
#------------------------------------------------------
def SLSDR(X,K,Steps,Alpha,Beta,Lambda,Break_Value,sigma):

    #-----------
    #Inter Parametr And Set  Need Value
    #-----------
    X                   =  np.array(X)
    Y                   =  np.array(X)
    Row_Number          =  len(X)
    Column_Number       =  len(X[0])
    S                   =  np.random.rand(Column_Number,K)
    V                   =  np.random.rand(K,Column_Number)
    S_Final_Norm        =  []
    S_Final_Norm_Index  =  []
    #-----------
    #End
    #-----------

    #-----------
    #Start Algoritm
    #-----------
    Start=ti.time()
    for i in range(Steps):

        #-----------
        #  Set W_S
        #-----------
        W_S=W(X,K,sigma)
        #-----------

        #-----------
        #  Set D_S
        #-----------
        D_S=Diagonal_Matrix(W_S)
        #-----------

        #-----------
        #  Set W_V
        #-----------
        W_V=W(X.T,K,sigma)
        #-----------

        #-----------
        #  Set D_V
        #-----------
        D_V=Diagonal_Matrix(W_V)
        #-----------

        #-----------
        #  Set U
        #-----------
        U=U_Value(X,V,S)
        #-----------

        #-----------
        #  Update S
        #-----------
        S_UP1     = np.dot(np.dot(np.dot(X.T,U),X),V.T)
        S_UP2     = np.dot(Alpha * (np.dot(np.dot(X.T,W_S),X)) + ((np.identity(Column_Number)) *  (Beta + Lambda)   ),S)
        S_UP      = S_UP1 + S_UP2

        S_DOWN1   = np.dot(np.dot(np.dot(np.dot(np.dot(X.T,U),X),S),V),V.T)
        S_DOWN2   = np.dot((Alpha*(np.dot(np.dot(X.T,D_S),X))) + (Beta*np.ones(Column_Number))+ Lambda *np.dot(S,S.T),S)
        S_DOWN    = S_DOWN1+S_DOWN2

        S         =S*(S_UP/S_DOWN)
        #-----------

        #-----------
        #  Update V
        #-----------
        V_UP      =np.dot(np.dot(np.dot(S.T,X.T),U),X) +   Alpha*(np.dot(V,W_V))

        V_DOWN    =np.dot(np.dot(np.dot(np.dot(np.dot(S.T,X.T),U),X),S),V)  +  Alpha*(np.dot(V,D_V))

        V         =V*(V_UP/V_DOWN)
        #-----------

    #-----------
    #Calculate Norm OF W And Sort Index And Norm
    #-----------
    for i in range(0,Column_Number):
        S_Norm          = np.linalg.norm(S[i])
        S_Final_Norm.append(S_Norm)
        S_Final_Norm_Index.append(i+1)

    S_Final_Norm         = np.array(S_Final_Norm)
    S_Final_Norm_Index   = np.array(S_Final_Norm_Index)
    S_Norm_Index         = np.array([[S_Final_Norm],[S_Final_Norm_Index]])
    S_Norm_Index         = S_Norm_Index.T
    S_Norm_Index         = np.matrix(S_Norm_Index)
    S_Sorted             = S_Norm_Index[np.argsort(S_Norm_Index.A[:, 0])]
    S_Sorted             = np.array(S_Sorted)
    Final_Index          = Index_Select(S_Sorted,1)
    Final_Index.reverse()
    S_Sorted             = np.array(S_Sorted)
    Final_Norm           = Index_Select(S_Sorted,0)
    Final_Norm.reverse()
    #-----------
    #End
    #-----------

    #-----------
    # Select Need Dimension Of Main Dataset  And  Show
    #-----------
    Dimension_Index_List=[]
    Final_Index_List=[]
    for i in range(K):
        My_Index=int(Final_Index[i]-1)
        Dimension_Index_List.append(My_Index)
        Final_Index_List.append(int(Final_Index[i]))
    Data_Set_Main=np.array(Y.T)
    Selected_Column=Data_Set_Main[Dimension_Index_List]
    return Selected_Column.T
    #-----------
    #End
    #-----------

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

# In[18]:

#------------------------------------------------------
#           Definision For Return SLSDR Dataset With Multi K
#------------------------------------------------------
def Multi_SLSDR(K):
    Data_Set=SLSDR(Main_Data_Set,K,Steps,Alpha,Beta,Lambda,Break_Value,sigma)
    return  Data_Set
#------------------------------------------------------

# In[19]:

#------------------------------------------------------
#           Definision For Return Multi SLSDR
#------------------------------------------------------
def Data_Sets_SLSDR(K):
    return Multi_SLSDR(K)
#------------------------------------------------------

# In[20]:

#------------------------------------------------------
#          Definision  For Return Final Result
#------------------------------------------------------
def Result(Main_Labels,Dimension_Select_List,Kmeans_Count,sigma):

    #-----------
    #   Define Empty List For BaseLine Method
    #-----------
    ACC_List_BaseLine     =[]
    NMI_List_BaseLine     =[]
    ACC_Std_BaseLine      =[]
    NMI_Std_BaseLine      =[]
    #-----------

    #-----------
    #   Define Empty List For MFFS Method
    #-----------
    Multi_ACC_List_MFFS   =[]
    Multi_NMI_List_MFFS   =[]
    ACC_List_MFFS         =[]
    NMI_List_MFFS         =[]
    ACC_Std_MFFS          =[]
    NMI_Std_MFFS          =[]
    #-----------

    #-----------
    #   Define Empty List For SLSDR Method
    #-----------
    Multi_ACC_List_SLSDR  =[]
    Multi_NMI_List_SLSDR  =[]
    ACC_List_SLSDR        =[]
    NMI_List_SLSDR        =[]
    ACC_Std_SLSDR         =[]
    NMI_Std_SLSDR         =[]
    #-----------

    #-----------
    #   Calculate  Acc And NMI For BaseLine Method
    #-----------
    K_Means_BaseLine =K_Means_Clustering(Main_Data_Set,Cluster_Count(Main_Labels))
    K_Labels_BaseLine=K_Means_BaseLine
    for ij in range(len(Dimension_Select_List)):

        ACC_List_BaseLine.append(Acc(Main_Labels,K_Labels_BaseLine))
        NMI_List_BaseLine.append(NMI(Main_Labels,K_Labels_BaseLine))
    #-----------

    #-----------
    #   Calculate  Acc And NMI For MFFS  And SLSDR  Method
    #-----------

    #-----------
    #  Define i(Dimension_Select_List.  For Example:[1,12]. Select 1 AND 12 Important Dimention .)
    #-----------
    for i in Dimension_Select_List:

        #-----------
        #  Set Dataset
        #-----------
        Data_Set_MFFS  =Data_Sets_MFFS(i)
        Data_Set_SLSDR =Data_Sets_SLSDR(i)
        #-----------

        #-----------
        # Define j(Kmeans_Count. For Example:(5).  It Sends Each Dataset To The Kmeans Algoritm  5 Times )
        #-----------
        for j in range(Kmeans_Count):

            #-----------
            #  Send MFFS To Acc And NMI
            #-----------
            K_Means_MFFS =K_Means_Clustering(Data_Set_MFFS,Cluster_Count(Main_Labels))
            K_Labels_MFFS=K_Means_MFFS
            Multi_ACC_List_MFFS.append(Acc(Main_Labels,K_Labels_MFFS))
            Multi_NMI_List_MFFS.append(NMI(Main_Labels,K_Labels_MFFS))

            #-----------
            #   Send SLSDR To Acc And NMI
            #-----------
            K_Means_SLSDR =K_Means_Clustering(Data_Set_SLSDR,Cluster_Count(Main_Labels))
            K_Labels_SLSDR=K_Means_SLSDR
            Multi_ACC_List_SLSDR.append(Acc(Main_Labels,K_Labels_SLSDR))
            Multi_NMI_List_SLSDR.append(NMI(Main_Labels,K_Labels_SLSDR))

        #-----------
        #   Calculate Mean Of MFFS Dateset(Acc And NMI) And Clear List
        #-----------
        ACC_List_MFFS.append(np.mean(Multi_ACC_List_MFFS))
        NMI_List_MFFS.append(np.mean(Multi_NMI_List_MFFS))
        Multi_ACC_List_MFFS.clear()
        Multi_NMI_List_MFFS.clear()
        #-----------

        #-----------
        #    Calculate Mean Of SLSDR Dateset(Acc And NMI) And Clear List
        #-----------
        ACC_List_SLSDR.append(np.mean(Multi_ACC_List_SLSDR))
        NMI_List_SLSDR.append(np.mean(Multi_NMI_List_SLSDR))
        Multi_ACC_List_SLSDR.clear()
        Multi_NMI_List_SLSDR.clear()
        #-----------

    #-----------
    #   Calculate STD OF ACC And NMI For BaseLine And MFFS And SLSDR
    #-----------
    ACC_Std_BaseLine.append(np.std(ACC_List_BaseLine))
    NMI_Std_BaseLine.append(np.std(NMI_List_BaseLine))
    ACC_Std_MFFS.append(np.std(ACC_List_MFFS))
    NMI_Std_MFFS.append(np.std(NMI_List_MFFS))
    ACC_Std_SLSDR.append(np.std(ACC_List_SLSDR))
    NMI_Std_SLSDR.append(np.std(NMI_List_SLSDR))
    #-----------

    #-----------
    #Show ACC in 2*D
    #-----------
    X_List_Acc=Dimension_Select_List
    Y1_List_Acc=ACC_List_BaseLine
    Y2_List_Acc=ACC_List_MFFS
    Y3_List_Acc=ACC_List_SLSDR
    plt.plot(X_List_Acc,Y1_List_Acc,color='lightcoral',marker='D',markeredgecolor='red' , label='BaseLine')
    plt.plot(X_List_Acc,Y2_List_Acc,color='lightcoral',marker='D',markeredgecolor='blue'  , label='MFFS')
    plt.plot(X_List_Acc,Y3_List_Acc,color='lightcoral',marker='D',markeredgecolor='green'  , label='SLSDR')
    plt.ylim(0,0.2)
    plt.xlim(20,100)
    plt.xlabel('Count Of Dimension')
    plt.ylabel('Acc Value')
    plt.title('ACC')
    plt.legend()
    plt.show()
    #-----------
    #End
    #-----------

    #-----------
    #Show Show NMI in 2*D
    #-----------
    X_List_NMI=Dimension_Select_List
    Y1_List_NMI=NMI_List_BaseLine
    Y2_List_NMI=NMI_List_MFFS
    Y3_List_NMI=NMI_List_SLSDR
    plt.plot(X_List_NMI,Y1_List_NMI,color='lightcoral',marker='D',markeredgecolor='red' , label='BaseLine')
    plt.plot(X_List_NMI,Y2_List_NMI,color='lightcoral',marker='D',markeredgecolor='blue', label='MFFS')
    plt.plot(X_List_NMI,Y3_List_NMI,color='lightcoral',marker='D',markeredgecolor='green' , label='SLSDR')
    plt.ylim(0.2,0.6)
    plt.xlim(20,100)
    plt.xlabel('Count Of Dimension')
    plt.ylabel('NMI Value')
    plt.title('NMI')
    plt.legend()
    plt.show()
    #-----------
    #End
    #-----------
#------------------------------------------------------

# In[21]:

#------------------------------------------------------
#           Enter First Data And Run Algoritm
#------------------------------------------------------
#   Main_Data_Set = [
#                   [5,3,0,1],
#                   [4,0,0,1],
#                   [1,1,0,5],
#                   [1,0,0,4],
#                  ]

#Main_Labels =[1,0,0,2]

#-----------
#  Set Main Dataset
#-----------
Main_Data_Set =pd.read_csv('C:\\Users\\babak_Nouri\\Desktop\\ORL_64x64_fea.CSV', header=None, skiprows=1)
#-----------

#-----------
#  Set Main Label
#-----------
Labels = pd.read_csv('C:\\Users\\babak_Nouri\\Desktop\\ORL_64x64_gnd.CSV', header=None, skiprows=1)
Main_Labels=np.array(Labels).ravel().tolist()
#-----------

#-----------
#  Set Steps For Count Of Update
#-----------
Steps=30
#-----------

#-----------
#  Set Aloha For MFFS  And SLSDR Algoritm
#-----------
Alpha=0.001
#-----------

#-----------
#  Set Beta For SLSDR Algoritm
#-----------
Beta=0.001
#-----------

#-----------
#  Set Lambda For SLSDR Algoritm
#-----------
Lambda=100
#-----------

#-----------
#  Set Value for Break Algoritm
#-----------
Break_Value=4
#-----------

#-----------
#  Set Number Of Dimension For
#-----------
Dimension_Select_List=[20,30,40,50,60,70,80,90,100]
#-----------

#-----------
#  Set Count Of Send Each Dataset To Kmeans Algoritm
#-----------
Kmeans_Count=5
#-----------

#-----------
#  Set sigma For SLSDR Algoritm
#-----------
sigma=100
#-----------

#-----------
#  Call The Result Function
#-----------
Result(Main_Labels,Dimension_Select_List,Kmeans_Count,sigma)
#------------------------------------------------------

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:


import numpy as np
import tensorflow
import tensorflow as tf

from keras.layers import Dense, Flatten, Conv2D, Embedding, Input, Dot
from pyspark.sql import SparkSession
from tqdm import tqdm

from keras import regularizers

"""
tf2 customized train step and test step
"""

spark = SparkSession.builder.master("local[2]").appName("SparkByExamples").getOrCreate()
NUM = 100
print("NUM = ", NUM)

input_tar = Input(shape=(1, ))
input_pos = Input(shape=(1, ))
input_neg = Input(shape=(1, ))
embedding_query = Embedding(input_length=1, input_dim=NUM, output_dim=8,
                                         name='embedding_query', trainable=True,
                                         embeddings_regularizer= regularizers.L2(0.01),
                                         embeddings_initializer='random_uniform',
                            )  # shape T,1,32
d = Dense(32, activation='relu', name="dense_0" )
embedding_search = Embedding(input_length=1, input_dim=NUM, output_dim=32,
                                          name='embedding_search', trainable=True,
                                          embeddings_regularizer= regularizers.L2(0.01),
                                          embeddings_initializer='zeros')  # shape T,1,32
tar = embedding_query(input_tar)  # shape T,1,8
pos = embedding_search(input_pos)  # shape T,1,32
neg = embedding_search(input_neg)  # shape T,1,32
tmp = d(tar)  # shape T,1,32
p = tf.squeeze(Dot(axes=2)([tmp, pos]), axis=[2])  # shape T,1
n = tf.squeeze(Dot(axes=2)([tmp, neg]), axis=[2])  # shape T,1
logits = p - n

model_0 = tf.keras.Model(inputs=[input_tar, input_pos, input_neg], outputs=logits, name="model_0")
tf.keras.utils.plot_model(model_0, "foo_1.png", show_shapes=True)

# customized train and test step
# Instantiate an optimizer.
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
# Instantiate a loss function.
loss_fn = tf.keras.losses.BinaryCrossentropy(from_logits=True)
# Prepare the metrics.
train_entropy_metric = tf.keras.metrics.BinaryCrossentropy(from_logits=True, name="train_entropy_metric")
test_entropy_metric = tf.keras.metrics.BinaryCrossentropy(from_logits=True, name="test_entropy_metric")

train_loss = tf.keras.metrics.Mean(name='train_loss')
test_loss = tf.keras.metrics.Mean(name='test_loss')

@tf.function
def train_step(x, y):
    with tf.GradientTape() as tape:
        logits = model_0(x, training=True)
        loss_value = loss_fn(y, logits)
        # Add any extra losses created during the forward pass.
        #loss_value += sum(model_0.losses)
    grads = tape.gradient(loss_value, model_0.trainable_variables)
    optimizer.apply_gradients(zip(grads, model_0.trainable_variables))

    train_loss(loss_value)
    train_entropy_metric(y, logits)

@tf.function
def test_step(x, y):
    logits = model_0(x, training=False)
    loss_value = loss_fn(y, logits)

    test_loss(loss_value)
    test_entropy_metric(y, logits)

EPOCHS = 0

train_data = spark.sparkContext.parallelize(np.random.randint(10, size=(1024, 3)).tolist(), 8)\
    .map(lambda x: [int(x[0]), int(x[1]), int(x[2])]).repartition(16)\
        .mapPartitions(lambda it: [list(it)]).cache()

test_data = spark.sparkContext.parallelize(np.random.randint(10, size=(1024, 3)).tolist(), 8)\
    .map(lambda x: [int(x[0]), int(x[1]), int(x[2])]).repartition(16)\
        .mapPartitions(lambda it: [list(it)]).cache()

for epoch in range(EPOCHS):
    train_it = train_data.toLocalIterator()
    test_it = test_data.toLocalIterator()
    it = zip(train_it, test_it)
    train_entropy_metric.reset_states()
    test_entropy_metric.reset_states()
    train_loss.reset_states()
    test_loss.reset_states()

    with tqdm(total=16, desc="process") as pbar:
        i = 0
        for u in tqdm(it, position=0, leave=True):
            i += 1
            pbar.update(1)
            train = np.array(u[0])
            test = np.array(u[1])
            tar = train[:, :1]
            pos = train[:, 1:2]
            neg = train[:, 2:]
            labels = np.ones(tar.shape)

            train_step([train[:, :1], train[:, 1:2], train[:, 2:]], labels)
            test_step([test[:, :1], test[:, 1:2], test[:, 2:]], labels)

            if i % 4 == 0:
                pbar.set_postfix({'epoch': '{0:4d}'.format(epoch),
                                  'train_loss': '{0:1.5f}'.format(train_loss.result()),
                                  'train_entropy': '{0:1.5f}'.format(train_entropy_metric.result()),
                                  'test_loss': '{0:1.5f}'.format(test_loss.result()),
                                  'test_entropy': '{0:1.5f}'.format(test_entropy_metric.result())
                                  })

    pbar.close()

embedding_search_result = model_0.get_layer('embedding_search').get_weights()[0]
print(embedding_search_result.shape, type(embedding_search_result))

def relu(x):
    return np.maximum(0, x)
# embedding as input then dense finally output
tmp_embedding = model_0.get_layer("embedding_query").get_weights()[0] #shape 100 8
tmp_dense = model_0.get_layer("dense_0").get_weights()[0] # 8 32

embedding_query_result = relu(np.dot(tmp_embedding, tmp_dense))

print(embedding_query_result.shape, type(embedding_query_result))

search_df = spark.sparkContext.parallelize(embedding_search_result, 100).map(lambda x: x.tolist()).zipWithIndex()\
    .toDF(["embedding_search","idx"])
query_df = spark.sparkContext.parallelize(embedding_query_result, 100).map(lambda x: x.tolist()).zipWithIndex()\
    .toDF(["embedding_query","idx"])

search_df.join(query_df, ["idx"], "inner").printSchema()


import argparse
import sys
from client import UDPClient

if __name__ == '__main__':
    # arguments
    parser = argparse.ArgumentParser(
        usage="%(prog)s [OPTION]...",
        description="Run a client to send ping and receive pong as well as calculate rtt.",
    )
    parser.add_argument(
        "-ip",
        "--server_ip",
        help=('Set the IP address that the client will connect. Default is 127.0.0.1.'),
        action='store',
        default='127.0.0.1',
    )
    parser.add_argument(
        "-port",
        "--server_port",
        help=('Set the port that the client will connect. Default is 3000.'),
        action='store',
        default=3000,
    )
    parser.add_argument(
        "-l",
        "--logger",
        help='Save all client output in log file.',
        action='store_true',
    )
    parser.add_argument(
        "-c",
        "--csv",
        help='Save all packet data in a csv file.',
        action='store_true',
    )
    parser.add_argument(
        "-t",
        "--timeout",
        help=('Set how long to wait for a client to receive a ' 'response before receiving a timeout, in seconds.'),
        action='store',
        default=10,
    )
    parser.add_argument(
        "-p",
        "--packets",
        help=('Number of packets to send.'),
        action='store',
        default=10,
    )
    args = parser.parse_args()

    # stdout change
    if args.logger:
        previous = sys.stdout
        sys.stdout = open('client_log.txt', 'w', encoding='utf8')

    client = UDPClient(
        server_ip=args.server_ip,
        server_port=int(args.server_port),
        timeout=int(args.timeout),
        number_of_packets=int(args.packets),
        save_csv=args.csv,
    )
    client.run()

    # revert stdout change
    if args.logger:
        sys.stdout.close()
        sys.stdout = previous


import time
import cv2 as cv
import numpy as np
from PySide6 import QtCore, QtWidgets
from LAB.config import setting
from LAB.common.util import img_level
from LAB.common.util import img_convert_qt
from LAB.common.util import img_threshold

CONNECTIVITY = 4  # 연결성
MASK_LIST = [None for _ in range(setting.USER_CHOICE_COUNT)]
MOUSE_LIST = [None for _ in range(setting.USER_CHOICE_COUNT)]
ROI = 0
ZOOM = 1

# 마법봉 윤곽 좌표
def _find_exterior_contours(img):
    ret = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    if len(ret) == 2:
        return ret[0]
    elif len(ret) == 3:
        return ret[1]

class ViewMain(QtWidgets.QGraphicsView):
    call_click_threshold = None

    level_window = setting.DEFAULT_LEVEL_WINDOW  # 윈도우 값 세팅
    level_muscle = setting.DEFAULT_LEVEL_MUSCLE  # 근육 값 세팅

    tool_radio_chk = 1              # 상단 tool 뷰의 라디오 버튼 확인
    threshold = None                # 현재 적용된 쓰레숄드 값
    q_graphic = None                # view 세팅에 사용 됩니다.
    screen_img = None               # 화면에 보여지는 이미지
    screen_rect = None              # 화면에 보여지는 이미지 사각형 크기
    update_level_img = None         # 화면에 업데이트된 레벨 이미지
    gray_scale_img = None           # 내부 에서 사용되는 GRAY SCALE 이미지
    flood_mask = None               # 마법봉 알고리즘 변수
    flood_fill_flags = None         # 마법봉 채우기 변수
    mouse_position_list: list = []  # 사용자 마우스좌표 저장
    mask_img = None                 # 사용자 클릭 마스크 저장

    # 딥줌
    mode = 0
    scale = 1
    center_x = 0
    center_y = 0
    touched_zoom = False
    WIDTH = 512
    HEIGHT = 512

    # QT 예제 기본 VIEW 구조
    def __init__(self, parent=None):
        super(ViewMain, self).__init__(parent)
        self.scene = QtWidgets.QGraphicsScene(self)
        self.q_graphic = QtWidgets.QGraphicsPixmapItem()
        self.scene.addItem(self.q_graphic)
        self.setScene(self.scene)

        # 딥줌
        self.touch_init()

    def setup(self):
        self.screen_rect: QtCore.QRectF = QtCore.QRectF(0.0, 0.0, 513, 513)
        self.setSceneRect(QtCore.QRectF(self.screen_rect))

    # 마법봉 관련 변수 초기화
    def re_default(self):
        self.flood_mask = None
        self.flood_fill_flags = None

    # 마법봉 다시 세팅
    def re_setting(self, img):
        print('ViewMain: resetting')

        # 이미지 관련 변수 초기화
        self.re_default()

        # 이미지 포멧
        # img = cv.imread(path, 1)
        cv_gray = img
        cv_color = cv.cvtColor(img, cv.COLOR_BGR2RGB)

        # cv 이미지 사이즈
        h, w = cv_color.shape[:2]

        # open cv image 준비시간 0.1 초 Delay
        self.screen_img = cv_color.copy()
        self.gray_scale_img = cv_gray.copy()
        time.sleep(0.1)
        self.flood_mask = np.zeros((h + 2, w + 2), np.uint8)
        time.sleep(0.1)
        self.flood_fill_flags = (CONNECTIVITY | cv.FLOODFILL_FIXED_RANGE | cv.FLOODFILL_MASK_ONLY | 255 << 8)
        time.sleep(0.1)

    # mark -  Event method
    def moveEvent(self, e):
        print('ViewMain: moveEvent')

    # mark -  Event method
    def mouseMoveEvent(self, e):
        print('ViewMain: mouseMoveEvent')

    # mark -  Event method
    def mouseReleaseEvent(self, e):
        print('ViewMain: mouseReleaseEvent')

    # mark -  Event method
    def mousePressEvent(self, e):
        print('ViewMain: mousePressEvent')

        x = e.x()
        y = e.y()

        # 딥줌
        if self.mode == ZOOM:
            self.center_x = x
            self.center_y = y
            self.touched_zoom = True
            if e.button() == QtCore.Qt.MouseButton.LeftButton:
                self.zoom_in()
            if e.button() == QtCore.Qt.MouseButton.RightButton:
                self.zoom_out()
        else:
            choice = self.tool_radio_chk
            self.make_threshold(x, y, choice)

    def make_threshold(self, x, y, choice):

        # 정수형 으로 변환
        _x = int(x)
        _y = int(y)

        # error 예외 처리
        h, w = self.gray_scale_img.shape[:2]
        if w < _x or h < _y:
            print('ViewMain: position OVER')
            return
        if _x is 0:
            return

        # 마스크 영역 채우기
        self.flood_mask[:] = 0
        cv.floodFill(self.gray_scale_img, self.flood_mask, (_x, _y), 1,
                     self.threshold,
                     self.threshold,
                     self.flood_fill_flags)
        mask_copy = self.flood_mask[1:-1, 1:-1].copy()

        # 사용자가 선택한 라디오 값 의 마스크와 마우스 포지션 저장
        mouse_position = (_x, _y)
        MASK_LIST[choice] = mask_copy
        MOUSE_LIST[choice] = mouse_position

        # 사용자 클릭 threshold 정보를 보냅니다.
        _call = self.call_click_threshold
        _call(MOUSE_LIST)

        # main view 화면을 업데이트 합니다.
        self.update_screen()

    def update_screen(self):
        print('ViewMain: update_screen')

        # 화면에 보여질 칼라 이미지 레벨을 조정하고
        level_image = img_level.tissue_process(self.screen_img,
                                               0,
                                               self.level_window,
                                               self.level_muscle,
                                               0.1)

        # 이미지 광역 쓰레숄드
        level_image = img_threshold.all_bgr(level_image)

        length = len(MASK_LIST)
        for i in range(0, length):
            # 사용자가 선택한 라디오 값 의 마스크 가져오기
            self.mask_img = MASK_LIST[i]

            # 사용자 선택 쓰레숄드 내부 칠하기
            a, b, c = setting.ROI_COLOR[i]
            level_image[self.mask_img == 255] = [a, b, c]

        # 딥줌
        if self.mode == ZOOM:
            if self.touched_zoom:
                level_image = self.__zoom(level_image, (self.center_x, self.center_y))
            else:
                if not self.scale == 1:
                    level_image = self.__zoom(level_image)
            self.touch_init()

        # 화면에 보여주기
        pix_image = img_convert_qt.bgr_to_pixImage(level_image)
        self.q_graphic.setPixmap(pix_image)
        self.repaint()

    # 레벨이 적용된 환면을 업데이트 합니다.
    def update_level(self):
        print('ViewMain: update_level')

        # 이미지 레벨링
        level_image = img_level.tissue_process(self.screen_img,
                                               0,
                                               self.level_window,
                                               self.level_muscle,
                                               0.1)
        # 레벨 적용 이미지 화면에 보이기
        level_image = img_threshold.all_bgr(level_image)

        # 쓰레숄드 가능한 이미지 업데이트
        self.gray_scale_img = level_image

        # 화면에 보이는 이미지
        pix_image = img_convert_qt.bgr_to_pixImage(level_image)
        self.q_graphic.setPixmap(pix_image)
        self.repaint()
        return level_image

    # 사용자가 선택한 threshold radio 버튼을 업데이트 합니다.
    def user_threshold_change(self, user_choice):
        self.tool_radio_chk = user_choice
        self.update_screen()

    def set_mouse_list(self, mouse_data):
        for i in range(0, len(mouse_data)):
            _tuple = mouse_data[i]
            if _tuple is None:
                pass
            else:
                x = _tuple[0]
                y = _tuple[1]

                # 포지션 값으로 쓰레숄드를 만들어 줍니다.
                self.make_threshold(x, y, i)

    @classmethod
    def clean_mask(cls):
        for i in range(0, setting.USER_CHOICE_COUNT):
            MASK_LIST[i] = None

    @classmethod
    def clean_mouse(cls):
        for i in range(0, setting.USER_CHOICE_COUNT):
            MOUSE_LIST[i] = None

    @classmethod
    def get_mask_list(cls):
        return MASK_LIST

    @classmethod
    def get_mouse_list(cls):
        return MOUSE_LIST

    # 딥줌
    def __zoom(self, img, center=None):
        height, width = img.shape[:2]
        if center is None:
            #   중심값이 초기값일 때의 계산
            center_x = int(width / 2)
            center_y = int(height / 2)
            radius_x, radius_y = int(width / 2), int(height / 2)
        else:
            #   특정 위치 지정시 계산
            rate = height / width
            center_x, center_y = center

            #   비율 범위에 맞게 중심값 계산
            if center_x < width * (1-rate):
                center_x = width * (1-rate)
            elif center_x > width * rate:
                center_x = width * rate
            if center_y < height * (1-rate):
                center_y = height * (1-rate)
            elif center_y > height * rate:
                center_y = height * rate

            center_x, center_y = int(center_x), int(center_y)
            left_x, right_x = center_x, int(width - center_x)
            up_y, down_y = int(height - center_y), center_y
            radius_x = min(left_x, right_x)
            radius_y = min(up_y, down_y)

        # 실제 zoom 코드
        radius_x, radius_y = int(self.scale * radius_x), int(self.scale * radius_y)

        # size 계산
        min_x, max_x = center_x - radius_x, center_x + radius_x
        min_y, max_y = center_y - radius_y, center_y + radius_y

        # size 에 맞춰 이미지를 자른다
        cropped = img[min_y:max_y, min_x:max_x]

        # 원래 사이즈로 늘려서 리턴
        new_cropped = cv.resize(cropped, (width, height))

        return new_cropped

    def touch_init(self):
        self.center_x = self.WIDTH / 2
        self.center_y = self.HEIGHT / 2
        self.touched_zoom = False
        self.scale = 1

    def zoom_out(self):
        print('zoom_out')
        # scale 값을 조정하여 zoom-out
        if self.scale < 1:
            self.scale += 0.1
        if self.scale == 1:
            self.center_x = self.WIDTH
            self.center_y = self.HEIGHT
            self.touched_zoom = False

        self.update_screen()

    def zoom_in(self):
        print('zoom_in')
        if self.scale > 0.2:
            self.scale -= 0.1

        self.update_screen()


import functools
from testcase import Document
from testcase import DocumentTranslationTest
from preparer import DocumentTranslationPreparer, DocumentTranslationClientPreparer as _DocumentTranslationClientPreparer
from azure.core.exceptions import HttpResponseError
from azure.ai.translation.document import DocumentTranslationClient, DocumentTranslationInput, TranslationTarget
DocumentTranslationClientPreparer = functools.partial(_DocumentTranslationClientPreparer, DocumentTranslationClient)

class TestCancelTranslation(DocumentTranslationTest):

    @DocumentTranslationPreparer()
    @DocumentTranslationClientPreparer()
    def test_cancel_translation(self, client):
        '''
            some notes (test sporadically failing):
            1. use a large number of translations
                - because when running tests the translations sometimes finishes with status 'Succeeded'
                  before we call the 'cancel' endpoint!
            2. wait sometime after calling 'cancel' and before calling 'get status'
                - in order for the cancel status to propagate
        '''
        # submit translation operation
        docs_count = 8 # large number of docs
        poller = self._begin_and_validate_translation_with_multiple_docs(client, docs_count, wait=False)

        # cancel translation
        client.cancel_translation(poller.id)

        # wait for propagation
        wait_time = 15  # for 'canceled' status to propagate, if test failed, increase this value!
        self.wait(duration=wait_time)

        # check translation status
        translation_details = client.get_translation_status(poller.id)
        self._validate_translations(translation_details, status="Canceled", total=docs_count)
        try:
            poller.wait()
        except HttpResponseError:
            pass  # expected if the operation was already in a terminal state.


from django import forms
from django.contrib.auth.models import User
from django.forms import Textarea, TextInput, NullBooleanSelect, Select, HiddenInput
from consorcios.models import *
from .models import *
from contabilidad.models import *
from django.db.models import Q
from django_afip.models import PointOfSales
from admincu.forms import FormControl

from django.db.models import Max

class ingresoForm(FormControl, forms.ModelForm):
	class Meta:
		model = Ingreso
		fields = [
			'nombre', 'prorrateo',
			'prioritario', 'cuenta_contable'
		]
		labels = {
			'nombre': "Nombre del ingreso",
			'prioritario': "Tiene prioridad de cobro?",
			'prorrateo': "Prorratea por m2?",
		}
		widgets = {
			'prorrateo': NullBooleanSelect(),
			'prioritario': NullBooleanSelect(),
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		if not self.consorcio.superficie:
			self.fields.pop('prorrateo')
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(
				nivel=4,
				).order_by('numero')
		if self.instance.primario:
			self.fields.pop('cuenta_contable')

class gastoForm(FormControl, forms.ModelForm):
	class Meta:
		model = Gasto
		fields = [
			'nombre', 'cuenta_contable'
		]
		labels = {
			'nombre': "Nombre del tipo de gasto",
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(nivel=4).all().order_by('numero')

class cajaForm(FormControl, forms.ModelForm):
	class Meta:
		model = Caja
		fields = ['nombre', 'entidad', 'saldo', 'fecha', 'cuenta_contable']

		labels = {
			'saldo' : "Saldo trasladable",
			'fecha': "Fecha del saldo",
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(nivel=4).filter(
				Q(numero__range=[111000,113000]) |
				Q(numero__range=[211000,221000])
				).order_by('numero')
		if self.instance.primario:
			self.fields.pop('entidad')
			self.fields.pop('cuenta_contable')

class dominioForm(FormControl, forms.ModelForm):
	class Meta:
		model = Dominio
		fields = [
			'propietario', 'socio',
			'numero', 'identificacion',
			'superficie_total', 'superficie_cubierta',
			'domicilio_calle', 'domicilio_numero',
			'domicilio_piso', 'domicilio_oficina',
			'domicilio_sector', 'domicilio_torre',
			'domicilio_manzana', 'domicilio_parcela',
			'domicilio_catastro', 'padre',
			]

		labels = {
			'domicilio_catastro': "Catastro / Matricula",
			'socio': "Ocupante",
			'identificacion': 'Identificacion (ocupante)',
			'padre': 'Unifica con',
			'domicilio_manzana': 'Domicilio manzana / modulo',
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		socios = Socio.objects.filter(consorcio=consorcio)
		self.fields['socio'].queryset = socios
		self.fields['propietario'].queryset = socios
		self.fields['padre'].queryset = Dominio.objects.filter(consorcio=consorcio, padre__isnull=True)
		self.fields['padre'].label_from_instance = self.label_from_instance

	def label_from_instance(self, obj):
		return "{} - {}".format(obj.socio, obj.nombre)

	def clean_superficie_total(self):
		superficie_total = self.cleaned_data['superficie_total']
		ingresos = Ingreso.objects.filter(consorcio=self.consorcio)
		prorrateo_superficie = []
		for ingreso in ingresos:
			if ingreso.prorrateo:
				prorrateo_superficie.append(ingreso)
		if prorrateo_superficie and not superficie_total:
			raise forms.ValidationError("Este campo es obligatorio.")
		return superficie_total

class socioForm(FormControl, forms.ModelForm):
	class Meta:
		model = Socio
		fields = [
			'nombre', 'apellido','numero_asociado','tipo_asociado',
			'fecha_alta',  'tipo_documento',
			'numero_documento','fecha_nacimiento',
			'es_extranjero', 'domicilio', 'localidad',
			'provincia', 'telefono','profesion',
			'mail',   'notificaciones'
			]
		labels = {
			'numero_asociado' : "Numero de asociado",
			'fecha_nacimiento': "Fecha de nacimiento",
			'es_extranjero': 'Es extranjero?',
			'tipo_documento': 'Tipo de Documento',
			'numero_documento': 'Numero de Documento',
			'tipo_asociado':'Tipo de asociado',
			'fecha_alta': 'Fecha de alta',
			'notificaciones': 'Recibe notificaciones?'
		}
		widgets = {
			'notificaciones': NullBooleanSelect(),
			'es_extranjero': NullBooleanSelect(),
			'numero_documento': TextInput(attrs={'type': 'number', 'min': '0', 'step':'1', 'required':True}),

		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['numero_asociado'].initial = Socio.objects.aggregate(Max('numero_asociado'))['numero_asociado__max']+1
		self.fields['tipo_asociado'].queryset = Tipo_asociado.objects.filter(consorcio=consorcio, baja__isnull=True)
		self.fields['tipo_documento'].required = True
		self.fields['numero_documento'].required = True
		self.fields['fecha_alta'].required = True
		self.fields['tipo_asociado'].required = True
		self.fields['numero_asociado'].required = True
		self.fields['nombre'].required = True

	def clean_numero_asociado(self):
		numero_asociado = self.cleaned_data['numero_asociado']
		socios_del_club = Socio.objects.filter(consorcio=self.consorcio)
		if self.instance:
			socios_del_club = socios_del_club.exclude(pk=self.instance.pk)
		n_asocs = []
		for s in socios_del_club:
			n_asocs.append(s.numero_asociado)
		if numero_asociado in n_asocs:
			raise forms.ValidationError("ya existe un asociado con el numero indicado")
		return numero_asociado

	def clean_numero_documento(self):
		numero_documento = self.cleaned_data['numero_documento']
		socios_del_club = Socio.objects.filter(consorcio=self.consorcio)
		if self.instance:
   			socios_del_club = socios_del_club.exclude(pk=self.instance.pk)
		documentos = []
		for s in socios_del_club:
			documentos.append(s.numero_documento)
		if numero_documento in documentos:
			raise forms.ValidationError("ya existe un asociado con el numero de documento indicado")
		return numero_documento

class acreedorForm(FormControl, forms.ModelForm):
	class Meta:
		model = Acreedor
		fields = [
			'nombre','tipo', 'tipo_documento',
			'numero_documento', 'genera',
			'cuenta_contable',
			]
		labels = {
			'tipo': 'Tipo de Gasto',
			'tipo_documento': 'Tipo de documento',
			'genera': 'Genera retenciones?',
			'numero_documento': 'Numero de documento',
		}
		widgets = {
			'numero_documento': TextInput(attrs={'type': 'number', 'min': '0', 'step':'1', 'required':True})
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['tipo'].queryset = Gasto.objects.filter(consorcio=consorcio)
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(nivel=4).filter(
				numero__range=[210000,299999]
				).order_by('numero')
		self.fields['tipo_documento'].required = True
		if self.instance.primario:
			self.fields.pop('nombre')
			self.fields.pop('tipo_documento')
			self.fields.pop('numero_documento')
			self.fields.pop('cuenta_contable')
			self.fields.pop('genera')

class interesForm(FormControl, forms.ModelForm):
	class Meta:
		model = Accesorio
		fields = [
			'nombre', 'ingreso',
			'plazo', 'tipo',
			'reconocimiento',
			'monto', 'base_calculo',
			'cuenta_contable'
		]
		labels = {
			'nombre': "Titulo del interes",
			'plazo': "Plazo en dias",
			'tipo': "Tipo de calculo",
			'monto': "Valor de calculo",
			'base_calculo': "Base de calculo",
		}
		help_texts = {
			"plazo":"Dias desde la fecha de facturacion para que opere el vencimiento y empiece a correr el interes",
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(
				nivel=4,
				numero__gte=400000,
				numero__lt=500000,
				).order_by('numero')
		self.fields['ingreso'].queryset = Ingreso.objects.filter(consorcio=consorcio)
		for field in iter(self.fields):
			self.fields[field].required = True

class descuentoForm(FormControl, forms.ModelForm):
	class Meta:
		model = Accesorio
		fields = [
				'nombre','ingreso',
				'plazo',
				'tipo', 'monto',
				'cuenta_contable'
			]
		labels = {
			'nombre': "Titulo del descuento",
			'plazo': "Plazo en dias",
			'tipo': "Tipo de calculo",
			'monto': "Valor de calculo",
		}
		help_texts = {
			"plazo":"Dias de gracia desde la fecha de facturacion",
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(
				nivel=4,
				numero__gte=400000,
				).order_by('numero')
		self.fields['ingreso'].queryset = Ingreso.objects.filter(consorcio=consorcio)
		for field in iter(self.fields):
			self.fields[field].required = True

class bonificacionForm(FormControl, forms.ModelForm):
	class Meta:
		model = Accesorio
		fields = [
				'nombre','ingreso',
				'tipo', 'monto',
				'cuenta_contable'
			]
		labels = {
			'nombre': "Titulo de la bonificacion",
			'tipo': "Tipo de calculo",
			'monto': "Valor de calculo",
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['cuenta_contable'].queryset = Plan.objects.get(consorcio=consorcio).cuentas.filter(
				nivel=4,
				numero__gte=400000,
				).order_by('numero')
		self.fields['ingreso'].queryset = Ingreso.objects.filter(consorcio=consorcio)
		for field in iter(self.fields):
			self.fields[field].required = True

class grupoForm(FormControl, forms.ModelForm):
	class Meta:
		model = Tipo_asociado
		fields = ['nombre', 'descripcion']

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)
		self.fields['nombre'].required = True
		#self.fields['dominios'].queryset = Dominio.objects.filter(consorcio=consorcio)

class servicioForm(FormControl, forms.ModelForm):
	class Meta:
		model = Socio
		fields = ['nombre_servicio_mutual','nombre', 'descripcion' ]
		labels = {
			'nombre':"Nombre del grupo de asociados que reciben el servicio",
			'descripcion': "Descripcion del servicio",
			'nombre_servicio_mutual': "Nombre del servicio mutual",
		}

	def __init__(self, consorcio=None, *args, **kwargs):
		self.consorcio = consorcio
		super().__init__(*args, **kwargs)

		self.fields['nombre_servicio_mutual'].required = True
		self.fields['nombre'].required = True

class hiddenForm(forms.ModelForm):

	class Meta:
		model = Accesorio
		fields = ['finalizacion']

		widgets = {
			'finalizacion': HiddenInput(),
		}


""" pytests for file API endpoints """

import pytest
from app import app
import json
import time
import uuid

from app.services import file_service

FILE_NAME = 'test_file_endpoints'
APPLICATION_TYPE = 'application/json'
HEADERS = {
    'Content-Type': APPLICATION_TYPE,
    'Accept': APPLICATION_TYPE
}
DATA = {
    'sessionId': str(FILE_NAME)
}

@pytest.fixture(scope="module")
def client():
    app.config['TESTING'] = True
    return app.test_client()

def setup_module(client):
    f = open('tests/titanic.csv', 'r')
    f.filename = FILE_NAME
    f.content_type = 'application/CSV'
    file_service.upload_file(f, FILE_NAME)
    f.close()

def test_file_upload(client):
    # arrange
    file_location = 'tests/titanic.csv'
    data = {
        'sessionId': str(FILE_NAME),
        'file': (open(file_location, 'rb'), FILE_NAME)
    }
    url = 'api/data/upload'

    # act
    resp = client.post(url, data=data, headers=HEADERS,
                       follow_redirects=True, content_type='multipart/form-data')

    # assert
    resp_json = json.loads(resp.json)
    nunique = resp_json['nunique']
    assert nunique is not None
    assert resp.status_code == 200

def test_create_unique_session(client):
    # arrange
    url = 'api/session/create'

    # act
    resp = client.post(url, headers=HEADERS, follow_redirects=True)
    uuid_response = resp.json

    # assert
    try:
        uuid_obj = uuid.UUID(uuid_response, version=4)
    except ValueError:
        return False

    is_uuid_valid = str(uuid_obj) == uuid_response

    assert is_uuid_valid
    assert resp.status_code == 200


from django.contrib.auth.models import User
from django.db import models

class Topic(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField(max_length=500)
    creator = models.ForeignKey(User, related_name='topics', blank=True, on_delete=models.CASCADE)
    created = models.DateField(auto_now_add=True)
    number_of_likes = models.PositiveIntegerField(default=0)
    number_of_comments = models.PositiveIntegerField(default=0)

    class Meta:
        ordering = ('created', )

    def __str__(self):
        return "{} - {}".format(self.title, self.creator)

class Comment(models.Model):
    body = models.CharField(max_length=255)
    creator = models.ForeignKey(User, related_name='comments', on_delete=models.CASCADE)
    created = models.DateField(auto_now_add=True)

    class Meta:
        ordering = ('created', )

class TopicLike(models.Model):
    user = models.ForeignKey(User, related_name='user_likes', on_delete=models.CASCADE)
    topic = models.ForeignKey(Topic, related_name='topic_likes', on_delete=models.CASCADE)


from django import template

from homepage.models import SimplePage

register = template.Library()

class SimplePageNode(template.Node):
    def __init__(self, context_name):
        self.context_name = context_name

    def render(self, context):
        pages = SimplePage.objects.all()
        context[self.context_name] = pages
        return ""

@register.tag
def get_pages(parser, token):
    """Get all simple pages

    Example:
        {% get_pages as pages %}"""
    bits = token.split_contents()
    if bits[-2] != "as":
        raise template.TemplateSyntaxError("Usage: {% get_pages as pages %}")
    context_name = bits[-1]
    return SimplePageNode(context_name)


from dataclasses import dataclass, field

@dataclass(order=True)
class Person:
    # To remove sort index from response, we have to use, repr=False
    sort_index: int = field(init=False, repr=False)
    name: str
    job: str
    age: int

    def __post_init__(self):
        self.sort_index = self.age

person1 = Person("Atawur vai", "Clan lead", 40)
person2 = Person("Masud Vai", "Senior Soft Engr", 28)
person3 = Person("Masud Vai", "Senior Soft Engr", 28)

print(id(person1))
print(id(person2))
print(person1)
print(person1.job)

print(person1 > person3)


from flask import Flask, Response, request
import json
from src.NamedEntity import *

app = Flask(__name__)

@app.route("/health", methods=['GET'])
def get_status():
    return Response(json.dumps({"status":"UP"}), status=200, mimetype='application/json')

@app.route("/", methods=['GET'])
def get_help():
    return Response(json.dumps(
        {"languages supported": ["English"],
         "models": {"en_core_web_sm": {"Language": "English",
                                       "Description": "This model is multi-task CNN trained on OntoNotes. "
                                                      "Assigns context-specific token vectors, POS tags, "
                                                      "dependency parse and named entities.",
                                       "Accuracy Metrics": {"F-Score": 85.86,
                                                            "Precision": 86.33,
                                                            "Recall": 85.39}},

                    "en_core_web_md": {"Language": "English",
                                       "Description": "This model is multi-task CNN trained on OntoNotes, "
                                                      "with GloVe vectors trained on Common Crawl. Assigns word vectors, "
                                                      "context-specific token vectors, POS tags, dependency parse and named entities.",
                                       "Accuracy Metrics": {"F-Score": 85.56,
                                                            "Precision": 86.88,
                                                            "Recall": 86.25}},
                    "en_core_web_lg": {"Language": "English",
                                       "Description": "This model is multi-task CNN trained on OntoNotes, with GloVe vectors"
                                                      " trained on Common Crawl. Assigns word vectors, context-specific token vectors,"
                                                      " POS tags, dependency parse and named entities.",
                                       "Accuracy Metrics": {"F-Score": 85.56,
                                                            "Precision": 86.88,
                                                            "Recall": 86.25}}
                    },
         "sample input body": {
             "text": "i will fire you raman prasad. Return my hyundai verna and hyundai creta",
             "model": "en_core_web_sm"
         }
         }
    ), status=200, mimetype='application/json')

@app.route("/predict_entity", methods=["POST"])
def predict_entity():
    text = request.json["text"]
    model = request.json["model"]
    entity_dict = NamedEntityService.get_entities(text, model)
    return Response(json.dumps(entity_dict), status=200, mimetype='application/json')

@app.route("/predict_entity_sm", methods=["GET"])
def predict_entity_sm():
    """
            for h2load testing
                    """
    text = request.args.get("text", type=str)
    model = "en_core_web_sm"
    entity_dict = NamedEntityService.get_entities(text, model)
    return Response(json.dumps(entity_dict), status=200, mimetype='application/json')

if __name__ == "__main__":
    app.run(port = 5000, debug=True, threaded=True)


from collections import deque
import sys
input = sys.stdin.readline

N, M = map(int,input().split())
temp = [0 for _ in range(N+1)]
graph = [[] for _ in range(N+1)]

for _ in range(M):
    A,B = map(int,input().split())
    graph[A].append(B)
    temp[B] += 1

Q = deque([])
result = [0 for _ in range(N+1)]
for i in range(1,N+1):
    if temp[i] ==0:
        Q.append(i)
        result[i] = 1

while Q:
    now = Q.popleft()

    for i in graph[now]:
        temp[i] -= 1
        if temp[i] == 0:
            Q.append(i)
            result[i] = result[now] + 1

ans = result[1:]
print(*ans)


"""Common fixtures for testing."""

import asyncio
import hashlib
import logging
import os
from typing import Iterator, Optional

import pytest
from acapy_client.api.connection import create_static, delete_connection, set_metadata
from acapy_client.client import Client
from acapy_client.models import (
    ConnectionMetadataSetRequest,
    ConnectionStaticRequest,
    ConnectionStaticResult,
)
from acapy_client.models.conn_record import ConnRecord
from echo_agent.client import EchoClient

LOGGER = logging.getLogger(__name__)

@pytest.fixture(scope="session")
def event_loop():
    """Create a session scoped event loop.
    pytest.asyncio plugin provides a default function scoped event loop
    which cannot be used as a dependency to session scoped fixtures.
    """
    return asyncio.get_event_loop()

@pytest.fixture(scope="session")
def backchannel():
    """Yield backchannel client."""
    endpoint = os.environ.get("ADMIN_ENDPOINT")
    yield Client(base_url=endpoint)

@pytest.fixture(scope="session")
def echo_seed():
    yield hashlib.sha256(b"acapy-pickup-int-test-runner").hexdigest()[:32]

@pytest.fixture(scope="session")
def agent_seed():
    yield hashlib.sha256(b"acapy-pickup-agent").hexdigest()[:32]

@pytest.fixture(scope="session")
def echo_endpoint():
    yield os.environ.get("ECHO_ENDPOINT")

@pytest.fixture(scope="session")
def ws_endpoint():
    yield os.environ.get("WS_ENDPOINT")

@pytest.fixture(scope="session")
def agent_connection(
    echo_seed, agent_seed, echo_endpoint, backchannel
) -> Iterator[ConnectionStaticResult]:
    """Yield agent's representation of this connection."""

    # Create connection in agent under test
    create_result: Optional[ConnectionStaticResult] = create_static.sync(
        client=backchannel,
        json_body=ConnectionStaticRequest.from_dict(
            {
                "my_seed": agent_seed,
                "their_seed": echo_seed,
                "their_label": "test-runner",
            }
        ),
    )
    if not create_result:
        raise RuntimeError("Could not create static connection with agent under test")

    # Set admin metadata to enable access to admin protocols
    set_result = set_metadata.sync(
        client=backchannel,
        conn_id=create_result.record.connection_id,
        json_body=ConnectionMetadataSetRequest.from_dict(
            {"metadata": {"group": "admin"}}
        ),
    )
    if not set_result:
        raise RuntimeError("Could not set metadata on static connection")

    yield create_result

    delete_connection.sync(
        client=backchannel, conn_id=create_result.record.connection_id
    )

@pytest.fixture(scope="session")
def echo_agent(echo_endpoint: str):
    yield EchoClient(base_url=echo_endpoint)

@pytest.fixture
async def echo(echo_agent: EchoClient):
    async with echo_agent as client:
        yield client

@pytest.fixture(scope="session")
def conn_record(agent_connection: ConnectionStaticResult):
    yield agent_connection.record

@pytest.fixture(scope="session")
def connection_id(conn_record: ConnRecord):
    yield conn_record.connection_id

@pytest.fixture(scope="session", autouse=True)
async def connection(
    agent_connection: ConnectionStaticResult, echo_agent: EchoClient, echo_seed: str
):
    """Yield static connection to agent under test."""
    # Create and yield static connection
    async with echo_agent as echo:
        conn = await echo.new_connection(
            seed=echo_seed,
            endpoint=agent_connection.my_endpoint,
            their_vk=agent_connection.my_verkey,
        )
    yield conn