from chat.ChatMessage import ChatMessage
from chat.ChatObserver import ChatObserver, NotifyAction

MAX_HISTORY_SIZE = 500

class ChatProvider:
    history: list[ChatMessage]
    observers: list[ChatObserver]

    def __init__(self):
        self.history = []
        self.observers = []

    def addObserver(self, observer: ChatObserver) -> None:
        self.observers.append(observer)
        observer.startObserving()

    def removeObserver(self, observer: ChatObserver) -> None:
        self.observers.remove(observer)
        observer.endObserving()

    def cleanAndAddMultipleMessages(self, msgs: list[ChatMessage]) -> None:
        if len(self.history) + len(msgs) > MAX_HISTORY_SIZE:
            self.history.clear()
        for msg in msgs:
            self.__addMessage(msg)

    def __addMessage(self, msg: ChatMessage) -> None:
        for obs in self.observers:
            result: NotifyAction = obs.notify(msg)
            if result == NotifyAction.END_NOTIFY_CHAIN:
                break
        self.history.append(msg)


from operator import itemgetter

from pytz import common_timezones, common_timezones_set
from wtforms.fields import BooleanField, EmailField, IntegerField, SelectField, StringField
from wtforms.validators import DataRequired, Email, NumberRange, ValidationError

from indico.core.auth import multipass
from indico.core.config import config
from indico.modules.auth.forms import LocalRegistrationForm, _check_existing_email
from indico.modules.users import User
from indico.modules.users.models.emails import UserEmail
from indico.modules.users.models.users import NameFormat
from indico.util.i18n import _, get_all_locales
from indico.web.forms.base import IndicoForm
from indico.web.forms.fields import (IndicoEnumSelectField, IndicoSelectMultipleCheckboxField, MultiStringField,
                                     PrincipalField, PrincipalListField)
from indico.web.forms.util import inject_validators
from indico.web.forms.validators import HiddenUnless
from indico.web.forms.widgets import SwitchWidget

class UserPreferencesForm(IndicoForm):
    lang = SelectField(_('Language'))

    force_language = BooleanField(
        _('Use my language'),
        widget=SwitchWidget(),
        description=_("Always use my preferred language instead of an event's supported language."
                      ' This may result in a mix of two languages in some areas of an event.'))

    timezone = SelectField(_('Timezone'))

    force_timezone = BooleanField(
        _('Use my timezone'),
        widget=SwitchWidget(),
        description=_("Always use my current timezone instead of an event's timezone."))

    show_future_events = BooleanField(
        _('Show future events'),
        widget=SwitchWidget(),
        description=_('Show future events by default.'))

    show_past_events = BooleanField(
        _('Show past events'),
        widget=SwitchWidget(),
        description=_('Show past events by default.'))

    name_format = IndicoEnumSelectField(_('Name format'), enum=NameFormat,
                                        description=_('Default format in which names are displayed'))

    use_previewer_pdf = BooleanField(
        _('Use previewer for PDF files'),
        widget=SwitchWidget(),
        description=_('The previewer is used by default for image and text files, but not for PDF files.'))

    add_ical_alerts = BooleanField(
        _('Add alerts to iCal'),
        widget=SwitchWidget(),
        description=_('Add an event reminder to exported iCal files/URLs.'))

    add_ical_alerts_mins = IntegerField(
        _('iCal notification time'),
        [HiddenUnless('add_ical_alerts'), NumberRange(min=0)],
        description=_('Number of minutes to notify before an event.'))

    use_markdown_for_minutes = BooleanField(
        _('Markdown editor for minutes'),
        widget=SwitchWidget(),
        description=_('Use Markdown editor instead of HTML editor when editing the minutes of a meeting.'))

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

        locales = [(code, f'{name} ({territory})' if territory else name)
                   for code, (name, territory, __) in get_all_locales().items()]
        self.lang.choices = sorted(locales, key=itemgetter(1))
        self.timezone.choices = list(zip(common_timezones, common_timezones))
        if self.timezone.object_data and self.timezone.object_data not in common_timezones_set:
            self.timezone.choices.append((self.timezone.object_data, self.timezone.object_data))

class UserEmailsForm(IndicoForm):
    email = EmailField(_('Add new email address'), [DataRequired(), Email()], filters=[lambda x: x.lower() if x else x])

    def validate_email(self, field):
        conflict = (UserEmail.query
                    .filter(~User.is_pending,
                            ~UserEmail.is_user_deleted,
                            UserEmail.email == field.data)
                    .join(User)
                    .has_rows())
        if conflict:
            raise ValidationError(_('This email address is already in use.'))

class SearchForm(IndicoForm):
    last_name = StringField(_('Family name'))
    first_name = StringField(_('First name'))
    email = StringField(_('Email'), filters=[lambda x: x.lower() if x else x])
    affiliation = StringField(_('Affiliation'))
    exact = BooleanField(_('Exact match'))
    include_deleted = BooleanField(_('Include deleted'))
    include_pending = BooleanField(_('Include pending'))
    external = BooleanField(_('External'))

class MergeForm(IndicoForm):
    source_user = PrincipalField(_('Source user'), [DataRequired()],
                                 description=_('The user that will be merged into the target one'))
    target_user = PrincipalField(_('Target user'), [DataRequired()],
                                 description=_('The user that will remain active in the end'))

class AdminUserSettingsForm(IndicoForm):
    notify_account_creation = BooleanField(_('Registration notifications'), widget=SwitchWidget(),
                                           description=_('Send an email to all administrators whenever someone '
                                                         'registers a new local account.'))
    email_blacklist = MultiStringField(_('Email blacklist'), field=('email_blacklist', _('email')),
                                       unique=True, flat=True,
                                       description=_('Prevent users from creating Indico accounts with these email '
                                                     'addresses. Supports wildcards, e.g. *@gmail.com'))
    allow_personal_tokens = BooleanField(_('Personal API tokens'), widget=SwitchWidget(),
                                         description=_('Whether users are allowed to generate personal API tokens. '
                                                       'If disabled, only admins can create them, but users will '
                                                       'still be able to regenerate the tokens assigned to them.'))
    mandatory_fields_account_request = IndicoSelectMultipleCheckboxField(
        _('Mandatory fields in account request'),
        choices=[('affiliation', _('Affiliation')), ('comment', _('Comment'))],
        description=_('Fields a new user has to fill in when requesting an account')
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not multipass.has_moderated_providers:
            del self.mandatory_fields_account_request

class AdminAccountRegistrationForm(LocalRegistrationForm):
    email = EmailField(_('Email address'), [DataRequired(), Email(), _check_existing_email],
                       filters=[lambda s: s.lower() if s else s])
    create_identity = BooleanField(_('Set login details'), widget=SwitchWidget(), default=True)

    def __init__(self, *args, **kwargs):
        if config.LOCAL_IDENTITIES:
            for field in ('username', 'password', 'confirm_password'):
                inject_validators(self, field, [HiddenUnless('create_identity')], early=True)
        super().__init__(*args, **kwargs)
        if not config.LOCAL_IDENTITIES:
            del self.username
            del self.password
            del self.confirm_password
            del self.create_identity

class AdminsForm(IndicoForm):
    admins = PrincipalListField(_('Admins'), [DataRequired()])


class newNode:
    def __init__(self,data):
        self.data=data
        self.left=None
        self.right=None

def display(head):
    left_node=0.0
    right_node=0.0
    if not head:
        return
    if(head.left):
        left_node=head.left.data
    if(head.right):
        right_node=head.right.data
    print(left_node,"<-",head.data,"->",right_node)
    display(head.right)
    display(head.left)

def height(root):
    if root==None:
        return -1
    return max(height(root.left),height(root.right))+1

def inOrder(root):
    if root==None:
        return
    inOrder(root.left)
    print(root.data,end=" ")
    inOrder(root.right)

def postOrder(root):
    if root==None:
        return

    postOrder(root.left)
    postOrder(root.right)
    print(root.data,end=" ")

def postOrderIterative(root):
    st=[]
    out=[]
    curr=root
    while(len(st)>0 or curr):
        if(curr):
            st.append(curr)
            # if(curr.left):
            out.append(curr.data)
            curr=curr.right

        else:
            curr=st.pop()
            curr=curr.left
    out.reverse()
    print("\n",out)

def postOrderIterative_2(root):
    st=[root]
    out=[]
    while(len(st))>0:
        node=st.pop()
        out.append(node.data)
        if(node.left):
            st.append(node.left)
        if(node.right):
            st.append(node.right)
    out.reverse()
    print(out)

#using queue
# def postOrderIterative_3(root):
#     qu=[root]
#     out=[]
#     while(len(qu))>0:
#         node=qu.pop(0)
#         out.append(node.data)
#         if(node.right):
#             qu.append(node.right)
#         if(node.left):
#             qu.append(node.left)

#     out.reverse()
#     print(out)

root = newNode(50)
root.left=newNode(25)
root.right=newNode(75)
root.right.right=newNode(87)
root.right.left=newNode(62)
root.right.left.right=newNode(70)
root.right.left.left=newNode(60)
root.left.right=newNode(37)
root.left.right.left=newNode(30)
root.left.right.right=newNode(40)
root.left.left=newNode(12)

# root = newNode(5)
# root.left = newNode(3)
# root.right = newNode(6)
# root.left.left = newNode(2)
# root.left.left.right = newNode(1)
# root.left.right = newNode(4)
display(root)
inOrder(root)
print()
postOrder(root)
# print()
postOrderIterative(root)
postOrderIterative_2(root)
# postOrderIterative_3(root)
print()


import io
import os
import platform
import struct
import threading

from fleetspeak.src.client.channel.proto.fleetspeak_channel import channel_pb2
from fleetspeak.src.common.proto.fleetspeak import common_pb2

_WINDOWS = platform.system() == "Windows"
if _WINDOWS:
  import msvcrt  # pylint: disable=g-import-not-at-top

class ProtocolError(Exception):
  """Raised when we do not understand the data received from Fleetspeak."""

# Constants to match behavior of channel.go.
_MAGIC = 0xF1EE1001

# We recommend that messages be ~1MB or smaller, and daemonservice has has 2MB
# hardcoded maximum.
MAX_SIZE = 2 * 1024 * 1024

# Format for the struct module to pack/unpack a 32 bit unsigned integer to/from
# a little endian byte sequence.
_STRUCT_FMT = "<I"

# The number of bytes required/produced when using _STRUCT_FMT.
_STRUCT_LEN = 4

# Environment variables, used to find the filedescriptors left open for
# us when started by Fleetspeak.
_INFD_VAR = "FLEETSPEAK_COMMS_CHANNEL_INFD"
_OUTFD_VAR = "FLEETSPEAK_COMMS_CHANNEL_OUTFD"

def _EnvOpen(var, mode):
  """Open a file descriptor identified by an environment variable."""
  value = os.getenv(var)
  if value is None:
    raise ValueError("%s is not set" % var)

  fd = int(value)

  # If running on Windows, convert the file handle to a C file descriptor; see:
  # https://groups.google.com/forum/#!topic/dev-python/GeN5bFJWfJ4
  if _WINDOWS:
    fd = msvcrt.open_osfhandle(fd, 0)

  return io.open(fd, mode)

class FleetspeakConnection(object):
  """A connection to the Fleetspeak system.

  It's safe to call methods of this class in parallel.
  """

  def __init__(self, version=None, read_file=None, write_file=None):
    """Connect to Fleetspeak.

    Connects to and begins an initial exchange of magic numbers with the
    Fleetspeak process. In normal use, the arguments are not required and will
    be created using the environment variables set by daemonservice.

    Args:
      version: A string identifying the version of the service being run. Will
        be included in resource reports for this service.
      read_file: A python file object, or similar, used to read bytes from
        Fleetspeak. If None, will be created based on the execution environment
        provided by daemonservice.
      write_file: A python file object, or similar, used to write bytes to
        Fleetspeak. If None, will be created based on the execution environment
        provided by daemonservice.

    Raises:
      ValueError: If read_file and write_file are not provided, and the
        corresponding environment variables are not set.
      ProtocolError: If we receive unexpected data from Fleetspeak.
    """
    self._read_file = read_file
    if not self._read_file:
      self._read_file = _EnvOpen(_INFD_VAR, "rb")

    self._read_lock = threading.Lock()

    self._write_file = write_file
    if not self._write_file:
      self._write_file = _EnvOpen(_OUTFD_VAR, "wb")

    self._write_lock = threading.Lock()

    # It is safer to send the magic number before reading it, in case the other
    # end does the same. Also, we'll be killed as unresponsive if we don't
    # write the magic number quickly enough. (Currently though, the other end is
    # the go implementation, which reads and writes in parallel.)
    self._WriteMagic()

    self._WriteStartupData(version)
    self._ReadMagic()

  def Send(self, message):
    """Send a message through Fleetspeak.

    Args:
      message: A message protocol buffer.

    Returns:
      Size of the message in bytes.
    Raises:
      ValueError: If message is not a common_pb2.Message.
    """
    if not isinstance(message, common_pb2.Message):
      raise ValueError("Send requires a fleetspeak.Message")

    if message.destination.service_name == "system":
      raise ValueError(
          "Only predefined messages can have destination.service_name =="
          ' "system"'
      )

    return self._SendImpl(message)

  def _SendImpl(self, message):
    if not isinstance(message, common_pb2.Message):
      raise ValueError("Send requires a fleetspeak.Message")

    buf = message.SerializeToString()
    if len(buf) > MAX_SIZE:
      raise ValueError(
          "Serialized message too large, size must be at most %d, got %d"
          % (MAX_SIZE, len(buf))
      )

    with self._write_lock:
      self._write_file.write(struct.pack(_STRUCT_FMT, len(buf)))
      self._write_file.write(buf)
      self._WriteMagic()

    return len(buf)

  def Recv(self):
    """Accept a message from Fleetspeak.

    Returns:
      A tuple (common_pb2.Message, size of the message in bytes).
    Raises:
      ProtocolError: If we receive unexpected data from Fleetspeak.
    """
    size = struct.unpack(_STRUCT_FMT, self._ReadN(_STRUCT_LEN))[0]
    if size > MAX_SIZE:
      raise ProtocolError(
          "Expected size to be at most %d, got %d" % (MAX_SIZE, size)
      )
    with self._read_lock:
      buf = self._ReadN(size)
      self._ReadMagic()

    res = common_pb2.Message()
    res.ParseFromString(buf)

    return res, len(buf)

  def Heartbeat(self):
    """Sends a heartbeat to the Fleetspeak client.

    If this daemonservice is configured to use heartbeats, clients that don't
    call this method often enough are considered faulty and are restarted by
    Fleetspeak.
    """
    heartbeat_msg = common_pb2.Message(
        message_type="Heartbeat",
        destination=common_pb2.Address(service_name="system"),
    )
    self._SendImpl(heartbeat_msg)

  def _ReadMagic(self):
    got = struct.unpack(_STRUCT_FMT, self._ReadN(_STRUCT_LEN))[0]
    if got != _MAGIC:
      raise ProtocolError(
          "Expected to read magic number {}, got {}.".format(_MAGIC, got)
      )

  def _WriteMagic(self):
    buf = struct.pack(_STRUCT_FMT, _MAGIC)
    self._write_file.write(buf)
    self._write_file.flush()

  def _WriteStartupData(self, version):
    startup_msg = common_pb2.Message(
        message_type="StartupData",
        destination=common_pb2.Address(service_name="system"),
    )
    startup_msg.data.Pack(
        channel_pb2.StartupData(pid=os.getpid(), version=version)
    )
    self._SendImpl(startup_msg)

  def _ReadN(self, n):
    """Reads n characters from the input stream, or until EOF.

    This is equivalent to the current CPython implementation of read(n), but
    not guaranteed by the docs.

    Args:
      n: int

    Returns:
      string
    """
    ret = b""
    while True:
      chunk = self._read_file.read(n - len(ret))
      ret += chunk

      if len(ret) == n or not chunk:
        return ret


from flask import render_template, flash, redirect, url_for, request, jsonify
from flask_login import current_user, login_user, logout_user, login_required
from app import app, db, photos
from app.forms import LoginForm, RegistrationForm, NewCharacterForm, CharacterSearchForm, DiceRoll, NewPartyForm
from app.models import User, Character, Sub_Race, Sub_Class, Results
from werkzeug.urls import url_parse
from werkzeug.utils import secure_filename
from pathlib import Path, PureWindowsPath, PurePath
import json
import os

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
@login_required
def index():
	characters = Character.query.all()
	return render_template('index.html', title='Home Page', characters=characters)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        next_page = request.args.get('next')
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('index')
        return redirect(next_page)
    return render_template('login.html', title='Sign In', form=form)

@app.route('/logout')
def logout():
	logout_user()
	return redirect(url_for('index'))

@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, first_name=form.first_name.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html', title='Register', form=form)

@app.route('/user/<username>')
@login_required
def user(username):
    user = User.query.filter_by(username=username).first_or_404()
    characters = current_user.get_characters()
    return render_template('user.html', user=user, characters=characters, title='Profile')

@app.route('/user/<username>/create_new_char', methods=['GET', 'POST'])
@login_required
def create_new_char(username):
	user = User.query.filter_by(username=username).first_or_404()
	form = NewCharacterForm()
	form.sub_class.choices = [(sub_class.name, sub_class.name) for sub_class in Sub_Class.query.filter_by(char_class='Barbarian').all()]
	form.sub_race.choices = [(sub_race.name, sub_race.name) for sub_race in Sub_Race.query.filter_by(race='Aarakocra').all()]
	if request.method == 'POST':
		character = Character(name=form.name.data, race=form.race.data,\
		 char_class=form.char_class.data, sub_class=form.sub_class.data, sub_race=form.sub_race.data, level=form.level.data, hp=form.hp.data, user_id=user.id)
		db.session.add(character)
		db.session.commit()
		flash('Your character has been created!')
		return redirect(url_for('user', username=current_user.username))
	return render_template('create_new_char.html', user=user, form=form, title='Create New Character')

@app.route('/user/<username>/edit_character/<character>', methods=['GET', 'POST'])
@login_required
def edit_character(username, character):
	user = User.query.filter_by(username=username).first_or_404()
	char_id = user.user_id
	char = Character.query.filter_by(user_id=char_id, name=character).first_or_404()
	form = NewCharacterForm(obj=char)
	current_char_race = char.race
	current_char_class = char.char_class
	form.sub_race.choices = [(sub_race.name, sub_race.name) for sub_race in Sub_Race.query.filter_by(race=current_char_race).all()]
	form.sub_class.choices = [(sub_class.name, sub_class.name) for sub_class in Sub_Class.query.filter_by(char_class=current_char_class).all()]
	if request.method == 'POST':
		form.populate_obj(char)
		db.session.add(char)
		db.session.commit()
		flash('Your character has been saved!')
		return redirect(url_for('user', username=current_user.username))
	return render_template('edit_character.html', user=user, form=form, title='Edit Character')

@app.route('/user/<username>/<character>', methods=['GET', 'POST'])
@login_required
def display_character(username, character):
	if character == None:
		return redirect(url_for('index'))
	user = User.query.filter_by(username=username).first_or_404()
	char_id = user.id
	char = Character.query.filter_by(user_id=char_id, name=character).first_or_404()
	return render_template('display_char.html', username=user, character=char, title=str(character))

@app.route('/search', methods=['GET', 'POST'])
@login_required
def search():
	search = CharacterSearchForm(request.form)
	if request.method == 'POST':
		return search_results(search)
	return render_template('search.html', form=search, title="Search")

@app.route('/results', methods=['GET', 'POST'])
@login_required
def search_results(search):
	results = []
	first_string = search.data['search']
	second_string = first_string.lower()
	search_string = second_string.capitalize()
	if search_string:
		if search.data['select'] == 'name':
			qry = Character.query.filter(Character.name.contains(search_string))
			results = qry.all()
		elif search.data['select'] == 'char_class':
			qry = Character.query.filter(Character.char_class.contains(search_string))
			results = qry.all()
		elif search.data['select'] == 'race':
			qry = Character.query.filter(Character.race.contains(search_string))
			results = qry.all()
		elif search.data['select'] == 'level':
			qry = Character.query.filter(Character.level.contains(search_string))
			results = qry.all()
		# elif search.data['select'] == 'party':
		# 	qry = Character.query.filter(Character.party.contains(search_string))
		# 	results = qry.all()
		else:
			qry = db.session.query(Character)
			results = qry.all()
	else:
		qry = db.session.query(Character)
		results = qry.all()

	if not results:
		flash('No results found!')
		return redirect(url_for('search'))

	else:
		table = Results(results)
		table.border = True
		return render_template('results.html', results=results, table=table, title="Search Results")

@app.route('/dice_roller', methods=['GET', 'POST'])
@login_required
def dice_roller():
	form = DiceRoll(request.form)
	num = 0
	return render_template('dice_roller.html', form=form, num=num)

@app.route('/dice_update', methods=['POST'])
def dice_update():
	num = request.form['result']
	return jsonify({'result': num})

def allowed_file(filename):
	return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

# create new party
@app.route('/create_new_party', methods=['GET', 'POST'])
@login_required
def create_new_party():
	user = User.query.filter_by(username=current_user.username).first_or_404()
	form = NewPartyForm()
	form.party_members.choices = [(character.name, character.name) for character in Character.query.all()]

	if request.method == 'POST':
		current_party_list = party_list()
		new_party = Party(party_name=form.party_name.data, party_leader=user.id)
		for char in current_party_list:
			char.party_id = new_party.party_id
		db.session.add(new_party)
		db.session.commit()
		flash('Your party has been created!')
		return redirect(url_for('user', username=current_user.username))
	return render_template('create_new_party.html', form=form, user=user)

@app.route('/party_list')
@login_required
def party_list():
	current_party_list = json.loads(request.args.get('party_list'))
	return jsonify(result=current_party_list)

@app.route('/upload/<username>', methods=['GET', 'POST'])
@login_required
def upload(username):
	user = User.query.filter_by(username=username).first_or_404()

	if request.method == 'POST':

		if 'photo' not in request.files:
			flash('No file part')
			return redirect(url_for('user', username=username))

		file = request.files['photo']

		if file.filename == '':
			flash("No selected file")
			return redirect(url_for('user', username=username))

		if file and allowed_file(file.filename):

			# TODO
			# language to delete old photos using OS neutral path
			# if user.profile_photo:
			# 	delete_old = os.path.normpath(user.profile_photo)
			# 	flash(str(delete_old))
			# 	os.remove(user.profile_photo)

			# save requested img to server
			filename = Path(secure_filename(file.filename)).as_posix()
			filename_2 = photos.save(request.files['photo'])

			# establish OS neutral file path to save to DB
			pure_path = Path(PureWindowsPath('\\static\\img\\'))
			user.profile_photo = os.path.join(pure_path.as_posix(), filename)

			#commit filepath string to db
			db.session.commit()

			flash("New Avatar Uploaded Sucessfully!")
			return redirect(url_for('user', username=username))
	return render_template('upload.html', username=username)

# dynamic SelectField for sub_races
@app.route('/sub_race/<race>')
@login_required
def sub_race(race):
	sub_races = Sub_Race.query.filter_by(race=race).all()
	sub_race_array = []
	for sub_race in sub_races:
		sub_race_obj = {}
		sub_race_obj['name'] = sub_race.name
		sub_race_array.append(sub_race_obj)
	return jsonify({'sub_races' : sub_race_array})

# dynamic SelectField for sub_classes
@app.route('/sub_class/<char_class>')
@login_required
def sub_class(char_class):
	sub_classes = Sub_Class.query.filter_by(char_class=char_class).all()
	sub_class_array = []
	for sub_class in sub_classes:
		sub_class_obj = {}
		sub_class_obj['name'] = sub_class.name
		sub_class_array.append(sub_class_obj)
	return jsonify({'sub_classes' : sub_class_array})

@app.route('/delete_confirm/<character>', methods=['GET', 'POST'])
@login_required
def delete_confirm(character):
	char = Character.query.filter_by(name=character).first_or_404()
	char_name = char.name

	if request.method == 'POST':
		db.session.delete(char)
		db.session.commit()
		flash("Character Successfully Deleted!")
		return redirect(url_for('user', username=current_user.username))

	return render_template('delete_character.html', title="Delete Character", character=char_name)


import tkinter as tk
from PIL import ImageTk, Image

RaizComic = tk.Tk()
RaizComic.title("¡Comics!")
RaizComic.iconbitmap("Icono.ico")
RaizComic.geometry('600x600')
image2 = Image.open('marvelydc.png')
image1 = ImageTk.PhotoImage(image2)
background_Label = tk.Label(RaizComic, image=image1)
background_Label.image1 = image1
background_Label.place(x=0, y=0, height=600, width=600)

Bienvenida = tk.Label(RaizComic, text = '¡BIENVENIDOS!')
Bienvenida.place(x=150, y= 10)
Bienvenida.config(bg = 'black', fg = 'white', justify = 'right', font = ('Comic Sans', 30))

def salir():
    RaizComic.destroy()

#----------------------MARVEL.................................
def marvelbo():
    elframe = tk.Toplevel()
    elframe.geometry('790x600')
    elframe.title('Comics de Marvel')
    #w=350
    #h=460

    scrollbar = tk.Scrollbar(elframe)
    c = tk.Canvas(elframe, yscrollcommand=scrollbar.set)
    scrollbar.config(command= c.yview)
    scrollbar.pack(side= tk.RIGHT, fill= tk.Y)
    elframe = tk.Frame(c)
    c.pack(side='left', fill='both', expand= True)
    c.create_window(0,0, window= elframe, anchor= 'nw')
    imagefondo = Image.open('fondo.png')
    imagefondo1 = ImageTk.PhotoImage(imagefondo)
    background_Label = tk.Label(elframe, image=imagefondo1)
    background_Label.imagefondo1 = imagefondo1
    background_Label.place(x=0, y=0, height=1120, width=950)

    #ImagenBienvenida = tk.PhotoImage(file = 'mavellogo.png')
    #PrintBienvenida_marvel = tk.Label(elframe, image = ImagenBienvenida)
    #PrintBienvenida_marvel.grid(row=0, columnspan=2)

    ImagenBienvenida = tk.PhotoImage(file = 'marvellogo1.png')
    PrintBienvenida_marvel = tk.Label(elframe, image = ImagenBienvenida)
    PrintBienvenida_marvel.grid(row=0, column=1)

    ImagenBienvenida1 = tk.PhotoImage(file = 'marvellogo2.png')
    PrintBienvenida_marvel1 = tk.Label(elframe, image = ImagenBienvenida1)
    PrintBienvenida_marvel1.grid(row=0, column=2)

#------------------Spiderman-----------------------------
    ImagenSpiderman = tk.PhotoImage(file = 'marvel/marvel-spider.png')
    PrintSpiderman = tk.Label(elframe, image = ImagenSpiderman)
    PrintSpiderman.grid(row =1, column = 0)

    tk.Label(elframe, font=8,
        text=("Spiderman\n Amazing Fantasy #15\n"
            "Peter Parker\n"
            "Marvel Comics")).grid(row=1, column=1)

    def BotonSpiderman():
        spider_man = tk.Toplevel()
        spider_man.geometry('700x430')
        spider_man.title('¡Spider-Man!')
        spider_man.configure(background='yellow')

        def salir_ventana():
            spider_man.destroy()

        ImagenSpiderman1 = tk.PhotoImage(file = 'marvelfotos/spiderman2.png')
        PrintSpiderman1 = tk.Label(spider_man, image = ImagenSpiderman1)
        PrintSpiderman1.grid(row=0, column=0)

        tk.Label(spider_man, font=('Comic Sans', 18),
            text=("Spiderman\n Amazing Fantasy #15\n"
                "Peter Parker\n"
                "Marvel Comics\n"
                "gran fuerza\n agilidad\n"
                " Un sentido arácnido\n"
                "que le permite saber si\n"
                "un peligro se cierne sobre él\n"
                "antes de que suceda.\n")).place(x= 365, y= 30)
        botonsalir=tk.Button(spider_man, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 465, y =370)
        PrintSpiderman1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonSpiderman)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =300)

#-------------------Capitan america---------------------------------
    ImagenCapi = tk.PhotoImage(file = 'marvel/marvel-captain.png')
    PrintCapi = tk.Label(elframe,image = ImagenCapi)
    PrintCapi.grid(row = 2, column =0)

    tk.Label(elframe, font=8,
        text=("Capitan America\n Captain America Comics #1\n"
            "Steve Rogers\n"
            "Marvel Comics")).grid(row=2, column=1)

    def BotonCapi():
        capitan = tk.Toplevel()
        capitan.geometry('800x460')
        capitan.title('¡Capitan America!')
        capitan.configure(background='royal blue')

        def salir_ventana():
            capitan.destroy()

        ImagenCapi1 = tk.PhotoImage(file = 'marvelfotos/cap2.png')
        PrintCapi1 = tk.Label(capitan,image = ImagenCapi1)
        PrintCapi1.grid(row = 0, column =0)

        tk.Label(capitan, font=('Comic Sans', 18),
            text=("Capitan America\n Captain America Comics #1\n"
                "Steve Rogers\n"
                "Marvel Comics\n"
                "Gran habilidad con armas de fuego\n"
                "con el martillo Mjolnir y con su escudo\n"
                "inmune a gases y enfermedades\n"
                "Genio táctico\n"
                "acróbata experto\n")).place(x=375, y=100)
        botonsalir=tk.Button(capitan, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 530, y =390)
        PrintCapi1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonCapi)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =490)

#-------------------Iron man----------------------------------------
    ImagenIron = tk.PhotoImage(file = 'marvel/marvel-iron.png')
    PrintIron = tk.Label(elframe,image = ImagenIron)
    PrintIron.grid(row = 4, column =0)

    tk.Label(elframe, font=8,
        text=("Iron Man\n Tales of Suspense #39\n"
            "Tony Stark\n"
            "Marvel Comics")).grid(row=4, column=1)

    def BotonIron():
        iron = tk.Toplevel()
        iron.geometry('850x450')
        iron.title('¡Iron Man!')
        iron.configure(background='red4')

        def salir_ventana():
            iron.destroy()

        ImagenIron1 = tk.PhotoImage(file = 'marvelfotos/iron1.png')
        PrintIron1 = tk.Label(iron,image = ImagenIron1)
        PrintIron1.grid(row = 0, column =0)

        tk.Label(iron, font=('Comic Sans', 18),
            text=("Iron Man\n Tales of Suspense #39\n"
                "Tony Stark\n"
                "Marvel Comics\n"
                "Genio, filantropo,\n"
                "Playboy\n"
                "Repulsor de energía y misiles de proyección\n"
                "Uso de equipamiento\n"
                "Dispositivos y armamento de alta tecnología.")).place(x=350, y=80)
        botonsalir=tk.Button(iron, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 530, y =390)
        PrintIron1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonIron)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =685)

#----------------------Daredevil--------------------------------------
    ImagenDaredevil = tk.PhotoImage(file = 'marvel/marvel-daredevil.png')
    PrintDaredevil = tk.Label(elframe, image = ImagenDaredevil)
    PrintDaredevil.grid(row = 6, column = 0)

    tk.Label(elframe, font=8,
        text=("Daredevil\n Daredevil #1\n"
            "Matthew Michael Murdock\n"
            "Marvel Comics")).grid(row=6, column=1)

    def BotonDare():
        daredevil = tk.Toplevel()
        daredevil.geometry('810x485')
        daredevil.title('¡Daredevil!')
        daredevil.configure(background='indian red')

        def salir_ventana():
            daredevil.destroy()

        ImagenDaredevil1 = tk.PhotoImage(file = 'marvelfotos/daredevil1.png')
        PrintDaredevil1 = tk.Label(daredevil, image = ImagenDaredevil1)
        PrintDaredevil1.grid(row = 0, column = 0)

        tk.Label(daredevil, font=('Comic Sans', 18),
            text=("Daredevil\n Daredevil #1\n"
                "Matthew Michael Murdock\n"
                "Marvel Comics\n"
                "Ecolocalización radar cerebral\n"
                "que le permite ver a pesar de estar ciego\n"
                "Tirador de precisión perfecta\n"
                "Carencia del sentido del miedo\n")).place(x=360, y=100)
        botonsalir=tk.Button(daredevil, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 530, y =420)
        PrintDaredevil1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonDare)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =875)

#-----------------------Hulk------------------------------------------
    ImagenHulk = tk.PhotoImage(file = 'marvel/marvel-hulk.png')
    PrintHulk = tk.Label(elframe, image = ImagenHulk)
    PrintHulk.grid(row = 8, column = 0)

    tk.Label(elframe, font=8,
        text=("Hulk\n The Incredible Hulk #1\n"
            "Bruce Banner\n"
            "Marvel Comics")).grid(row=8, column=1)

    def BotonHulk():
        Hulk = tk.Toplevel()
        Hulk.geometry('800x485')
        Hulk.title('¡Hulk!')
        Hulk.configure(background='DarkOliveGreen4')

        def salir_ventana():
            Hulk.destroy()

        ImagenHulk1 = tk.PhotoImage(file = 'marvelfotos/hulk1.png')
        PrintHulk1 = tk.Label(Hulk, image = ImagenHulk1)
        PrintHulk1.grid(row = 0, column = 0)

        tk.Label(Hulk, font=('Comic Sans', 18),
            text=("Hulk\n The Incredible Hulk #1\n"
                "Bruce Banner\n"
                "Marvel Comics\n"
                "Regeneración\n"
                "Capacidad Pulmonar\n"
                "Hulk se adapta a cualquier ambiente\n"
                "Inmortalidad\n"
                " Super velocidad.\n")).place(x=380, y=100)
        botonsalir=tk.Button(Hulk, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 530, y =420)
        PrintHulk1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonHulk)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =1065)

#-----------------------Thor---------------------------------
    ImagenThor = tk.PhotoImage(file = 'marvel/marvel-thor.png')
    PrintThor = tk.Label(elframe, image = ImagenThor)
    PrintThor.grid(row = 1, column = 2)

    tk.Label(elframe, font=8,
        text=("Thor\n Journey into Myster #83\n"
            "Thor Odinson\n"
            "Marvel Comics")).grid(row=1, column=3)

    def BotonThor():
        thor = tk.Toplevel()
        thor.geometry('700x500')
        thor.title('¡Thor !')
        thor.configure(background='RoyalBlue1')

        def salir_ventana():
            thor.destroy()

        ImagenThor1 = tk.PhotoImage(file = 'marvelfotos/thor1.png')
        PrintThor1 = tk.Label(thor, image = ImagenThor1)
        PrintThor1.grid(row = 0, column = 0)

        tk.Label(thor, font=('Comic Sans', 18),
            text=("Thor\n Journey into Myster #83\n"
                "Thor Odinson\n"
                "Marvel Comics\n"
                "dios del trueno\n"
                "Fuerza sobrehumana\n"
                "velocidad\n"
                "durabilidad\n")).place(x=415, y=120)
        botonsalir=tk.Button(thor, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 490, y =440)
        PrintThor1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonThor)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 560, y =300)

#-----------------------Wolverine---------------------------------
    ImagenWolverine = tk.PhotoImage(file = 'marvel/marvel-wolverine.png')
    PrintWolverine = tk.Label(elframe, image = ImagenWolverine)
    PrintWolverine.grid(row = 2, column = 2)

    tk.Label(elframe, font=8,
        text=("Wolverine\n The Incredible Hulk #180\n"
            "James Howlett\n"
            "Marvel Comics")).grid(row=2, column=3)

    def BotonWol():
        wolve = tk.Toplevel()
        wolve.geometry('910x500')
        wolve.title('¡Wolverine!')
        wolve.configure(background='yellow3')

        def salir_ventana():
            wolve.destroy()

        ImagenWolverine1 = tk.PhotoImage(file = 'marvelfotos/wolve1_.png')
        PrintWolverine1 = tk.Label(wolve, image = ImagenWolverine1)
        PrintWolverine1.grid(row = 0, column = 0)

        tk.Label(wolve, font=('Comic Sans', 14),
            text=("Wolverine\n The Incredible Hulk #180\n"
                "James Howlett\n"
                "Marvel Comics\n"
                "Es un mutante que posee sentidos afinados a los animales\n"
                "Capacidades físicas mejoradas\n"
                "Poderosa capacidad de regeneración\n"
                "Tres garras retráctiles en cada mano.\n")).place(x=400, y=130)
        botonsalir=tk.Button(wolve, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 600, y =430)
        PrintWolverine1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonWol)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 560, y =490)

#---------------------Cyclope---------------------------------------
    ImagenCyclops = tk.PhotoImage(file = 'marvel/marvel-cyclops.png')
    PrintCyclops = tk.Label(elframe, image = ImagenCyclops)
    PrintCyclops.grid(row = 4, column = 2)

    tk.Label(elframe, font=8,
        text=("Cyclops\n X-Men #1\n"
            "Scott Summers\n"
            "Marvel Comics")).grid(row=4, column=3)

    def BotonCyclo():
        clyclo = tk.Toplevel()
        clyclo.geometry('850x460')
        clyclo.title('¡Clyclops!')
        clyclo.configure(background='bisque3')

        def salir_ventana():
            clyclo.destroy()

        ImagenCyclops1 = tk.PhotoImage(file = 'marvelfotos/cyclops.png')
        PrintCyclops1 = tk.Label(clyclo, image = ImagenCyclops1)
        PrintCyclops1.grid(row = 0, column = 0)

        tk.Label(clyclo, font=('Comic Sans', 14),
            text=("Cyclops\n X-Men #1\n"
                "Scott Summers\n"
                "Marvel Comics\n"
                "es un mutante \n"
                "con la capacidad de proyectar potentes\n"
                "explosiones de fuerza a través de sus ojos\n"
                "Es visualmente distintivo\n"
                "su visor de rubí de cuarzo,\n"
                "lo que le confiere el nombre clave de Cyclops (Cíclope).\n")).place(x=360, y=100)
        botonsalir=tk.Button(clyclo, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 560, y =390)
        PrintCyclops1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonCyclo)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 560, y =685)

#----------------------Hawkeye------------------------------------
    ImagenHawkeye = tk.PhotoImage(file = 'marvel/marvel-hawkeye.png')
    PrintHawkeye = tk.Label(elframe, image = ImagenHawkeye)
    PrintHawkeye.grid(row = 6, column = 2)

    tk.Label(elframe, font=8,
        text=("Hawkeye\n Tales of Suspense #57\n"
            "Clinton Francis Barton\n"
            "Marvel Comics")).grid(row=6, column=3)

    def BotonHaw():
        haw = tk.Toplevel()
        haw.geometry('700x380')
        haw.title('¡Hawkeye!')
        haw.configure(background='purple')

        def salir_ventana():
            haw.destroy()

        ImagenHawkeye1 = tk.PhotoImage(file = 'marvelfotos/Hawkeye.png')
        PrintHawkeye1 = tk.Label(haw, image = ImagenHawkeye1)
        PrintHawkeye1.grid(row = 0, column = 0)

        tk.Label(haw, font=('Comic Sans', 14),
            text=("Hawkeye\n Tales of Suspense #57\n"
                "Clinton Francis Barton\n"
                "Marvel Comics\n"
                "es un eximio arquero\n"
                "y suele utilizar muchas flechas con trucos\n"
                "ademas de las corrientes\n"
                "Puede apuntar una flecha con perfecta\n"
                "precision desde cualquier angulo.\n")).place(x=300, y=80)
        botonsalir=tk.Button(haw, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 420, y =320)
        PrintHawkeye1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonHaw)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 560, y =875)

#---------------------Silver surfer------------------------------
    ImagenSilver = tk.PhotoImage(file = 'marvel/marvel-silver.png')
    PrintSilver = tk.Label(elframe, image = ImagenSilver)
    PrintSilver.grid(row = 8, column = 2)

    tk.Label(elframe, font=8,
        text=("Silver Surfer\n The Fantastic Four #48\n"
            "Norrin Radd\n"
            "Marvel Comics")).grid(row=8, column=3)

    def BotonSilver():
        sil = tk.Toplevel()
        sil.geometry('700x356')
        sil.title('¡Silver Surfer!')
        sil.configure(background='gray80')

        def salir_ventana():
            sil.destroy()

        ImagenSilver1 = tk.PhotoImage(file = 'marvelfotos/Silver_Surfer.png')
        PrintSilver1 = tk.Label(sil, image = ImagenSilver1)
        PrintSilver1.grid(row = 0, column = 0)

        tk.Label(sil, font=('Comic Sans', 14),
            text=("Silver Surfer\n The Fantastic Four #48\n"
                "Norrin Radd\n"
                "Marvel Comics\n"
                "poderes cósmicos,gracias a que Galactus\n"
                "se los concedió,como heraldo \n"
                "Tiene la capacidad de reunir \n"
                "energía cósmica del ambiente\n"
                "para concentrarla en su cuerpo\n"
                "a voluntad o lanzarla violentamente.\n")).place(x=300, y=50)
        botonsalir=tk.Button(sil, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 440, y =300)
        PrintSilver1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonSilver)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 560, y =1065)

    elframe.update()
    c.config(scrollregion=c.bbox('all'))
    elframe.mainloop()

#--------------------DC----------------------------------------
def dcboton():
    elframe = tk.Toplevel()
    elframe.geometry('780x600')
    elframe.title('Comics de DC')

    scrollbar = tk.Scrollbar(elframe)
    c = tk.Canvas(elframe, yscrollcommand=scrollbar.set)
    scrollbar.config(command= c.yview)
    scrollbar.pack(side= tk.RIGHT, fill= tk.Y)
    elframe = tk.Frame(c)
    c.pack(side='left', fill='both', expand= True)
    c.create_window(0,0, window= elframe, anchor= 'nw')
    imagefondodc = Image.open('dcfondo.png')
    imagefondodc1 = ImageTk.PhotoImage(imagefondodc)
    background_Label = tk.Label(elframe, image=imagefondodc1)
    background_Label.imagefondodc1 = imagefondodc1
    background_Label.place(x=0, y=0, height=1120, width=950)

    ImagenBienvenidaDC = tk.PhotoImage(file = 'dc1.png')
    PrintBienvenida_dc = tk.Label(elframe, image = ImagenBienvenidaDC)
    PrintBienvenida_dc.grid(row=0, column=1)

    ImagenBienvenidaDC1 = tk.PhotoImage(file = 'dc2.png')
    PrintBienvenida_dc1 = tk.Label(elframe, image = ImagenBienvenidaDC1)
    PrintBienvenida_dc1.grid(row=0, column=2)

#----------------------Superman---------------------
    ImagenSuperman = tk.PhotoImage(file = 'dc/dc-superman.png')
    PrintSpiderman = tk.Label(elframe, image = ImagenSuperman)
    PrintSpiderman.grid(row =1, column = 0)

    tk.Label(elframe, font=8,
        text=("Superman\n Action Comics #1\n"
            "kal-El\n"
            "DC Comics")).grid(row=1, column=1)

    def BotonSuper():
        superman = tk.Toplevel()
        superman.geometry('700x500')
        superman.title('¡Superman!')
        superman.configure(background='black')

        def salir_ventana():
            superman.destroy()

        ImagenSuperman1 = tk.PhotoImage(file = 'dcfotos/tomsuper.png')
        PrintSuperman1 = tk.Label(superman, image = ImagenSuperman1)
        PrintSuperman1.grid(row=0, column=0)

        tk.Label(superman, font=('Comic Sans', 18),
            text=("Superman\n Action Comics #1\n"
                "kal-El\n"
                "DC Comics\n"
                "súper fuerza\n"
                "invulnerabilidad\n"
                "la capacidad de volar\n"
                "visión calorífica\n"
                "el aliento helado.\n")).place(x=410, y=100)
        botonsalir=tk.Button(superman, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 480, y =430)
        PrintSuperman1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonSuper)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =290)

#----------------Wonder woman----------------------------------
    ImagenWonder = tk.PhotoImage(file = 'dc/dc-wonder.png')
    PrintWonder = tk.Label(elframe, image = ImagenWonder)
    PrintWonder.grid(row =2, column = 0)

    tk.Label(elframe, font=8,
        text=("Wonder Woman\n All Star Comics #8\n"
            "Princess Diana\n"
            "DC Comics")).grid(row=2, column=1)

    def BotonWonder():
        wonder = tk.Toplevel()
        wonder.geometry('700x400')
        wonder.title('¡Wonder Woman!')
        wonder.configure(background='medium spring green')

        def salir_ventana():
            wonder.destroy()

        ImagenWonder1 = tk.PhotoImage(file = 'dcfotos/wonder.png')
        PrintWonder1 = tk.Label(wonder, image = ImagenWonder1)
        PrintWonder1.grid(row =0, column = 0)

        tk.Label(wonder, font=('Comic Sans', 14),
            text=("Wonder Woman\n All Star Comics #8\n"
                "Princess Diana\n"
                "DC Comics\n"
                "Invulnerabilidad al fuego\n"
                "Agilidad superhumana\n"
                "Teletransportación dimensional\n"
                "Durabilidad superhumana\n"
                "Comunicación con animales\n"
                "Multi-lenguaje.\n")).place(x=350, y=60)
        botonsalir=tk.Button(wonder, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 435, y =340)
        PrintWonder1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonWonder)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =480)

#--------------------Robin nightwing-----------------------
    ImagenRobin = tk.PhotoImage(file = 'dc/dc-robin.png')
    PrintRobin = tk.Label(elframe, image = ImagenRobin)
    PrintRobin.grid(row =4, column = 0)

    tk.Label(elframe, font=8,
        text=("Robin/Nightwing\n Detective Comics #38\n"
            "Dick Grayson\n"
            "DC Comics")).grid(row=4, column=1)

    def BotonRobin():
        robin = tk.Toplevel()
        robin.geometry('800x506')
        robin.title('¡Robin/Nightwing!')
        robin.configure(background='honeydew4')

        def salir_ventana():
            robin.destroy()

        ImagenRobin1 = tk.PhotoImage(file = 'dcfotos/robin.png')
        PrintRobin1 = tk.Label(robin, image = ImagenRobin1)
        PrintRobin1.grid(row =0, column = 0)

        tk.Label(robin, font=('Comic Sans', 18),
            text=("Robin/Nightwing\n Detective Comics #38\n"
                "Dick Grayson\n"
                "DC Comics\n"
                "es experto en las artes marciales\n"
                "crea armas simples\n")).place(x=425, y=150)
        botonsalir=tk.Button(robin, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 550, y =430)
        PrintRobin1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonRobin)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =675)

#-----------------Flash---------------------------
    ImagenFlash = tk.PhotoImage(file = 'dc/dc-flash.png')
    PrintFlash = tk.Label(elframe, image = ImagenFlash)
    PrintFlash.grid(row =6, column = 0)

    tk.Label(elframe, font=8,
        text=("Flash\n Flash Comics #1\n"
            "Barry Allen\n"
            "DC Comics")).grid(row=6, column=1)

    def BotonFlash():
        flash = tk.Toplevel()
        flash.geometry('840x455')
        flash.title('¡Flash!')
        flash.configure(background='firebrick2')

        def salir_ventana():
            flash.destroy()

        ImagenFlash1 = tk.PhotoImage(file = 'dcfotos/flashba.png')
        PrintFlash1 = tk.Label(flash, image = ImagenFlash1)
        PrintFlash1.grid(row =0, column = 0)

        tk.Label(flash, font=('Comic Sans', 16),
            text=("Flash\n Flash Comics #1\n"
                "Barry Allen\n"
                "DC Comics\n"
                "pensar y reaccionar a velocidad luz\n"
                "además de tener una resistencia sobrehumana\n"
                "que les permite recorrer distancias increíbles.\n")).place(x=380, y=150)
        botonsalir=tk.Button(flash, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 555, y =390)
        PrintFlash1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonFlash)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =870)

#--------------Linterna verde--------------------------
    ImagenVerde = tk.PhotoImage(file = 'dc/dc-green.png')
    PrintVerde = tk.Label(elframe, image = ImagenVerde)
    PrintVerde.grid(row =8, column = 0)

    tk.Label(elframe, font=8,
        text=("Green Lantern\n All-American Comics #16\n"
            "Alan Scott\n"
            "DC Comics")).grid(row=8, column=1)

    def BotonVerde():
        verde = tk.Toplevel()
        verde.geometry('800x545')
        verde.title('¡Green Lantern!')
        verde.configure(background='forest green')

        def salir_ventana():
            verde.destroy()

        ImagenVerde1 = tk.PhotoImage(file = 'dcfotos/linver.png')
        PrintVerde1 = tk.Label(verde, image = ImagenVerde1)
        PrintVerde1.grid(row =0, column = 0)

        tk.Label(verde, font=('Comic Sans', 16),
            text=("Green Lantern\n All-American Comics #16\n"
                "Alan Scott\n"
                "DC Comics\n"
                "se caracterizan por un anillo de poder\n"
                "y la capacidad de crear manifestaciones\n"
                "de luz sólida con los susodichos anillos.\n")).place(x=390, y=180)
        botonsalir=tk.Button(verde, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 520, y =470)
        PrintVerde1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonVerde)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 150, y =1065)

#--------------Flecha verde-----------------------
    ImagenFlecha = tk.PhotoImage(file = 'dc/dc-arrow.png')
    PrintFlecha = tk.Label(elframe, image = ImagenFlecha)
    PrintFlecha.grid(row =1, column = 2)

    tk.Label(elframe, font=8,
        text=("Green Arrow\n More Fun Comics #73\n"
            "Oliver Queen\n"
            "DC Comics")).grid(row=1, column=3)

    def BotonFlecha():
        flecha = tk.Toplevel()
        flecha.geometry('740x505')
        flecha.title('¡Green Arrow!')
        flecha.configure(background='royal blue')

        def salir_ventana():
            flecha.destroy()

        ImagenFlecha1 = tk.PhotoImage(file = 'dcfotos/flechaoli.png')
        PrintFlecha1 = tk.Label(flecha, image = ImagenFlecha1)
        PrintFlecha1.grid(row =0, column = 0)

        tk.Label(flecha, font=('Comic Sans', 16),
            text=("Green Arrow\n More Fun Comics #73\n"
                "Oliver Queen\n"
                "DC Comics\n"
                "Posee una gran habilidad como arquero\n"
                "y tiene un amplio arsenal de flechas\n"
                "Excelente rastreador\n"
                "manejo de armas y piloto aviador.\n")).place(x=350, y=150)
        botonsalir=tk.Button(flecha, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 490, y =440)
        PrintFlecha1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonFlecha)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 550, y =290)

#-----------------Martian Manhunter------------------------
    ImagenMartin = tk.PhotoImage(file = 'dc/dc-martian.png')
    PrintMartin = tk.Label(elframe, image = ImagenMartin)
    PrintMartin.grid(row = 2, column = 2)

    tk.Label(elframe, font=8,
        text=("Martian Manhunter\n Detective Comics #225\n"
            "Martian Manhunter\n"
            "DC Comics")).grid(row=2, column=3)

    def BotonMartin():
        martin = tk.Toplevel()
        martin.geometry('700x510')
        martin.title('¡Martian Manhunter!')
        martin.configure(background='RoyalBlue4')

        def salir_ventana():
            martin.destroy()

        ImagenMartin1 = tk.PhotoImage(file = 'dcfotos/martian.png')
        PrintMartin1 = tk.Label(martin, image = ImagenMartin1)
        PrintMartin1.grid(row = 0, column = 0)

        tk.Label(martin, font=('Comic Sans', 18),
            text=("Martian Manhunter\n Detective Comics #225\n"
                "Martian Manhunter\n"
                "DC Comics\n"
                "Superfuerza Velocidad \n"
                "Telepatía Telekinesis\n"
                "Cambio de forma\n"
                "Nueve sentidos\n")).place(x=390, y=140)
        botonsalir=tk.Button(martin, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 465, y =440)
        PrintMartin1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonMartin)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 550, y =480)

#-------------Blue Beetle------------------------
    ImagenBlue = tk.PhotoImage(file = 'dc/dc-blue.png')
    PrintBlue = tk.Label(elframe, image = ImagenBlue)
    PrintBlue.grid(row = 4, column = 2)

    tk.Label(elframe, font=8,
        text=("Blue Beetle\n Mystery Men Comics #1\n"
            "Dan Garret\n"
            "DC Comics")).grid(row=4, column=3)

    def BotonBlue():
        blue = tk.Toplevel()
        blue.geometry('700x505')
        blue.title('¡Blue Beetle!')
        blue.configure(background='SteelBlue4')

        def salir_ventana():
            blue.destroy()

        ImagenBlue1 = tk.PhotoImage(file = 'dcfotos/bluebe.png')
        PrintBlue1 = tk.Label(blue, image = ImagenBlue1)
        PrintBlue1.grid(row = 0, column = 0)

        tk.Label(blue, font=('Comic Sans', 18),
            text=("Blue Beetle\n Mystery Men Comics #1\n"
                "Dan Garret\n"
                "DC Comics\n"
                "capacidad de volar\n"
                "superfuerza y luminosidad\n")).place(x=370, y=160)
        botonsalir=tk.Button(blue, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.place(x = 465, y =430)
        PrintBlue1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonBlue)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 550, y =675)

#----------------Black Canary------------------
    ImagenBlack = tk.PhotoImage(file = 'dc/dc-black.png')
    PrintBlack = tk.Label(elframe, image = ImagenBlack)
    PrintBlack.grid(row = 6, column = 2)

    tk.Label(elframe, font=8,
        text=("Black Canary\n Flash Comics #86\n"
            "Dinah Drake\n"
            "DC Comics")).grid(row=6, column=3)

    def BotonBlack():
        black = tk.Toplevel()
        black.geometry('1050x550')
        black.title('¡Black Canary!')
        black.configure(background='orchid2')

        def salir_ventana():
            black.destroy()

        ImagenBlack1 = tk.PhotoImage(file = 'dcfotos/blackca.png')
        PrintBlack1 = tk.Label(black, image = ImagenBlack1)
        PrintBlack1.grid(row = 0, column = 0)

        tk.Label(black, font=('Comic Sans', 16),
            text=("Black Canary\n Flash Comics #86\n"
                "Dinah Drake\n"
                "DC Comics\n"
                "Su superpoder más conocido es el grito del canario\n"
                "Un chillido ultrasónico que le permite aturdir a sus enemigos\n"
                "E incluso destruir objetos\n")).place(x=480, y=180)
        botonsalir=tk.Button(black, text = "RETROCEDER", command = salir_ventana,fg = 'red', padx = 10, pady = 10)
        botonsalir.config(width=12, height=0)
        botonsalir.place(x = 720, y =480)
        PrintBlack1.mainloop()

    boton_1 = tk.Button(elframe, text = "Más", command = BotonBlack)
    boton_1.config(width=8, height=0)
    boton_1.place(x = 550, y =870)

    elframe.update()
    c.config(scrollregion=c.bbox('all'))
    elframe.mainloop()

#--------------BOTONES-----------
BotonMarvel = tk.Button(RaizComic, text = 'MARVEL', command = marvelbo, fg = 'RED', padx = 40, pady = 5)
BotonMarvel.place(x=100, y=80)
botonsalir = tk.Button(RaizComic, text = 'SALIR', command= salir, padx = 10, pady = 10)
botonsalir.place(x=275, y= 500)
BotonDC = tk.Button(RaizComic, text= 'DC', command= dcboton, fg = 'BLUE', padx = 50, pady = 5)
BotonDC.place(x=380, y=80)
#botonbuscar = tk.Button(RaizComic, text= 'BUSCAR', padx = 10, pady = 5)
#botonbuscar.place(x=275,y=80)

RaizComic.mainloop()


class Solution:
    def nextGreatestLetter(self, letters: List[str], target: str) -> str:
        if target >= letters[-1] or target < letters[0]:
            return letters[0]
        i, j = 0, len(letters)-1

        while i <= j:
            mid = (i+j) // 2
            if letters[mid] > target:
                j = mid -1
            elif letters[mid] <= target:
                i = mid + 1

        if letters[i] <= target:
            return letters[i+1]
        else:
            return letters[i]


def mini(l):
    m=l[0]
    for i in l:
        if i<m:
            m=i
    return m

def Sort(l):
    if len(l)==1 or l==[]:
        return l
    m=mini(l)
    l.remove(m)
    return [m]+Sort(l)

l=[5,2,3,1,4]
print(Sort(l))


# -*- coding: utf-8 -*-
"""
Created on Tue Oct  5 09:01:40 2021

@author: staar
"""

#%%
import matplotlib as mpl
help(mpl.figure) # too big -- this is sub-module !
dir(mpl.figure)

help(mpl.figure.Figure)  # it's still big!

#%% see first simpler pyplot constructor

import matplotlib.pyplot as plt
help(plt.figure)

#%%
"""
figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True,
       FigureClass=<class 'matplotlib.figure.Figure'>, clear=False, **kwargs)

    Create a new figure, or activate an existing figure.

    Parameters
    ----------
    num : int or str, optional
        A unique identifier for the figure.

        If a figure with that identifier already exists, this figure is made
        active and returned.
        An integer refers to the ``Figure.number``
        attribute, a string refers to the figure label.

        If there is no figure with the identifier or *num* is not given, a new
        figure is created, made active and returned.
        If *num* is an int, it
        will be used for the ``Figure.number`` attribute, otherwise, an
        auto-generated integer value is used (starting at 1 and incremented
        for each new figure). If *num* is a string, the figure label and the
        window title is set to this value.

    figsize : (float, float), default: :rc:`figure.figsize`
        Width, height in inches.

    dpi : float, default: :rc:`figure.dpi`
        The resolution of the figure in dots-per-inch.

    facecolor : color, default: :rc:`figure.facecolor`
        The background color.

    edgecolor : color, default: :rc:`figure.edgecolor`
        The border color.

    frameon : bool, default: True
        If False, suppress drawing the figure frame.

    FigureClass : subclass of `~matplotlib.figure.Figure`
        Optionally use a custom `.Figure` instance.

    clear : bool, default: False
        If True and the figure already exists, then it is cleared.

    tight_layout : bool or dict, default: :rc:`figure.autolayout`
        If ``False`` use *subplotpars*. If ``True`` adjust subplot
        parameters using `.tight_layout` with default padding.
        When providing a dict containing the keys ``pad``, ``w_pad``,
        ``h_pad``, and ``rect``, the default `.tight_layout` paddings
        will be overridden.

    constrained_layout : bool, default: :rc:`figure.constrained_layout.use`
        If ``True`` use constrained layout to adjust positioning of plot
        elements.  Like ``tight_layout``, but designed to be more
        flexible.  See
        :doc:`/tutorials/intermediate/constrainedlayout_guide`
        for examples.  (Note: does not work with `add_subplot` or
        `~.pyplot.subplot2grid`.)

    **kwargs : optional
        See `~.matplotlib.figure.Figure` for other possible arguments.

    Returns
    -------
    `~matplotlib.figure.Figure`
        The `.Figure` instance returned will also be passed to
        new_figure_manager in the backends, which allows to hook custom
        `.Figure` classes into the pyplot interface. Additional kwargs will be
        passed to the `.Figure` init function.

    Notes
    -----
    If you are creating many figures, make sure you explicitly call
    `.pyplot.close` on the figures you are not using, because this will
    enable pyplot to properly clean up the memory.

    `~matplotlib.rcParams` defines the default values, which can be modified
    in the matplotlibrc file.
"""
#%%

plt.figure(1, clear=True)  # clearing figure 1 (if exists)
plt.figure(1, tight_layout=True)

#%%
fig = mpl.figure.Figure()
ax = fig.add_subplot()
ax.plot(range(5), [3, 2, 5, 4, 1])
# nothing...

fig.draw(...)     # ???

fig.show()  # AttributeError: Figure.show works only for figures managed by pyplot,
            # normally created by pyplot.figure()

#%%
#%%
import matplotlib as mpl
help(mpl.figure) # too big -- this is sub-module !
dir(mpl.figure)

help(mpl.figure.Figure)

# https://matplotlib.org/stable/api/figure_api.html#module-matplotlib.figure
"""
Parameters:

figsize : 2-tuple of floats, default: rcParams["figure.figsize"] (default: [6.4, 4.8])
    Figure dimension (width, height) in inches.

dpi : float, default: rcParams["figure.dpi"] (default: 100.0)
    Dots per inch.

facecolor : default: rcParams["figure.facecolor"] (default: 'white')
    The figure patch facecolor.

edgecolor : default: rcParams["figure.edgecolor"] (default: 'white')
    The figure patch edge color.

linewidth : float
    The linewidth of the frame (i.e. the edge linewidth of the figure patch).

frameonbool : default: rcParams["figure.frameon"] (default: True)
    If False, suppress drawing the figure background patch.

subplotpars : SubplotParams
    Subplot parameters. If not given, the default subplot parameters rcParams["figure.subplot.*"] are used.

tight_layout : bool or dict, default: rcParams["figure.autolayout"] (default: False)
    If False use subplotpars.
    If True adjust subplot parameters using tight_layout with default padding.
    When providing a dict containing the keys pad, w_pad, h_pad, and rect,
    the default tight_layout paddings will be overridden.

constrained_layout : bool, default: rcParams["figure.constrained_layout.use"] (default: False)
    If True use constrained layout to adjust positioning of plot elements.
    Like tight_layout, but designed to be more flexible. See Constrained Layout Guide for examples. (Note: does not work with add_subplot or subplot2grid.)

"""
#%%


'''
Підрахуйте кількість елементів одновимірного масиву, які збігаються зі
своїм номером і при цьому кратні 3.
Виконав студент групи КН-А Андрощук Артем Олександрович
'''

n = int(input("Input quantity of array: "))  # Користувач вводить кількість чисел у масиві

array = []  # Ініціалізуємо масив

answer = 0  # Ініціалізуємо змінну яка підрахує к-сть чисел

for i in range(n):  # проходимо по циклу n разів
    x = int(input())  # вводимо число з клавіатури
    array.append(x)  # додаємо це число до масиву

for i in range(n):  # проходимо по циклу n разів
    if array[i] == i and array[i] % 3 == 0: # перевіряємо умову задачі
        answer += 1
print(answer)


import torch
from sentence_transformers import SentenceTransformer
import numpy as np
from tqdm import tqdm
import json
import argparse
from PIL import Image
from lavis.models import load_model_and_preprocess
import torch

def sbert_encoder(utterances, directory, split):
    """
    Encodes `utterances` with sentence_transformers library and saves embeddings to .npy file.

    Params
    ------
        utterances: list[str], all utterances from dataset
        path: str, where to save .npy file
    """
    model = SentenceTransformer('sentence-transformers/all-distilroberta-v1').to('cuda')
    embeddings = model.encode(utterances, show_progress_bar=True)
    np.save(f'{directory}/{split}_embeddings', embeddings)

def clip_encoder(utterances, directory, split, image_batch_size=8, text_batch_size=32):
    """
    Encodes `utterances` with sentence_transformers library and saves embeddings to .npy file.

    Params
    ------
        utterances: list[str], all utterances from dataset
        path: str, where to save .npy file
    """

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    model, vis_processors, txt_processors = load_model_and_preprocess(
        name="clip_feature_extractor",
        model_type="ViT-B-16",
        is_eval=True,
        device=device
    )

    # divide images, texts and last utterances
    images = []
    texts = []
    last_utters = []
    is_image = []
    for i, ut in enumerate(utterances):
        if isinstance(ut, list):
            is_image.append(True)
            img, lut = ut
            images.append(Image.open(img).convert('RGB'))
            last_utters.append(lut)
        else:
            is_image.append(False)
            texts.append(ut)
    is_image = np.array(is_image)

    pbar = tqdm(total=len(images) * 2 + len(texts))

    # encode them all
    image_embeddings = []
    for i in range(0, len(images), image_batch_size):
        inp = images[i:i+image_batch_size]
        preproc = torch.stack(list(map(vis_processors['eval'], inp)))
        embs = model.extract_features({'image': preproc.to(device)})
        image_embeddings.append(embs.detach().cpu().numpy())
        pbar.update(len(inp))
    image_embeddings = np.concatenate(image_embeddings, axis=0)

    text_embeddings = []
    for i in range(0, len(texts), text_batch_size):
        inp = texts[i:i+text_batch_size]
        preproc = txt_processors['eval'](inp)
        embs = model.extract_features({'text_input': preproc})
        text_embeddings.append(embs.detach().cpu().numpy())
        pbar.update(len(inp))
    text_embeddings = np.concatenate(text_embeddings, axis=0)

    last_utters_embeddings = []
    for i in range(0, len(texts), text_batch_size):
        inp = last_utters[i:i+text_batch_size]
        preproc = txt_processors['eval'](inp)
        embs = model.extract_features({'text_input': preproc})
        last_utters_embeddings.append(embs.detach().cpu().numpy())
        pbar.update(len(inp))
    last_utters_embeddings = np.concatenate(last_utters_embeddings, axis=0)

    # these will be used in dgac_clustering.py
    embeddings = np.empty((len(utterances), text_embeddings.shape[1]))
    embeddings[is_image] = image_embeddings
    embeddings[~is_image] = text_embeddings
    np.save(f'{directory}/{split}_embeddings', embeddings)

    # these will be used in response_selection.py and my_dff.py
    embeddings[is_image] = last_utters_embeddings
    np.save(f'{directory}/{split}_response_embeddings', embeddings)

if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument('--task', dest='task', required=True)
    args = ap.parse_args()

    directory = f'{args.task}_stuff'

    # load json files
    train_utterances = json.load(open(f'{directory}/train_utterances.json', 'r'))
    test_utterances = json.load(open(f'{directory}/test_utterances.json', 'r'))
    val_utterances = json.load(open(f'{directory}/val_utterances.json', 'r'))

    if args.task == 'persona_chat':
        encoder = sbert_encoder
    elif args.task == 'imad':
        encoder = clip_encoder
    else:
        raise ValueError(f'not supported: {args.task}')

    encoder(train_utterances, directory, 'train')
    encoder(test_utterances, directory, 'test')
    encoder(val_utterances, directory, 'val')


from app.servicios.conectar_sql import conexion_sql, crear_diccionario
from app.servicios.urls import rutaLogs
from datetime import datetime

def tienePermiso(idUsuario, seccion):
    # El ID de los componentes de React (idReact en la BD) es igual a la sección, pero con la primera letra en minúscula
    cnxn = conexion_sql('DJANGO')
    if seccion == "Home":
        cursor = cnxn.cursor().execute(f"select usuario from DJANGO.php.usuarios u where id = {idUsuario}")
        resultados = crear_diccionario(cursor)
        # print(f"resultados[0]['usuario'][-15:] desde permisos.py = {resultados[0]['usuario'][-15:]}")
        return resultados[0]['usuario'][-15:] == 'chedraui.com.mx'
    idReact = seccion[0].lower() + seccion[1:]
    query = f"""select * from DJANGO.php.permisosVistas pv
    left join DJANGO.php.usuariosAreas ua on pv.area = ua.area
    left join DJANGO.php.vistas v on v.id_vista = pv.vista
    where ua.id_usuario  = {idUsuario}
    and v.idReact='{idReact}'"""
    cursor = cnxn.cursor().execute(query)
    resultados = crear_diccionario(cursor)
    # print(f"arreglo de resultados de permisos.py: {str(resultados)}")
    return len(resultados) > 0

def permisoMarkdown(id_rol, nombre_archivo):
    query = f"""
    select *
    from DJANGO.php.vistas_documentos vd
    left join DJANGO.php.usuario_vista uv on vd.id_vista = uv.id_vista
    where vd.nombre_archivo = '{nombre_archivo}'
    and uv.id_rol = {id_rol}
    """
    cnxn = conexion_sql('DJANGO')
    cursor = cnxn.cursor().execute(query)
    resultados = crear_diccionario(cursor)
    # print(f"arreglo de resultados de permisos.py: {str(resultados)}")
    return True if len(resultados) > 0 else False


import tensorflow as tf

c = TF_CONFIG = {
    "task": {
        "type": "worker",
        "index": 1,
    },
    "environment": "CLOUD", # LOCAL | CLOUD
    "cluster": {
        "worker": [
            "localhost:2222",
            "localhost:2223",
            "localhost:2224"
        ],
        "ps": [
            "localhost:2220",
        ]
    }
}
cluster_spec = tf.train.ClusterSpec(c["cluster"])
ps = tf.train.Server(cluster_spec,job_name='ps')
ps.join()


def check(ca,cb):
    i='a'
    while(i<='z'):
        if ca[i]>=cb[i]:
            x=1
        else:
            return False
        i=chr(ord(i)+1)
    return True

def findMinLen(b,a):
    ca={}
    cb={}
    reset={}
    i='a'
    while(i<='z'):
        reset[i]=0
        ca[i]=0
        cb[i]=0
        i=chr(ord(i)+1)
    for i in b:
        cb[i]+=1

    ans=9999999999

    for i in range(len(a)):
        for j in range(i,len(a)):
            ca[a[j]]+=1
            if (check(ca,cb)==True):
                ans=min(ans,j-i+1)
        x='a'
        while(x<='z'):
            ca[x]=0
            x=chr(ord(x)+1)
    return ans if ans!=9999999999 else -1
for _ in range(int(input())):
    val,txt=map(str,input().split())
    print(findMinLen(val,txt))

Enclosing Substring using carryforward.py


import argparse
import os
import glob
import pickle
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans

import torch

from src.ebirl import EBIRL
from src.data import pad_collate
from src.train_utils import train, Logger

def parse_args():
    bool_ = lambda x: x if isinstance(x, bool) else x == "True"

    parser = argparse.ArgumentParser()
    # data args
    parser.add_argument("--data_path", type=str, default="../../data", help="data path, default=../../data")
    parser.add_argument("--exp_path", type=str, default="../../exp", help="experiment path, default=../exp")
    # agent args
    parser.add_argument("--state_dim", type=int, default=2, help="agent state dimension, default=2")
    parser.add_argument("--horizon", type=int, default=30, help="agent max plan horizon, default=30")
    # prior args
    parser.add_argument("--prior_cov", type=str, choices=["diag", "full"], default="full", help="prior covariance type, default=full")
    parser.add_argument("--bc_penalty", type=float, default=1., help="prior behavior cloning penalty, default=1.")
    parser.add_argument("--obs_penalty", type=float, default=1., help="observation likelihood penalty, default=1.")
    parser.add_argument("--kl_penalty", type=float, default=1., help="prior kl penalty, default=1.")
    # train args
    parser.add_argument("--cp_path", type=str, default="none", help="checkpoint path, default=none")
    parser.add_argument("--lr", type=float, default=0.01)
    parser.add_argument("--decay", type=float, default=0.)
    parser.add_argument("--epochs", type=int, default=100)
    parser.add_argument("--cp_every", type=int, default=20)
    parser.add_argument("--verbose", type=int, default=10)
    parser.add_argument("--save", type=bool_, default=True)
    parser.add_argument("--seed", type=int, default=0)
    arglist = parser.parse_args()
    arglist = vars(arglist)
    return arglist

def main(arglist):
    np.random.seed(arglist["seed"])
    torch.manual_seed(arglist["seed"])
    print(f"learning with args: {arglist}\n")

    # load data
    with open(os.path.join(arglist["data_path"], "data.p"), "rb") as f:
        data = pickle.load(f)

    # parse data
    data = [
        {
            k: torch.from_numpy(v).to(torch.float32)
            for k, v in d.items() if k not in ["drive_id", "t"]
        } for d in data
    ]
    data, mask = pad_collate(data)

    # process data
    nan_mask = mask.clone()
    nan_mask[mask == 0] = torch.nan
    obs_np = (nan_mask.unsqueeze(-1) * data["obs"]).numpy()

    obs_mean = np.nanmean(obs_np, axis=(0, 1))
    obs_std = np.nanstd(obs_np, axis=(0, 1))

    obs = (data["obs"] - obs_mean) / obs_std
    act = data["act"].long()

    data = (obs, act, mask)

    # compute kmeans obs initialization
    kmeans_data = obs.flatten(0, 1).numpy()
    kmeans_data = kmeans_data[mask.flatten() == 1]
    kmeans = KMeans(n_clusters=arglist["state_dim"]).fit(kmeans_data)
    kmeans_centers = torch.from_numpy(kmeans.cluster_centers_).to(torch.float32)

    # init model
    batch_size = obs.shape[1]
    act_dim = len(torch.unique(act))
    obs_dim = obs.shape[-1]
    model = EBIRL(
        arglist["state_dim"], act_dim, obs_dim, arglist["horizon"],
        prior_cov=arglist["prior_cov"], bc_penalty=arglist["bc_penalty"],
        obs_penalty=arglist["obs_penalty"], kl_penalty=arglist["kl_penalty"]
    )
    model.init_params(kmeans_centers)
    model.init_q(batch_size, freeze_prior=False)
    print(model)

    # init loss function
    loss_fn = lambda m, o, a, mask: m.compute_loss(o, a, mask)
    optimizer = torch.optim.Adam(model.parameters(), lr=arglist["lr"], weight_decay=arglist["decay"])

    # load pretrained prior
    cp_history = None
    if arglist["cp_path"] != "none":
        cp_path = os.path.join(arglist["exp_path"], arglist["cp_path"])
        cp_model_path = glob.glob(os.path.join(cp_path, "models/*.pt"))
        cp_model_path.sort(key=lambda x: int(os.path.basename(x).replace(".pt", "").split("_")[-1]))

        state_dict = torch.load(cp_model_path[-1], map_location="cpu")
        model.load_state_dict(state_dict["model_state_dict"], strict=False)
        optimizer.load_state_dict(state_dict["optimizer_state_dict"])

        # load history
        cp_history = pd.read_csv(os.path.join(cp_path, "history.csv"))
        print(f"loaded checkpoint from {cp_path}")

    callback = None
    if arglist["save"]:
        if not os.path.exists(arglist["exp_path"]):
            os.mkdir(arglist["exp_path"])
        callback = Logger(arglist, model.plot_keys, cp_history)

    # train loop
    model, optimizer, df_history, callback = train(
        model, data, loss_fn, optimizer, arglist["epochs"],
        verbose=arglist["verbose"], callback=callback, grad_check=False
    )

    if arglist["save"]:
        callback.save_checkpoint(model, optimizer)
        callback.save_history(df_history)
    return model, df_history

if __name__ == "__main__":
    arglist = parse_args()
    main(arglist)


## PyTorch
import torch
import torch.nn as nn
import torch.optim as optim

import numpy as np
import random
import math
import json
from functools import partial
import torch.nn.functional as F

# PyTorch Lightning
import pytorch_lightning as pl
from pytorch_lightning.callbacks import LearningRateMonitor, ModelCheckpoint

class CosineWarmupScheduler(optim.lr_scheduler._LRScheduler):

    def __init__(self, optimizer, warmup, max_iters):
        self.warmup = warmup
        self.max_num_iters = max_iters
        super().__init__(optimizer)

    def get_lr(self):
        lr_factor = self.get_lr_factor(epoch=self.last_epoch)
        return [base_lr * lr_factor for base_lr in self.base_lrs]

    def get_lr_factor(self, epoch):
        lr_factor = 0.5 * (1 + np.cos(np.pi * epoch / self.max_num_iters) )
        if epoch <= self.warmup:
            lr_factor *= epoch * 1.0 / self.warmup
        return lr_factor

def scaled_dot_product(q, k, v, mask=None):
    d_k = q.size()[-1]
    attn_logits = torch.matmul(q, k.transpose(-2, -1))
    attn_logits = attn_logits / math.sqrt(d_k)
    if mask is not None:
        nHeads=attn_logits.shape[-3]
        mask=mask.unsqueeze(dim=-3)
        mask=torch.repeat_interleave(mask,nHeads,dim=-3)
        attn_logits = attn_logits.masked_fill(mask == 0, -9e15)
    attention = F.softmax(attn_logits, dim=-1)
    values = torch.matmul(attention, v)
    return values, attention

class MultiheadAttention(nn.Module):
    """
    Applying a Multi-Head Attention layer in a neural network, where we don’t have an arbitrary query, key, and value vector.
       A simple but effective implementation is to set the current feature map in a NN, , as , and ( being the batch size,
       the sequence length, the hidden dimensionality of ). The consecutive weight matrices ,
       and can transform to the corresponding feature vectors that represent the queries, keys, and values of the input.
    """
    def __init__(self, input_dim, embed_dim, num_heads):
        super().__init__()
        assert embed_dim % num_heads == 0, "Embedding dimension must be 0 modulo number of heads. " +str(embed_dim)+"%"+str(num_heads)

        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads
        # Stack all weight matrices 1...h together for efficiency
        # Note that in many implementations you see "bias=False" which is optional
        self.qkv_proj = nn.Linear(input_dim, 3*embed_dim)
        self.o_proj = nn.Linear(embed_dim, embed_dim)

        self._reset_parameters()

    def _reset_parameters(self):
        # Original Transformer initialization, see PyTorch documentation
        nn.init.xavier_uniform_(self.qkv_proj.weight)
        self.qkv_proj.bias.data.fill_(0)
        nn.init.xavier_uniform_(self.o_proj.weight)
        self.o_proj.bias.data.fill_(0)

    def forward(self, x, mask=None, return_attention=False):
        batch_size, seq_length, _ = x.size()
        qkv = self.qkv_proj(x)

        # Separate Q, K, V from linear output
        qkv = qkv.reshape(batch_size, seq_length, self.num_heads, 3*self.head_dim)
        qkv = qkv.permute(0, 2, 1, 3) # [ Batch, Head, SeqLen, Dims ]
        q, k, v = qkv.chunk(3, dim=-1)

        # Determine value outputs
        values, attention = scaled_dot_product(q, k, v, mask=mask)
        values = values.permute(0, 2, 1, 3) # [Batch, SeqLen, Head, Dims]
        values = values.reshape(batch_size, seq_length, self.embed_dim)
        o = self.o_proj(values)

        if return_attention:
            return o, attention
        else:
            return o

class EncoderBlock(nn.Module):

    def __init__(self, input_dim, num_heads, dim_feedforward, dropout=0.0):
        """
        Inputs:
            input_dim - Dimensionality of the input
            num_heads - Number of heads to use in the attention block
            dim_feedforward - Dimensionality of the hidden layer in the MLP
            dropout - Dropout probability to use in the dropout layers
        """
        super().__init__()

        # Attention layer
        self.self_attn = MultiheadAttention(input_dim, input_dim, num_heads)

        # Two-layer MLP
        self.linear_net = nn.Sequential(
            nn.Linear(input_dim, dim_feedforward),
            nn.Dropout(dropout),
            nn.ReLU(inplace=True),
            nn.Linear(dim_feedforward, input_dim)
        )

        # Layers to apply in between the main layers
        self.norm1 = nn.LayerNorm(input_dim)
        self.norm2 = nn.LayerNorm(input_dim)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # Attention part
        attn_out = self.self_attn(x, mask=mask)
        x = x + self.dropout(attn_out)
        x = self.norm1(x)

        # MLP part
        linear_out = self.linear_net(x)
        x = x + self.dropout(linear_out)
        x = self.norm2(x)

        return x

class TransformerEncoder(nn.Module):
    def __init__(self, num_layers, **block_args):
        super().__init__()
        self.layers = nn.ModuleList([EncoderBlock(**block_args) for _ in range(num_layers)])

    def forward(self, x, mask=None):
        for l in self.layers:
            x = l(x, mask=mask)
        return x

    def get_attention_maps(self, x, mask=None):
        attention_maps = []
        for l in self.layers:
            _, attn_map = l.self_attn(x, mask=mask, return_attention=True)
            attention_maps.append(attn_map)
            x = l(x)
        return attention_maps

class PositionalEncoding(nn.Module):

    def __init__(self, d_model, max_len=5000):
        """
        Inputs
            d_model - Hidden dimensionality of the input.
            max_len - Maximum length of a sequence to expect.
        """
        super().__init__()

        # Create matrix of [SeqLen, HiddenDim] representing the positional encoding for max_len inputs
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)

        # register_buffer => Tensor which is not a parameter, but should be part of the modules state.
        # Used for tensors that need to be on the same device as the module.
        # persistent=False tells PyTorch to not add the buffer to the state dict (e.g. when we save the model)
        self.register_buffer('pe', pe, persistent=False)

    def forward(self, x):
        x = x + self.pe[:, :x.size(1)]
        return x

class TransformerPredictor(pl.LightningModule):

    def __init__(self, input_dim, model_dim, num_classes, num_heads,
                 num_layers, lr, warmup, max_iters, dropout=0.0, input_dropout=0.0):
        """
        Inputs:
            input_dim - Hidden dimensionality of the input
            model_dim - Hidden dimensionality to use inside the Transformer
            num_classes - Number of classes to predict per sequence element
            num_heads - Number of heads to use in the Multi-Head Attention blocks
            num_layers - Number of encoder blocks to use.
            lr - Learning rate in the optimizer
            warmup - Number of warmup steps. Usually between 50 and 500
            max_iters - Number of maximum iterations the model is trained for. This is needed for the CosineWarmup scheduler
            dropout - Dropout to apply inside the model
            input_dropout - Dropout to apply on the input features
        """
        super().__init__()
        self.save_hyperparameters()
        self._create_model()

    def _create_model(self):
        # Input dim -> Model dim
        self.input_net = nn.Sequential(
            nn.Dropout(self.hparams.input_dropout),
            nn.Linear(self.hparams.input_dim, self.hparams.model_dim)
        )
        # Positional encoding for sequences
        self.positional_encoding = PositionalEncoding(d_model=self.hparams.model_dim)
        # Transformer
        self.transformer = TransformerEncoder(num_layers=self.hparams.num_layers,
                                              input_dim=self.hparams.model_dim,
                                              dim_feedforward=2*self.hparams.model_dim,
                                              num_heads=self.hparams.num_heads,
                                              dropout=self.hparams.dropout)
        # Output classifier per sequence element
        self.output_net = nn.Sequential(
            nn.Linear(self.hparams.model_dim, self.hparams.model_dim),
            nn.LayerNorm(self.hparams.model_dim),
            nn.ReLU(inplace=True),
            nn.Dropout(self.hparams.dropout),
            nn.Linear(self.hparams.model_dim, self.hparams.num_classes)
        )

    def forward(self, x, mask=None, add_positional_encoding=True):
        """
        Inputs:
            x - Input features of shape [Batch, SeqLen, input_dim]
            mask - Mask to apply on the attention outputs (optional)
            add_positional_encoding - If True, we add the positional encoding to the input.
                                      Might not be desired for some tasks.
        """
        x = self.input_net(x)
        if add_positional_encoding:
            x = self.positional_encoding(x)
        x = self.transformer(x, mask=mask)
        x = self.output_net(x)
        return x

    @torch.no_grad()
    def get_attention_maps(self, x, mask=None, add_positional_encoding=True):
        """
        Function for extracting the attention matrices of the whole Transformer for a single batch.
        Input arguments same as the forward pass.
        """
        x = self.input_net(x)
        if add_positional_encoding:
            x = self.positional_encoding(x)
        attention_maps = self.transformer.get_attention_maps(x, mask=mask)
        return attention_maps

    def configure_optimizers(self):
        optimizer = optim.Adam(self.parameters(), lr=self.hparams.lr)

        # Apply lr scheduler per step
        lr_scheduler = CosineWarmupScheduler(optimizer,
                                             warmup=self.hparams.warmup,
                                             max_iters=self.hparams.max_iters)
        return [optimizer], [{'scheduler': lr_scheduler, 'interval': 'step'}]

    def training_step(self, batch, batch_idx):
        raise NotImplementedError

    def validation_step(self, batch, batch_idx):
        raise NotImplementedError

    def test_step(self, batch, batch_idx):
        raise NotImplementedError


from gettext import Catalog
import json
import pandas as pd
import yaml
import time

from py2neo import Node

from Database.connection import db_connect

counter = 1
class KnowledgeGraph:
    """
    Instance of knowledge graph, that is hosted on neo4j server. Contains functions for creation of the knowledge graph object
    """
    def __init__(self) -> None:
        try:
            file = open('Config/knowledge_graph.yaml', 'r')
            self.configurations = yaml.safe_load(file)
            file.close()
        except FileNotFoundError as e:
            print("knowledge graph config file not found. \n", e)
            exit(1)

        try:
            file = open('Database/queries.yaml')
            self.db_queries = yaml.safe_load(file)
            file.close()
        except FileNotFoundError as e:
            print("Database queries file not found. \n", e)
            exit(1)

        self.dataset = self.load_dataset(self.configurations['DATASET_PATH'])
        self.graph = db_connect()

        self.attribute_matching = {
            "category": ["category", "belongs_to_category"],
            "symptom": ["symptom", "has_symptom"],
            "prevent": ["prevent", "has_prevention"],
            "cause": ["cause", "has_cause"],
            "acompany": ["disease", "accompanies"],
            "cure_department": ["department", "cured_by_department"],
            "cure_way": ["cure_way", "cured_by"],
            "check": ["way_to_check", "required_check"],
            "recommand_drug": ["drug", "has_recommended_drug"],
            "common_drug": ["drug", "has_common_drug"],
            "do_eat": ["food", "do_eat"],
            "not_eat": ["food", "not_eat"],
            "recommand_eat": ["food", "recommended_eat"],
            "easy_get": ["prone_to", "prone_to"]
            }

    def load_dataset(self, file_path):
        """
        Loads json file into pandas dataframe
        :param file_path: Path of a json file (with indent = 4, and newlines after every record)
        :return: pandas dataframe for the loaded file
        """
        try:
            df = pd.read_json(file_path)
        except FileNotFoundError as e:
            print("Dataset cannot be found. \n", e)
            exit(1)
        return df

    def create_node(self, category, label, properties=None):
        label = str(label)
        label = label.lstrip().rstrip().lower()
        if category == "disease":
            if str(self.graph.run(f"""MATCH (x:disease) WHERE x.name="{label}" RETURN x.name""")) != "(No data)":
                return

            cost_money = "No Data"
            if properties['cost_money'] != None and properties['cost_money'] != []:
                if properties['cost_money'] != [] and len(properties['cost_money']) == 2:
                    cost_money = str(properties['cost_money'][0]) + " - " + str(properties['cost_money'][1])
                else:
                    cost_money =  str(properties['cost_money'][0])

            node = Node(
                category,
                name = label,
                description = str(properties['desc']).lower(),
                propogation_way = str(properties['get_way']).lower(),
                get_probability = str(properties['get_prob']).lower(),
                cure_last_time = str(properties['cure_lasttime']).lower(),
                cured_probabiltity = str(properties['cured_prob']).lower(),
                cost_money = cost_money
            )
        else:
            node = Node(
                category,
                name = label
            )
        self.graph.create(node)

    def delete_all_nodes(self):
        self.graph.run(self.db_queries['DELETE_ALL_NODES'])

    def get_unique(self, df_col):
        unique_list = list()
        for cell in df_col:
            for ele in cell:
                unique_list.append(ele)

        return unique_list

    def create_all_graph_nodes(self):
        def preprocess_labels(list_of_attribute):
            for i in range(len(list_of_attribute)):
                list_of_attribute[i] = list_of_attribute[i].lstrip().rstrip().lower()
            list_of_attribute = set(list_of_attribute)
            return list_of_attribute

        # Create all disease nodes
        for index, row, in self.dataset.iterrows():
            self.create_node(category="disease", label=row['name'], properties=row)

        # Get all unique properties
        disease_categories = self.get_unique(self.dataset.category)
        symptoms = self.get_unique(self.dataset.symptom)
        departments = self.get_unique(self.dataset.cure_department)
        cure_ways = self.get_unique(self.dataset.cure_way)
        ways_to_check = self.get_unique(self.dataset.check)
        drugs = self.get_unique(self.dataset.recommand_drug)
        drugs += self.get_unique(self.dataset.common_drug)
        food = self.get_unique(self.dataset.do_eat)
        food += self.get_unique(self.dataset.not_eat)
        food += self.get_unique(self.dataset.recommand_eat)
        prevent = self.get_unique(self.dataset.prevent)
        cause = self.get_unique(self.dataset.cause)
        easy_get = self.get_unique(self.dataset.easy_get)

        symptoms = preprocess_labels(symptoms)
        disease_categories = preprocess_labels(disease_categories)
        departments = preprocess_labels(departments)
        cure_ways = preprocess_labels(cure_ways)
        ways_to_check = preprocess_labels(ways_to_check)
        drugs = preprocess_labels(drugs)
        food = preprocess_labels(food)
        prevent = preprocess_labels(prevent)
        cause = preprocess_labels(cause)
        easy_get = preprocess_labels(easy_get)

        # Create Nodes for all unique properties
        for ele in disease_categories:
            self.create_node(category="disease category", label=ele)
        for ele in symptoms:
            self.create_node(category="symptom", label=ele)
        for ele in departments:
            self.create_node(category="department", label=ele)
        for ele in cure_ways:
            self.create_node(category="cure_way", label=ele)
        for ele in ways_to_check:
            self.create_node(category="way_to_check", label=ele)
        for ele in drugs:
            self.create_node(category="drug", label=ele)
        for ele in food:
            self.create_node(category="food", label=ele)
        for ele in prevent:
            self.create_node(category="prevention", label=ele)
        for ele in cause:
            self.create_node(category='cause', label=ele)
        for ele in easy_get:
            self.create_node(category="prone_to", label=ele)

    def create_relationship(self, start_node_type, end_node_type, start_node_name, end_node_name, relation_type):
        global counter
        print(counter)
        counter += 1
        start_node_name = str(start_node_name).lower().lstrip().rstrip()
        end_node_name = str(end_node_name).lower().lstrip().rstrip()
        end_node_name =  end_node_name.replace("\"", "")
        if relation_type == "acompanies":
            if str(self.graph.run(f"""MATCH (x:disease) WHERE x.name="{end_node_name}" RETURN x.name""")) != "(No data)":
                query = f"""
                    MATCH (a:{start_node_type}), (b:{end_node_type})
                    WHERE a.name = "{start_node_name}" AND b.name = "{end_node_name}"
                    MERGE (a)-[:{relation_type}]->(b)
                    """
                self.graph.run(query)
        else:
            query = f"""
            MATCH (a:{start_node_type}), (b:{end_node_type})
            WHERE a.name = "{start_node_name}" AND b.name = "{end_node_name}"
            MERGE (a)-[:{relation_type}]->(b)
            """
            x = self.graph.run(query)
            print(query)

    def create_all_graph_edges(self):
        for index, row in self.dataset.iterrows():
            disease = row['name']
            for att in self.attribute_matching.keys():
                prop = row[att]
                for node in prop:
                    self.create_relationship(
                        start_node_type="disease",
                        end_node_type=self.attribute_matching[att][0],
                        start_node_name=disease,
                        end_node_name=node,
                        relation_type=self.attribute_matching[att][1]
                    )

    def build_graph(self):
        print("BUILDING KNOWLEDGE GRAPH STARTED")

        # print("PREVIOUS DATA DELETION STARTED")
        # start = time.time()
        # self.delete_all_nodes()
        # end = time.time()
        # print("PREVIOUS DATA DELETION FINISHED, TIME TAKEN ", end-start, " seconds")

        print("GRAPH NODES CREATION STARTED")
        start = time.time()
        self.create_all_graph_nodes()
        end = time.time()
        print("GRAPH NODES CREATION FINISHED, TIME TAKEN ", end   -start, " seconds")

        print("GRAPH EDGE CREATION STARTED")
        start = time.time()
        self.create_all_graph_edges()
        end = time.time()
        print("GRAPH EDGE CREATION FINISHED, TIME TAKEN ", end-start, " seconds")
        print("KNOWLEDGE GRAPH CREATED")

# obj = KnowledgeGraph()
# obj.build_graph()