#!/usr/bin/env python3
# -*- coding: utf8 -*-

import time, os, sys, codecs, os.path
import html, random, string, hashlib, re, configparser
from io import StringIO
from docutils import core, nodes, writers
from docutils.parsers import rst
from docutils.transforms import Transform
from copy import copy
from math import log, ceil

class Prefs:
    base_category = 'Kwidgin'
    view_pdf_program = 'xdg-open'
    num_permutations = 5

## Docutils nodes and directives

def truefalse(argument):
    return rst.directives.choice(argument, ('false', 'true'))

class answer(nodes.list_item):
    def __init__(self, t_or_f):
        self.true_or_false = t_or_f
        nodes.list_item.__init__(self)

class question(nodes.compound): pass

class QuestionDirective(rst.Directive):
    has_content = True

    def run(self):
        self.assert_has_content()
        node = question()
        self.state.nested_parse(self.content, self.content_offset, node)
        return [node]

class AnswerDirective(rst.Directive):
    has_content = True
    required_arguments = 1

    def run(self):
        self.assert_has_content()
        args = self.arguments
        if args[0] not in ('true', 'false'):
            raise self.error("Argument must be `true' or `false'")
        node = answer(args[0] == 'true')
        self.state.nested_parse(self.content, self.content_offset, node)
        return [node]

class box(nodes.Inline, nodes.TextElement): pass
class frame(nodes.Inline, nodes.TextElement): pass

_reg = rst.directives.register_directive
_reg('question', QuestionDirective)
_reg('answer',   AnswerDirective)
_reg('pregunta', QuestionDirective)
_reg('resposta', AnswerDirective)
_reg = rst.roles.register_generic_role
_reg('box', box)
_reg('frame', frame)

## Transforms

class FlattenAnswers(Transform):
    default_priority = 900

    def apply(self):
        for node in self.document.traverse(answer):
            if len(node) == 1 and isinstance(node[0], nodes.paragraph):
                para = node[0]
                new_ans = answer(node.true_or_false)
                for item in para:
                    new_ans += item
                node.replace_self(new_ans)

class ShuffleAnswers(Transform):
    default_priority = 910

    def apply(self):
        # Collect answers
        answers = []
        for a in self.document.traverse(answer):
            answers.append(a)
        shuffled = copy(answers)
        random.shuffle(shuffled)
        for a, s in zip(answers, shuffled):
            a.replace_self(s)

## Translators

class BaseTranslator(nodes.NodeVisitor):
    def __init__(self, document):
        nodes.NodeVisitor.__init__(self, document)
        # self.settings = document.settings
        self.parts = {}
        self.parts['answers'] = []
        self.scratch = []
        self.title = self.last = None
        self.target = self.parts['question'] = []

    def put(self, s):
        self.target.append(s)

    def visit_document(self, node):
        self.parts['title'] = node.get('title', '')

    def depart_document(self, node):
        self.parts['question'] = u''.join(self.parts['question'])

    def visit_answer(self, node):
        self.last = self.target
        self.target = self.scratch

    def depart_answer(self, node):
        answ = (node.true_or_false, u''.join(self.scratch))
        self.parts['answers'].append(answ)
        self.scratch = []
        self.target = self.last

    def visit_comment(self, node):
        raise nodes.SkipNode

    def unknown_visit(self, node):
        print("WARNING: Visiting unknown node %s" % node.__class__.__name__)
        raise nodes.SkipNode

class MoodleXMLTranslator(BaseTranslator):

    def visit_Text(self, node):
        txt = node.astext().encode('utf-8')
        esc = html.escape(txt)
        self.put(esc.decode('utf-8'))

    def depart_Text(self, node): pass

    def visit_question(self, node): pass
    def depart_question(self, node): pass

    def visit_paragraph(self, node):  self.put('
')
    def depart_paragraph(self, node): self.put('
')

    def visit_system_message(self, node):
        self.put('System Message {')

    def depart_system_message(self, node):
        self.put('}')

    def visit_block_quote(self, node):
        self.put('
')

    def depart_block_quote(self, node):
        self.put('
\n')

    def visit_literal_block(self, node):
        style  = 'font-family: monospace;'
        style += 'font-size: 120%;'
        style += 'margin-left: 1.6em'
        self.put('
')

        text = node[0]
        text = string.replace(text, ' ', ' ')
        text = string.replace(text, '\n', '
')
        style  = 'background: rgb(128, 128, 128);'
        style += 'padding: .1em .3em;'
        style += 'color: white'
        patt = '\\1'
        text = re.sub(':box:`([^`]*)`', patt, text)
        self.put(text)
        self.put('
')
        raise nodes.SkipNode

    def visit_emphasis(self, node):  self.put('')
    def depart_emphasis(self, node): self.put('')

    def visit_literal(self, node):
        self.put('')

    def depart_literal(self, node):
        self.put('')

    enumerated_style = {
        'arabic': 'decimal',
        'loweralpha': 'lower-alpha',
        'upperalpha': 'upper-alpha',
        'lowerroman': 'lower-roman',
        'upperroman': 'upper-roman'
        }

    def visit_term(self, node):
        pass

    def depart_term(self, node):
        pass

    def visit_definition_list(self, node):
        self.put('
')

    def depart_definition_list(self, node):
        self.put('
')

    def visit_definition_list_item(self, node):
        pass

    def depart_definition_list_item(self, node):
        pass

    def visit_enumerated_list(self, node):
        typ = node['enumtype']
        self.put(u'
'
                           % self.enumerated_style[typ])

    def depart_enumerated_list(self, node):
        self.put(u'
')

    def visit_list_item(self, node):  self.put('
')
    def depart_list_item(self, node): self.put('
')

    common_style = [
        'font-family: monospace',
        'font-size: 120%',
        'padding: .1em .3em'
        ]

    def visit_box(self, node):
        style = copy(self.common_style)
        style += ['background: rgb(128, 128, 128)']
        style += ['color: white']
        self.put('' % '; '.join(style))

    def depart_box(self, node):
        self.put('')

    def visit_frame(self, node):
        style = copy(self.common_style)
        style += ['border: 1px solid black']
        self.put('' % '; '.join(style))

    def depart_frame(self, node):
        self.put('')

class HtmlTranslator(MoodleXMLTranslator):
    def visit_literal_block(self, node):
        self.put('
')
        text = node[0]
        text = string.replace(text, ' ', ' ')
        text = string.replace(text, '\n', '
')
        patt = '\\1'
        text = re.sub(':box:`([^`]*)`', patt, text)
        self.put(text)
        self.put('
')
        raise nodes.SkipNode

    def visit_literal(self, node):
        self.put('<tt>')

    def depart_literal(self, node):
        self.put('</tt>')

    enumerated_style = {
        'arabic': 'decimal',
        'loweralpha': 'lower-alpha',
        'upperalpha': 'upper-alpha',
        'lowerroman': 'lower-roman',
        'upperroman': 'upper-roman'
        }

    def visit_box(self, node):
        self.put(u'')

    def depart_box(self, node):
        self.put(u'')

    def visit_frame(self, node):
        self.put(u'')

    def depart_frame(self, node):
        self.put(u'')

class LaTeXTranslator(BaseTranslator):

    def visit_question(self, node):
        self.put("\n\n\\begin{pregunta}\n")

    def depart_question(self, node):
        self.put("\\end{pregunta}\n")

    def visit_Text(self, node):
        self.put(node.astext())

    def depart_Text(self, node): pass

    def visit_paragraph(self, node): pass
    def depart_paragraph(self, node):
        self.put('\n\n')

    def visit_literal_block(self, node):
        self.put('\\vspace{-.5em}\n\\begin{Code}\n')
        text = node[0]
        text = re.sub(':box:`([^`]*)`', '\\wog#\\1$', text)
        self.put(text)
        self.put('\n\\end{Code}\n\\vspace{-.7em}\n')
        raise nodes.SkipNode

    # def depart_literal_block(self, node):
    #    self.put('\n\\end{Verbatim}\n\\vspace{-.4em}')

    def visit_emphasis(self, node):
        self.put('\\emph{')

    def depart_emphasis(self, node):
        self.put('}')

    def print_literal(self, node):
        delim = '|'
        if '|' in node.astext(): delim = '@'
        self.put('\\Verb' + delim)
        text = node.astext()
        text = text.replace('&', '\\&')
        text = text.replace('_', '\\_')
        self.put(text)
        self.put(delim)

    def visit_literal(self, node):
        self.print_literal(node)
        raise nodes.SkipNode

    def visit_answer(self, node):
        BaseTranslator.visit_answer(self, node)
        if node.true_or_false:
            self.put('\\vertadera{')
        else:
            self.put('\\falsa{')

    def depart_answer(self, node):
        self.put('}\n')
        BaseTranslator.depart_answer(self, node)

    enumerated_style = {
        'arabic':     '1',
        'loweralpha': 'a',
        'upperalpha': 'A',
        'lowerroman': 'i',
        'upperroman': 'I'
        }

    def visit_enumerated_list(self, node):
        typ = node['enumtype']
        self.put('\\begin{enumerate}[%s.]\n'
                           % self.enumerated_style[typ])
        self.put('\\addtolength{\\itemsep}{-\parskip}\n')
        self.put('\\setlength{\\itemindent}{1em}\n')

    def depart_enumerated_list(self, node):
        self.put('\\end{enumerate}\n')

    def visit_list_item(self, node):
        self.put('\item ')

    def depart_list_item(self, node): pass

    def visit_box(self, node):
        self.put('\\wog{')
        self.print_literal(node[0])
        self.put('}')
        raise nodes.SkipNode

    def visit_frame(self, node):
        self.put('\\wox{')
        self.print_literal(node[0])
        self.put('}')
        raise nodes.SkipNode

## Writers

class QuestionWriter(writers.Writer):
    translator_class = None
    transforms = []

    def __init__(self):
        writers.Writer.__init__(self)
        self.translator = None

    def get_transforms(self):
        return writers.Writer.get_transforms(self) + self.transforms

    def translate(self):
        self.translator = self.translator_class(self.document)
        self.document.walkabout(self.translator)
        self.output = self.parts

    def assemble_parts(self):
        writers.Writer.assemble_parts(self)
        self.parts = self.translator.parts

class MoodleXMLWriter(QuestionWriter):
    translator_class = MoodleXMLTranslator
    transforms = [FlattenAnswers]

class HtmlWriter(QuestionWriter):
    translator_class = HtmlTranslator
    transforms = [FlattenAnswers]

class LaTeXWriter(QuestionWriter):
    translator_class = LaTeXTranslator
    transforms = [ShuffleAnswers, FlattenAnswers]

## MoodleXML publisher

def _file2string(filename):
    f = codecs.open(filename, 'r', 'utf-8')
    text = f.read()
    f.close()
    return text

def question_to_xml(out, q):
    out.write(u'<question type="multichoice">')
    out.write(u'<name><text>%s</text></name>' % q['title'])
    out.write(u'<questiontext format="html">')
    out.write(u'<text><![CDATA[%s]]></text>' % q['question'])
    out.write(u'</questiontext>')
    out.write(u'<defaultgrade>1</defaultgrade>')
    out.write(u'<shuffleanswers>1</shuffleanswers>')
    out.write(u'<answernumbering>none</answernumbering>')
    for a in q['answers']:
        fr = 0
        if a[0]: fr = 100
        out.write(u'<answer fraction="%d">' % fr)
        out.write(u'<text><![CDATA[%s]]></text>' % a[1])
        out.write(u'</answer>')
    out.write(u'</question>')

def category_to_xml(out, name, permut=''):
    out.write(u'<question type="category">')
    out.write(u'<category><text>%s/%s%s</text></category>'
              % (Prefs.base_category, name.decode('utf-8'), permut))
    out.write(u'</question>')

def directory_to_xml(out, topdir):
   out.write(u'<quiz>')
   for root, dirs, files in os.walk(topdir):
      count = 0
      t_rsts, rsts = [], []
      relp = os.path.relpath(root, topdir)
      absp = os.path.abspath(root)
      for f in files:
         prefix, ext = os.path.splitext(f)
         if ext == ".rst":
            print(os.path.join(relp, f))
            rsts.append(os.path.join(absp, f))
         elif ext == '.trst':
            print(os.path.join(relp, f))
            t_rsts.append(os.path.join(absp, f))
         count += 1

      if count > 0 and relp != ".":
         category_to_xml(out, relp)
      for r in rsts:
         txt = _file2string(r)
         try:
            dic = core.publish_parts(txt, writer = MoodleXMLWriter())
            question_to_xml(out, dic)
         except Exception as e:
            print(txt)
            raise

      for t in t_rsts:
         path = os.path.relpath(t, topdir)
         prefix, _ = os.path.splitext(path)
         category_to_xml(out, prefix, ' [PERMUT]')
         templ = string.Template(_file2string(t).encode('utf-8'),
                                 os.path.basename(t))
         for i in range(Prefs.num_permutations):
            # Add to python path the directory of the template
            sys.path.append(os.path.dirname(t))
            text = templ.generate()
            sys.path.pop()
            #
            dic = core.publish_parts(text, writer = MoodleXMLWriter())
            patt = ' [perm. %%0%dd]' % int(ceil(log(Prefs.num_permutations, 10)))
            dic['title'] += patt % i
            question_to_xml(out, dic)
   out.write(u'</quiz>')

## Genexam (LaTeX publisher)

def render(text, writer):
   w = None
   if writer == "latex":
      w = LaTeXWriter()
   elif writer == "moodlexml":
      w = MoodleXMLWriter()
   elif writer == "html":
      w = HtmlWriter()
   return core.publish_parts(text, writer = w)

def generate_exam(permutation, config, templ_list, basename, num_columns):
   cfg = {}
   for x in ('assignatura', 'especialitat', 'temps', 'titol'):
       cfg[x] = config.get('examen', x)

   solutions = ""
   indices = [i for i in range(len(templ_list))]
   random.shuffle(indices)
   buf = StringIO()

   buf.write("\\begin{document}")
   buf.write("\\Permutacio{%d}" % permutation)
   buf.write("\\Assignatura{%s}" % cfg['assignatura'])
   buf.write("\\Especialitat{%s}" % cfg['especialitat'])
   buf.write("\\TempsMaxim{%s}" % cfg['temps'])
   buf.write("\\Titol{%s}" % cfg['titol'])
   buf.write("\\NumPreguntes{%d}\n" % len(templ_list))
   buf.write("\\capsalera\n\n")
   buf.write("\\begin{multicols*}{%d}\n" % num_columns)
   for i in indices:
      t = templ_list[i]
      while isinstance(t, list):
         if len(t) == 0:
            raise RuntimeError("No templates in %d, \ntemplate_list=%s" % (i, templ_list.__str__()))
         t = random.choice(t)
      # print permutation, t.name
      # Add to python path the directory of the template
      sys.path.append(os.path.dirname(t.name))
      q = core.publish_parts(t.generate(), writer = LaTeXWriter())
      sys.path.pop()
      #
      buf.write(q['question'])
      random.shuffle(q['answers'])
      for a in q['answers']:
         buf.write(a[1])
      t_or_f = [a[0] for a in q['answers']]
      solutions += ['a', 'b', 'c', 'd', 'e', 'f'][t_or_f.index(True)]
   # print solutions
   buf.write("\\end{multicols*}\n")
   buf.write("\\end{document}\n")
   with codecs.open('tex/' + basename + 'n.tex', 'w', 'utf-8') as file:
      file.write("\\documentclass{test-fi}\n")
      file.write(buf.getvalue())
   with codecs.open('tex/' + basename + 's.tex', 'w', 'utf-8') as file:
      file.write("\\documentclass{test-fi-solucio}\n")
      file.write(buf.getvalue())
   return solutions, indices

Makefile_text = """
PDFS=${pdflist}

all: alln.pdf alls.pdf
\t@rm -f *.aux *.log

alln.pdf: $${PDFS}
\t@${alln_command}

alls.pdf: $${PDFS}
\t@${alls_command}

%.pdf: tex/%.tex
\t@xelatex -halt-on-error $$< 2> /dev/null > /dev/null

view: all
\txdg-open alls.pdf

clean:
\t@rm -f $${PDFS} *.aux *.log local.cls
"""

Classfile_text = """\\NeedsTeXFormat{LaTeX2e}[1995/12/01]
\\ProvidesClass{local}
\\LoadClass{test-fi}
"""

Classfile_solucio_text = """\\NeedsTeXFormat{LaTeX2e}[1995/12/01]
\\ProvidesClass{local}
\\LoadClass{test-fi-solucio}
"""

def get_template_tree(question_list):
    """ Substitute directories with all the files within them """
    result = []
    for path in question_list:
        if os.path.isdir(path):
            templ_list = get_template_tree([os.path.join(path, f) for f in os.listdir(path)])
            if len(templ_list) > 0:
               result.append(templ_list)
        else:
            _, ext = os.path.splitext(path)
            if ext in ['.rst', '.trst']:
                result.append(path)
            elif ext in ['.py', '.pyc']:
               pass # Nothing to do, this file probably is imported in the template
            else:
                print("Ignoring file %s" % path)
    return result

def templatize(x):
   if isinstance(x, list):
      result = []
      for item in x:
         result.append(templatize(item))
      return result
   else:
      fname = x.encode('utf-8')
      text = _file2string(fname).encode('utf-8')
      return template.Template(text, fname)

def print_tree(x, level = 0):
   if isinstance(x, list):
      print(" "*level + "::")
      for item in x:
         print_tree(item, level + 3)
   else:
      print(" "*level + x)

def generation_date():
   t = time.localtime()
   parts = (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
   return "%04d%02d%02d%02d%02d%02d" % parts

def generate_exam_dir(config, output_dir, num_permutations, num_columns):
    lastdir = os.getcwd()

    # Create directories
    if not os.path.isdir(output_dir): os.mkdir(output_dir)
    os.chdir(output_dir)
    if not os.path.isdir('tex'): os.mkdir('tex')

    # Read questions
    root = os.path.abspath(config.get('preguntes', 'root'))
    question_list = [os.path.join(root, f) for f in config.get('preguntes', 'list').split('\n')]
    file_tree = get_template_tree(question_list)

    # Read templates
    templates = templatize(file_tree)

    # Write each exam
    pdflist = ""
    with open('solutions.csv', 'w') as o:
        for n in range(num_permutations):
            prefix = '%04d' % n
            pdflist += prefix + 'n.pdf '
            pdflist += prefix + 's.pdf '
            solutions, indices = generate_exam(n, config, templates, prefix, num_columns)
            o.write("%d;%s\n" % (n, solutions))

    # Write metadata
    titol = config.get('examen', 'titol')
    assignatura = config.get('examen', 'assignatura')
    especialitat = config.get('examen', 'especialitat')
    temps = config.get('examen', 'temps')
    # data = config.get('examen', 'data')
    with codecs.open('metadata.csv', 'w', 'utf-8') as o:
        o.write('Titol;%s\n' % titol)
        o.write('Assignatura;%s\n' % assignatura)
        o.write('Especialitat;%s\n' % especialitat)
        o.write('Temps;%s\n' % temps)
        o.write('GenDate;%s\n' % generation_date())
        o.write('NumPermutations;%d\n' % num_permutations)

    # Write Makefile
    if sys.platform == "darwin":
        alls_command = 'pdfjoin -o alls.pdf ????s.pdf'
        alln_command = 'pdfjoin -o alln.pdf ????n.pdf'
    else:
        alls_command = 'pdftk ????s.pdf cat output alls.pdf'
        alln_command = 'pdftk ????n.pdf cat output alln.pdf'

    t = string.Template(Makefile_text)
    with open('Makefile', 'w') as file:
        file.write(t.substitute(
           pdflist=pdflist,
           alls_command=alls_command,
           alln_command=alln_command,
        ))

    with open('normal.cls', 'w') as file:
        file.write(Classfile_text)

    with open('showsol.cls', 'w') as file:
        file.write(Classfile_solucio_text)

    # Save the configuration file in the same folder
    with codecs.open('config.ini', 'w', 'utf-8') as file:
        config.write(file)

    print("Changing to " + lastdir)
    os.chdir(lastdir)


import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.stem import PorterStemmer

nltk.download('stopwords')

def converter_valor(valor_puro, moeda):
    cotacao = 1

    if moeda == "DOLAR":
        cotacao = 4.78
    elif moeda == "EURO":
        cotacao = 5.22

    return valor_puro * cotacao

def unirDemandaComUsuario(demandas, usuarios):
    tipoSolicitante = []
    cargoSolicitante = []
    departamentoSolicitante = []
    nomeSolicitante = []
    setorSolicitante = []

    for index, demanda in demandas.iterrows():
        usuario = usuarios.loc[usuarios['id_usuario'] == demanda.id_usuario]
        index = usuario.index[0]

        tipoSolicitante.append(usuarios.at[index, "dtype"])
        cargoSolicitante.append(usuario.at[index, "cargo"])
        departamentoSolicitante.append(usuario.at[index, "departamento"])
        nomeSolicitante.append(usuario.at[index, "nome_usuario"])
        setorSolicitante.append(usuario.at[index, "setor"])

    demandas["tipo_solicitante"] = tipoSolicitante
    demandas["cargo_solicitante"] = cargoSolicitante
    demandas["departamento_solicitante"] = departamentoSolicitante
    demandas["nome_solicitante"] = nomeSolicitante
    demandas["setor_solicitante"] = setorSolicitante

    demandas.drop(columns=["id_usuario"], inplace=True)

    return demandas

def unirDemandaComBeneficio(demandas, beneficiosDemanda):
    qtd_beneficio_real = []
    qtd_beneficio_potencial = []
    qtd_beneficio_qualitativo = []
    valor_total_beneficios_reais = []
    valor_total_beneficios_potenciais = []
    descricao_beneficios = []

    for index, demanda in demandas.iterrows():
        beneficios = beneficiosDemanda.loc[beneficiosDemanda.id_demanda == demanda.id_demanda]
        qtd_real = 0
        qtd_potencial = 0
        qtd_qualitativo = 0
        valor_total_real = 0.0
        valor_total_potencial = 0.0
        descricao_beneficios_demanda = ""

        for index, beneficio in beneficios.iterrows():
            tipo = beneficio.tipo_beneficio

            if tipo == "QUALITATIVO":
                qtd_qualitativo += 1
            elif tipo == "REAL":
                if np.isnan(beneficio.valor):
                    continue

                qtd_real += 1
                valor_total_real += converter_valor(beneficio.valor, beneficio.moeda)
            elif tipo == "POTENCIAL":
                if np.isnan(beneficio.valor):
                    continue

                qtd_potencial += 1
                valor_total_potencial += converter_valor(beneficio.valor, beneficio.moeda)

            descricao_beneficios_demanda += " " + beneficio.descricao

        qtd_beneficio_real.append(qtd_real)
        qtd_beneficio_potencial.append(qtd_potencial)
        qtd_beneficio_qualitativo.append(qtd_qualitativo)
        valor_total_beneficios_reais.append(valor_total_real)
        valor_total_beneficios_potenciais.append(valor_total_potencial)
        descricao_beneficios.append(descricao_beneficios_demanda)

    demandas["qtd_beneficio_real"] = qtd_beneficio_real
    demandas["qtd_beneficio_potencial"] = qtd_beneficio_potencial
    demandas["qtd_beneficio_qualitativo"] = qtd_beneficio_qualitativo
    demandas["valor_total_beneficios_reais (BRL)"] = valor_total_beneficios_reais
    demandas["valor_total_beneficios_potenciais (BRL)"] = valor_total_beneficios_potenciais
    demandas["descricao_beneficios"] = descricao_beneficios

    return demandas

def unirDemandaComCCs(demandas, CCs, CCsDemanda):
    quantidade_CC_demanda = []
    nomes_CC_demanda = []

    for index, demanda in demandas.iterrows():
        centros_custo_demanda = CCsDemanda[CCsDemanda.id_demanda == demanda.id_demanda]
        quantidade_CCs = 0
        nomes_CC = ""

        for index, centro_custo in centros_custo_demanda.iterrows():
            quantidade_CCs += 1
            nome = CCs.loc[CCs.id_centrocusto == centro_custo.id_centrocusto]
            nomes_CC += " " + nome.at[nome.index[0], "nome_centro_custo"]

        quantidade_CC_demanda.append(quantidade_CCs)
        nomes_CC_demanda.append(nomes_CC)

    demandas["quantidade_CC"] = quantidade_CC_demanda
    demandas["nomes_CC"] = nomes_CC_demanda

    return demandas

def transformarBancoToDataFrame(demandas, usuarios, beneficios, CCs, CCsDemanda):
    df_demandas = pd.DataFrame(demandas)
    df_usuarios = pd.DataFrame(usuarios)
    df_beneficios = pd.DataFrame(beneficios)
    df_CCs = pd.DataFrame(CCs)
    df_CCsDemanda = pd.DataFrame(CCsDemanda)

    df_demandas_transformadas = unirDemandaComUsuario(df_demandas, df_usuarios)
    df_demandas_transformadas = unirDemandaComBeneficio(df_demandas_transformadas, df_beneficios)
    df_demandas_transformadas = unirDemandaComCCs(df_demandas_transformadas, df_CCs, df_CCsDemanda)

    return df_demandas_transformadas

def adicionarNovaColuna(df_alvo, nome_coluna, df_info):
    stemmer = PorterStemmer()
    stop_words = set(stopwords.words('portuguese'))

    palavras = df_info[nome_coluna].values.astype('U').tolist()
    palavras = [palavra.lower() for palavra in palavras]
    palavras = [palavra for palavra in palavras if palavra not in stop_words]
    palavras = [stemmer.stem(palavra) for palavra in palavras]

    cvec = CountVectorizer().fit(palavras)
    df_coluna = pd.DataFrame(cvec.transform(palavras).todense(), columns=cvec.get_feature_names_out())

    return df_coluna

def transformarDataFrameToVetorizada(df_demanda):
    df_preparacao_NLP = pd.DataFrame()
    nome_colunas_desejadas = [
        "frequencia_uso", "objetivo", "situacao_atual","titulo_demanda","tipo_solicitante","cargo_solicitante",
        "departamento_solicitante","nome_solicitante", "setor_solicitante","descricao_beneficios","nomes_CC"
    ]

    for nome_coluna in df_demanda.columns:
        if nome_coluna in nome_colunas_desejadas:
            df_coluna_nova = adicionarNovaColuna(df_preparacao_NLP, nome_coluna, df_demanda)
            df_preparacao_NLP = pd.concat([df_preparacao_NLP, df_coluna_nova], axis=1)

    df_preparacao_nao_NLP = df_demanda.drop(columns=nome_colunas_desejadas, axis=1)

    df_preparacao_nao_NLP_normalizada=(df_preparacao_nao_NLP-df_preparacao_nao_NLP.min())/(df_preparacao_nao_NLP.max()-df_preparacao_nao_NLP.min())
    df_preparacao_nao_NLP_normalizada.drop("id_demanda", axis=1, inplace=True)
    df_preparacao_nao_NLP = pd.concat([df_preparacao_nao_NLP["id_demanda"], df_preparacao_nao_NLP_normalizada], axis=1)

    df_preparacao_NLP.reset_index(inplace=True, drop=True)
    df_preparacao_nao_NLP.reset_index(inplace=True, drop=True)

    df_todos_dados = pd.concat([df_preparacao_NLP, df_preparacao_nao_NLP], axis=1)

    return df_todos_dados

def transformarDicionarioToDataFrame(demanda_dict, usuarios_atualizados, CCs_atualizados):
    # separando as informações específicas da demanda em objetos
    demanda = {
        "id_demanda": -1,
        "frequencia_uso": demanda_dict["frequenciaUso"],
        "objetivo": demanda_dict["objetivo"],
        "situacao_atual": demanda_dict["situacaoAtual"],
        "titulo_demanda": demanda_dict["tituloDemanda"],
    }
    CCsDemanda = demanda_dict["centroCustoDemanda"]
    usuario = demanda_dict["usuario"]

    # adicionando as informações de usuário na demanda
    df_uma_demanda = pd.DataFrame(demanda, index=[0])

    usuario = usuarios_atualizados.loc[usuarios_atualizados['id_usuario'] == usuario["idUsuario"]]
    index = usuario.index[0]
    df_uma_demanda.loc[0,"tipo_solicitante"] = usuarios_atualizados.at[index, "dtype"]
    df_uma_demanda.loc[0,"cargo_solicitante"] = usuarios_atualizados.at[index, "cargo"]
    df_uma_demanda.loc[0,"departamento_solicitante"] = usuarios_atualizados.at[index, "departamento"]
    df_uma_demanda.loc[0,"nome_solicitante"] = usuarios_atualizados.at[index, "nome_usuario"]
    df_uma_demanda.loc[0,"setor_solicitante"] = usuarios_atualizados.at[index, "setor"]

    #adicionando as informacoes dos beneficios na demanda
    qtd_real = 0
    qtd_potencial = 0
    qtd_qualitativo = 0
    valor_total_real = 0.0
    valor_total_potencial = 0.0
    descricao_beneficios_demanda = ""

    if "beneficiosDemanda" in demanda_dict:
        beneficios = demanda_dict["beneficiosDemanda"]
        df_beneficios = pd.DataFrame(beneficios)

        for index, beneficio in df_beneficios.iterrows():
            tipo = beneficio.tipoBeneficio

            if tipo == "QUALITATIVO":
                qtd_qualitativo += 1
            elif tipo == "REAL":
                if np.isnan(beneficio.valor):
                    continue

                qtd_real += 1
                valor_total_real += converter_valor(beneficio.valor, beneficio.moeda)
            elif tipo == "POTENCIAL":
                if np.isnan(beneficio.valor):
                    continue

                qtd_potencial += 1
                valor_total_potencial += converter_valor(beneficio.valor, beneficio.moeda)

            descricao_beneficios_demanda += " " + beneficio.descricao

    df_uma_demanda.loc[0,"qtd_beneficio_real"] = qtd_real
    df_uma_demanda.loc[0,"qtd_beneficio_potencial"] = qtd_potencial
    df_uma_demanda.loc[0,"qtd_beneficio_qualitativo"] = qtd_qualitativo
    df_uma_demanda.loc[0,"valor_total_beneficios_reais (BRL)"] = valor_total_real
    df_uma_demanda.loc[0,"valor_total_beneficios_potenciais (BRL)"] = valor_total_potencial
    df_uma_demanda.loc[0,"descricao_beneficios"] = descricao_beneficios_demanda

    # adicionando as informações de centros de custo na demanda
    centros_custo_demanda = pd.DataFrame(CCsDemanda)
    quantidade_CCs = 0
    nomes_CC = ""

    for index, centro_custo in centros_custo_demanda.iterrows():
        quantidade_CCs += 1
        nome = CCs_atualizados.loc[CCs_atualizados.id_centrocusto == centro_custo.idCentroCusto]
        nomes_CC += " " + nome.at[nome.index[0], "nome_centro_custo"]

    df_uma_demanda.loc[0,"quantidade_CC"] = quantidade_CCs
    df_uma_demanda.loc[0,"nomes_CC"] = nomes_CC

    return df_uma_demanda;

def checarSimilaridade(df_demanda, demanda_nova, usuarios_atualizados, CCs_atualizados):
    df_uma_demanda_nova = transformarDicionarioToDataFrame(demanda_nova, usuarios_atualizados, CCs_atualizados)
    df_todas_demandas = pd.concat([df_demanda, df_uma_demanda_nova])
    df_todas_vetorizadas = transformarDataFrameToVetorizada(df_todas_demandas)

    similarity = cosine_similarity(df_todas_vetorizadas.drop("id_demanda", axis=1))
    indice_similaridade = 0.65
    valores_similaridade_ultima_demanda = similarity[-1]
    id_demandas_similares = []

    print(valores_similaridade_ultima_demanda)

    for i in range(len(valores_similaridade_ultima_demanda)):
        valor = valores_similaridade_ultima_demanda[i]
        if valor > indice_similaridade and i != len(valores_similaridade_ultima_demanda) - 1:
            id_demandas_similares.append(int(df_todas_vetorizadas.iloc[i]["id_demanda"]))

    return id_demandas_similares


from __future__ import division # for proper float division

import os
import sys
import math
import time
import types
import functools
import random
import numpy as np
from ddapp import ik
from ddapp import ikconstraints
from ddapp import ikconstraintencoder
import drc as lcmdrc
import json
from ddapp.utime import getUtime
from ddapp import lcmUtils

import ipab

class PlannerPublisher(object):

  def __init__(self, ikPlanner, affordanceMan):
    self.ikPlanner = ikPlanner
    self.affordanceManager = affordanceMan
    self.poses={}

  def setupMessage(self, constraints, endPoseName="", nominalPoseName="", seedPoseName="", additionalTimeSamples=None):
    poses = ikconstraintencoder.getPlanPoses(constraints, self.ikPlanner)
    poses.update(self.poses)
    msg = ipab.exotica_planner_request_t()
    msg.utime = getUtime()
    msg.poses = json.dumps(poses)
    msg.constraints = ikconstraintencoder.encodeConstraints(constraints)
    msg.seed_pose = seedPoseName
    msg.nominal_pose = nominalPoseName
    msg.end_pose = endPoseName
    msg.joint_names = json.dumps(list(self.ikPlanner.jointController.jointNames))
    msg.affordances = self.processAffordances()
    opt=ikplanner.getIkOptions()._properties
    if additionalTimeSamples:
      opt.update({'timeSamples':additionalTimeSamples})
    msg.options = json.dumps(opt)
    return msg

  def processIK(self, constraints, endPoseName="", nominalPoseName="", seedPoseName="", additionalTimeSamples=None):
    listener = self.ikPlanner.getManipIKListener()
    msg = self.setupMessage(constraints, endPoseName, nominalPoseName, seedPoseName, additionalTimeSamples)
    lcmUtils.publish('IK_REQUEST', msg)
    ikplan = listener.waitForResponse(timeout=12000)
    listener.finish()

    endPose = [0] * self.ikPlanner.jointController.numberOfJoints
    if ikplan.num_states>0:
      endPose[len(endPose)-len(ikplan.plan[ikplan.num_states-1].joint_position):] = ikplan.plan[ikplan.num_states-1].joint_position
      info=ikplan.plan_info[ikplan.num_states-1]
    else:
      info = -1
    self.ikPlanner.ikServer.infoFunc(info)
    return endPose, info

  def processTraj(self, constraints, endPoseName="", nominalPoseName="", seedPoseName="", additionalTimeSamples=None):
    # Temporary fix / HACK / TODO (should be done in exotica_json)
    largestTspan = [0, 0]
    for constraintIndex, _ in enumerate(constraints):
      # Get tspan extend to normalise time-span
      if np.isfinite(constraints[constraintIndex].tspan[0]) and np.isfinite(constraints[constraintIndex].tspan[1]):
        largestTspan[0] = constraints[constraintIndex].tspan[0] if (constraints[constraintIndex].tspan[0] < largestTspan[0]) else largestTspan[0]
        largestTspan[1] = constraints[constraintIndex].tspan[1] if (constraints[constraintIndex].tspan[1] > largestTspan[1]) else largestTspan[1]

    # Temporary fix / HACK/ TODO to normalise time spans
    for constraintIndex, _ in enumerate(constraints):
      if np.isfinite(constraints[constraintIndex].tspan[0]) and np.isfinite(constraints[constraintIndex].tspan[1]):
        if largestTspan[1] != 0:
          constraints[constraintIndex].tspan[0] = constraints[constraintIndex].tspan[0] / largestTspan[1]
          constraints[constraintIndex].tspan[1] = constraints[constraintIndex].tspan[1] / largestTspan[1]

    listener = self.ikPlanner.getManipPlanListener()
    msg = self.setupMessage(constraints, endPoseName, nominalPoseName, seedPoseName, additionalTimeSamples)
    lcmUtils.publish('PLANNER_REQUEST', msg)
    lastManipPlan = listener.waitForResponse(timeout=20000)
    listener.finish()
    if lastManipPlan:
      # HACK: need to multiply by original trajectory length again (the one in the plan is planning and not real time), otherwise jumps to real hardware
      for state in lastManipPlan.plan:
        state.utime = state.utime * 50

    self.ikPlanner.ikServer.infoFunc(lastManipPlan.plan_info[0])
    return lastManipPlan, lastManipPlan.plan_info[0]

  def processAddPose(self, pose, poseName):
    self.poses[poseName]=list(pose);

  def processAffordances(self):
      affs = self.affordanceManager.getCollisionAffordances()
      s='['
      first=True
      for aff in affs:
        des=aff.getDescription()
        classname=des['classname'];
        if first:
          s+='{'
        else:
          s+='\n,{'
        first=False
        s+='"classname":"'+classname+'"'
        s+=',"uuid":"'+des['uuid']+'"'
        s+=',"pose": {"position":{"__ndarray__":'+repr(des['pose'][0].tolist())+'},"quaternion":{"__ndarray__":'+repr(des['pose'][1].tolist())+'}}'
        if classname=='MeshAffordanceItem':
          s+=',"filename":"'+aff.getMeshManager().getFilesystemFilename(des['Filename'])+'"'
        if classname=='SphereAffordanceItem':
          s+=',"radius":'+repr(des['Radius'])
        if classname=='CylinderAffordanceItem' or classname=='CapsuleAffordanceItem':
          s+=',"radius":'+repr(des['Radius'])
          s+=',"length":'+repr(des['Length'])
        if classname=='BoxAffordanceItem':
          s+=',"dimensions":'+repr(des['Dimensions'])
        if classname=='CapsuleRingAffordanceItem':
          s+=',"radius":'+repr(des['Radius'])
          s+=',"tube_radius":'+repr(des['Tube Radius'])
          s+=',"segments":'+repr(des['Segments'])
        s+='}'
      s=s+']'
      return s

import ikplanner


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

# In[1]:

import time
import os
import numpy as np
import torch
import torchvision.transforms as tv
from torchvision.utils import make_grid
from PIL import Image
from torchvision.transforms import Compose
import logging
import matplotlib.pyplot as plt
import pandas as pd
import glob

'''Inference workflow
 model = load_model(model_path) ->
 show_img_with_pred(image_path, model, show_results=1) | batch_prediction(images_folder_path, model, save_path='results.csv') '''

mylogs = logging.getLogger()
mylogs.setLevel(logging.INFO)
# Logging to file
file = logging.FileHandler("inference.log", mode='w')
file.setLevel(logging.INFO)
fileformat = logging.Formatter("%(asctime)s:%(levelname)s:%(message)s",datefmt="%H:%M:%S")
file.setFormatter(fileformat)
mylogs.addHandler(file)
# Logging to console
stream = logging.StreamHandler()
stream.setLevel(logging.INFO)
mylogs.addHandler(stream)
mylogs.info("Inference")

device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
mylogs.info(f"Device is: {str(device)}")

def load_model(model_path):
    ''' Loads a model and its state dict. Accepts path to the model, returns the model. Default cnn type is resnet18 '''
    saved_model = torch.load(f'{model_path}')
    model_name  = saved_model['model_name']
    categories = saved_model['сategories']
    mylogs.info("Model: " + model_name)

    import resnet
    if model_name == 'ResNet18':
            model = resnet.ResNet18()
    elif model_name == 'ResNet34':
            model = resnet.ResNet34()
    elif model_name == 'ResNet50':
            model = resnet.ResNet50()
    elif model_name == 'ResNet101':
            model = resnet.ResNet101()
    elif model_name == 'ResNet152':
            model = resnet.ResNet152()
    else:
            model = resnet.ResNet18()
    model.load_state_dict(torch.load(model_path)['model_state_dict'])
    model.eval()

    return model, categories

def transform():
    return tv.Compose([
        tv.ToTensor(),
        tv.Normalize((0, 0, 0),(1, 1, 1))
    ])

def image_loader(image_path):
    '''loads image,transforms it and returns tensor'''
    img = Image.open(image_path)
    img = img.resize((224, 224))
    img = transform()(img)
    #As torch models expects a batch, this image should be turned into a batch with 1 image
    img  = img.unsqueeze(0)
    return img.cpu()

def show_img_with_pred(image_path, model,categories, show_results):
    ''' Predicts one image, returns prediction '''
    img = image_loader(image_path)
    img = img.to('cpu')
    model.to('cpu')
    with torch.no_grad():
        prediction = float(model(img))
    if show_results:
        img = img.to('cpu')
        figure, ax = plt.subplots(figsize=(6,6))
        plt.title(categories[0] if prediction <= 0.5 else categories[1], color= 'black')
        plt.imshow(make_grid(img,1).permute(1,2,0))
        ax.text(3, 8, (round(prediction,3)), style='italic',
        bbox={'facecolor': 'white', 'alpha': 0.5, 'pad': 10})
        plt.show()
    return prediction

def batch_prediction(images_folder_path, model, model_categories, show_results, save_path=None):
    ''' Make an inference on the images in the folder,can save results as a .csv, returns pandas dataframe'''
    imgs_path_list = glob.glob(f'{images_folder_path}\*')
    mylogs.info(f"Inference started. \n {len(imgs_path_list)} images to predict")
    predictions = []
    categories = []
    names = []
    start_time = time.time()
    for image_path in imgs_path_list:
        names.append(os.path.split(image_path)[1])
        prediction = show_img_with_pred(image_path, model,categories,show_results=0)
        category = (model_categories[0] if prediction <= 0.5 else model_categories[1])
        predictions.append(prediction)
        categories.append(category)

    df = pd.DataFrame({'Image' : pd.Series(names), 'Predictions' : pd.Series(predictions), 'Categories' : pd.Series(categories)})
    end_time = time.time()
    total_time = int(end_time - start_time)
    mylogs.info(f'Inference finished. Elapsed time: {total_time }s')
    if save_path:
        df.to_csv(save_path)
        mylogs.info('Results saved')
    if show_results:
        df.hist(column = "Predictions")
        plt.show()
    return df


from django import http
from django.db.models import Q
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from . import models

from linebot import LineBotApi, WebhookParser
from linebot.models import (
    Message,
    TextSendMessage,
    TemplateSendMessage,

    MessageEvent,
    PostbackEvent,
)

import requests as rq

line_bot_api = LineBotApi(settings.LINE_CHANNEL_ACCESS_TOKEN)
parser = WebhookParser(settings.LINE_CHANNEL_SECRET)

bot_description = """
WarmCom，全稱為 Warm Company 有溫暖陪伴的意思，同時也諧音 Warm Come 表示溫暖來臨之意。

WarmCom 提供這些服務：
$ 發表文章：以匿名的方式發表文章
$ 給予溫暖：查看別人的文章並溫暖地回應對方
$ 收到溫暖：查看所收到來自他人的溫暖
$ 配對諮商：協助您找到適合的諮商師
$ 成為諮商師：若您願意諮商他人，則可填寫諮商資訊，並開啟配對功能
""".split("\n")[1:]
bot_description = "\n".join(bot_description)

@csrf_exempt
def receive_message(request):
    signature = request.META['HTTP_X_LINE_SIGNATURE']
    body = request.body.decode('utf-8')
    events = parser.parse(body, signature)
    for event in events:
        if isinstance(event, MessageEvent):
            if event.message.text == "這個機器人是做什麼的?":
                msg = TextSendMessage(
                    text = bot_description,
                    emojis = [
                        {
                            "index": 77,
                            "productId": "5ac2213e040ab15980c9b447",
                            "emojiId": "017"
                        },
                        {
                            "index" : 95,
                            "productId" : "5ac2213e040ab15980c9b447",
                            "emojiId" : "018",
                        },
                        {
                            "index" : 118,
                            "productId" : "5ac2213e040ab15980c9b447",
                            "emojiId" : "019",
                        },
                        {
                            "index" : 138,
                            "productId" : "5ac2213e040ab15980c9b447",
                            "emojiId" : "020",
                        },
                        {
                            "index" : 157,
                            "productId" : "5ac2213e040ab15980c9b447",
                            "emojiId" : "021",
                        },
                    ]
                )
                line_bot_api.reply_message(event.reply_token, msg)
        if isinstance(event, PostbackEvent):
            user_id = event.source.user_id
            data = resolve_postback_data(event.postback.data)
            action = data["action"]
            if action == "pair":
                send_message(user_id, "已發送邀請給該諮商師，等待回覆中...")
                rq.post(
                    f"{settings.BASE_DOMAIN}/api/appoint",
                    {
                        "user_id" : user_id,
                        "counselor_id" : data["counselor_id"],
                    }
                )
            if action == "help":
                send_message(user_id, "已接受，將您的 id 傳送給對方")
                rq.post(
                    f"{settings.BASE_DOMAIN}/api/help",
                    {
                        "user_id" : data["target_id"],
                        "counselor_id" : user_id,
                    }
                )

    return http.HttpResponse()

def resolve_postback_data(postback_data: str):
    result = {}
    for tmp in postback_data.split("&"):
        t = tmp.split("=")
        result[t[0]] = t[1]
    return result

def send_to_user(user_id: str, message: Message):
    line_bot_api.push_message(user_id, message)

def send_message(user_id: str, message: str):
    msg = TextSendMessage(text=message)
    send_to_user(user_id, msg)

def generate_counselors_information_template(filter_types: list):
    def generate_counselor_template(counselor: models.Counselor):
        gender = counselor.gender
        age = counselor.age
        job = counselor.job
        is_professional = counselor.is_professional

        title = counselor.user_name
        if len(gender) == 1 or age or is_professional:
            tmp = ""
            if len(gender) == 1:
                tmp += gender
            if age:
                if tmp:
                    tmp += "，"
                tmp += str(age)
            if tmp:
                tmp += "，"
            if is_professional:
                tmp += "專業"
            else:
                tmp += "非專業"
            title += f" ({tmp})"

        text = counselor.description
        if job:
            text = f"職業: {job}\n{text}"
        else:
            text = f"職業: 無\n{text}"
        return {
            "thumbnailImageUrl": counselor.image,
            "imageBackgroundColor": "#FFFFFF",
            "title": title,
            "text": text,
            "actions": [
                {
                    "type": "postback",
                    "label": "配對",
                    "text": f"我要配對 {counselor.user_name}",
                    "data" : f"action=pair&counselor_id={counselor.user_id}"
                },
            ]
        }

    target_type_condition = None
    for idx, target_type in enumerate(filter_types):
        if idx == 0:
            target_type_condition = Q(target=target_type)
        else:
            target_type_condition = target_type_condition | Q(target=target_type)
    counselors = models.Counselor.objects.filter(target_type_condition & Q(can_be_paired=True)).distinct()[0:10]
    if len(counselors) == 0:
        return {}
    return {
        "type": "template",
        "alt_text": "符合條件的諮商師",
        "template": {
            "type": "carousel",
            "columns": [generate_counselor_template(c) for c in counselors],
            "imageAspectRatio": "rectangle",
            "imageSize": "cover"
        }
    }

def send_counselors_information_to_user(user_id: str, filter_types: list):
    counselors_information = generate_counselors_information_template(filter_types)
    if counselors_information:
        send_to_user(user_id, TemplateSendMessage(**counselors_information))
    else:
        send_to_user(user_id, TextSendMessage(text="查不到相關的諮商師"))

def generate_patient_template(user_id, brief):
    user = line_bot_api.get_profile(user_id)
    return {
        "type": "template",
        "alt_text": "有人需要被諮商!",
        "template": {
            "type": "buttons",
            "thumbnailImageUrl": user.picture_url,
            "imageAspectRatio": "rectangle",
            "imageSize": "cover",
            "imageBackgroundColor": "#FFFFFF",
            "title": user.display_name,
            "text": f"{brief}",
            "actions": [
                {
                    "type": "postback",
                    "label": "接受",
                    "text" : "接受",
                    "data" : f"action=help&target_id={user_id}"
                },
            ]
        }
    }

def send_patient_information_to_counselor(counselor_id, user_id, brief):
    template = generate_patient_template(user_id, brief)
    send_to_user(counselor_id, TemplateSendMessage(**template))


# coding=utf-8

"""
Functionality for building wheels
"""

import glob
import os.path as path
import shutil
import subprocess
import tempfile

from packaging import tags
from pkg_resources import Distribution, Requirement

from wheel_filename import InvalidFilenameError, parse_wheel_filename
from wheel_inspect import inspect_wheel
from wheel_inspect.classes import WheelFile

class BuildError(Exception):
    def __init__(self, package, version, root_exception=None):
        version = version or ""
        super(BuildError, self).__init__('Failed to create wheel for {} {}:\n{}\nOutput:\n{}'.format(
            package,
            version,
            root_exception,
            root_exception.output if hasattr(root_exception, 'output') and root_exception.output else ''
        ))

class Builder(object):
    """
    Provides a context in which wheels can be generated. If the context goes out of scope
    all created files will be removed.
    """
    def __enter__(self):
        self.scratch_dir = tempfile.mkdtemp()
        self.wheelhouse = path.join(self.scratch_dir, 'wheels')
        return lambda *args: self.build(*args)

    def __exit__(self, exc_type, exc_val, exc_tb):
        shutil.rmtree(self.scratch_dir)

    @staticmethod
    def _standardize_package_name(name):
        return name.replace(".", "-")

    def _matches_requirement(self, requirement, wheels):
        """
        List wheels matching a requirement.

        :param requirement:str : The requirement to satisfy
        :param wheels: List of wheels to search.
        """
        req = Requirement.parse(requirement)

        matching = []
        for wheel in wheels:
            w = wheel.parsed_filename
            dist = Distribution(project_name=self._standardize_package_name(w.project), version=w.version)
            if dist in req:
                matching.append(wheel.path)
        return matching

    def _find_wheel(self, name, version):
        """
        Find a wheel with the given name and version
        """
        candidates = [WheelFile(filename) for filename in glob.iglob(path.join(self.wheelhouse, '*.whl'))]
        name = self._standardize_package_name(name)
        requirement = '{}=={}'.format(name, version) if version else name
        matches = self._matches_requirement(requirement, candidates)
        if len(matches) > 0:
            return str(matches[0])
        else:
            raise BuildError(name, version, 'Failed to find the build wheel for {} {}'.format(name, version))

    def build(self, package, version):
        """
        Build a wheel for the given version of the given project.

        :param package: The name of the project
        :param version: The version to generate the wheel for
        :return: The path of the build wheel. Valid until the context is exited.
        """
        try:
            subprocess.check_output([
                'pip', 'wheel',
                '--wheel-dir=' + self.wheelhouse,
                '{}=={}'.format(package, version) if version else package,
            ], stderr=subprocess.STDOUT)
            return self._find_wheel(package, version)
        except subprocess.CalledProcessError as e:
            raise BuildError(package, version, e)

def is_pure(wheel):
    """
    Check whether wheel given by the passed path is pure.

    Pure wheels operate independent of the specific Python version and platform.

    :param wheel: The path to the wheel to inspect
    :return: True if the wheel is pure
    """
    return (
        inspect_wheel(wheel)
            .get("dist_info", {})
            .get("wheel", {})
            .get("root_is_purelib")
    )

def is_compatible(package):
    """
    Check whether the given python package is a wheel compatible with the
    current platform and python interpreter.

    Compatibility is based on https://www.python.org/dev/peps/pep-0425/
    """
    try:
        w = parse_wheel_filename(package)
        for systag in tags.sys_tags():
            for tag in w.tag_triples():
                if systag in tags.parse_tag(tag):
                    return True
    except InvalidFilenameError:
        return False

def has_compatible_wheel(packages):
    """
    Check for a compatible wheel in the given list of python packages
    """
    return any(is_compatible(pkg) for pkg in packages)


# Import the libraries required for running the program
import urllib.request
import json

# To ensure that this script is able to access the API url
url = ""
class AppURLopener(urllib.request.FancyURLopener):
    version = "Mozilla/5.0"

# Set the initial counter/conditional variables
globalHDCounterTrue = 0
globalHDCounterFalse = 0
checkMore = True
testVar = 1

# Store the test url for reference as a variable
urlTester = "http://api.viki.io/v4/videos.json?app=100250a&per_page=10&page="

# Define the primary condition
while (checkMore == True):
    url = ""
    url = urlTester + str(testVar)

# Convert the JSON object returned as a response to Python
    opener = AppURLopener()
    response = opener.open(url)
    data = json.loads(response.read().decode("utf8"))

# Access the response key which is an array of more JSON objects - 'flags' and within it, a key called 'hd'
    checkMore = data['more']
    checkOther = data['response']
    checkFlags = data['response'][0]['flags']
    checkHD = data['response'][0]['flags']['hd']

# Set counters and conditional statement to calculate the response objects that have flags:hd set to true and false
    i=0
    hdTrue = 0
    hdFalse = 0
    for something in data['response'][i]['flags']:
        if (data['response'][i]['flags']['hd']):
            hdTrue = hdTrue + 1
        else:
            hdFlase = hdFalse + 1
        i = i+1

# Increment page number of the test url
    testVar = testVar + 1

# A global counter to compute the value of response objects - flags:hd set to true and false
    globalHDCounterTrue = globalHDCounterTrue + hdTrue
    globalHDCounterFalse = globalHDCounterFalse + hdFalse

# Print the final results
print ("Total no. of pages parsed are")
print(testVar-1)
print ("Total no. of response objects that have the flag:hd value set to True is")
print(globalHDCounterTrue)
print("Total no. of response objects that have the flag:hd value set to False is")
print(globalHDCounterFalse)


from django.core.management.base import BaseCommand

from spire.scraper.classes.buildings.raw_building import get_raw_building_room

class Command(BaseCommand):
    help = "Testing for queries."

    def handle(self, *args, **options):

        matched_out = open("./matched", "w")
        unmatched_out = open("./unmatched", "w")

        with open("./possible_rooms", "r") as f:
            matched = 0
            total = 0
            for line in f:
                line = line.strip()
                total += 1

                match = get_raw_building_room(line)
                if not match.endswith("None"):
                    matched += 1

                print(match, file=matched_out if not match.endswith("None") else unmatched_out)

        print(matched / total, file=matched_out)
        print((total - matched) / total, file=unmatched_out)


import logging
import threading
from server.base import engine, Base
from server.model import User, Document
from server.loop import ThreadedTCPServer, ThreadedTCPRequestHandler

HOST = '0.0.0.0'
PORT = 5000

logging.basicConfig(level=logging.INFO)

Base.metadata.create_all(engine)

if __name__ == "__main__":
    with ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) as server:
        server_thread = threading.Thread(target=server.serve_forever)
        server_thread.daemon = True
        server_thread.start()

        print(f"Server loop running in thread: {server_thread.name}")

        server_thread.join()
        server.shutdown()


import numpy
import scipy.linalg
A = numpy.zeros((101,101))
i,j = numpy.indices(A.shape)
A[i==j+1]=1
A[i==j]=1
A[i==j+2]=1
B = numpy.arange(101)
print(scipy.linalg.solve(A,B))
print(A)


from datetime import datetime
from time import sleep

import requests
from pandas import DataFrame
from bs4 import BeautifulSoup

CNB_NEWS_ARCHIVE_URL = ("https://www.cnb.gov.sg/newsandevents/news/archive"
                        "/archivesubnews/index/{year}")

event_write_up = []
event_titles = []
dates = []
links = []
for year in range(2012, 2023):
    resp = requests.get(CNB_NEWS_ARCHIVE_URL.format(year=year))
    soup = BeautifulSoup(resp.text, 'html.parser')
    timeline_panels = soup.find_all('div', 'tl-heading')
    for tp in timeline_panels:
        event_title = tp.find('h4').get_text()
        event_link = tp.find('a').get('href')
        event_date = datetime.strptime(tp.find('p').get_text(), ' %d %b %Y')
        event_date = event_date.strftime('%Y-%m-%d')
        dates.append(event_date)
        links.append('https://www.cnb.gov.sg' + event_link)
        event_titles.append(event_title)
        article_resp = requests.get(links[-1])
        if article_resp.status_code != 200:
            continue
        art_soup = BeautifulSoup(article_resp.text, 'html.parser')
        p_tags = art_soup.find_all('p')
        write_up = ' '.join([p_tag.text for p_tag in p_tags])
        event_write_up.append(write_up)
        sleep(0.1)

DataFrame(
  {'title': event_titles,
   'date': dates,
   'link': links,
   'article': event_write_up}).to_csv("cnb_articles.csv")


"""
Whatson db

This module handles talking to Postgres via `psycopg2`.
"""

import logging
import os
import psycopg2
from psycopg2.extras import RealDictCursor
from dotenv import load_dotenv

load_dotenv()

LOG = logging.getLogger("whatson.db")
LOG.setLevel(logging.DEBUG)

DB = psycopg2.connect(os.environ["DATABASE_URL"], cursor_factory=RealDictCursor)

def reset_database(db):
    """Resets the database to its basic schema"""
    with db as conn:
        cursor = conn.cursor()
        cursor.execute("DROP TABLE IF EXISTS shows")
        cursor.execute(
            """CREATE TABLE shows (
                id SERIAL PRIMARY KEY,
                theatre VARCHAR(255) NOT NULL,
                title VARCHAR(255) NOT NULL,
                image_url TEXT NOT NULL,
                link_url TEXT NOT NULL,
                start_date DATE NOT NULL,
                end_date DATE NOT NULL,
                created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
                )"""
        )
        cursor.execute(
            """CREATE UNIQUE INDEX _idx_shows_theatre_title
                ON shows (theatre, title)
                """
        )

        cursor.execute(
            """CREATE OR REPLACE FUNCTION total_months(date)
            RETURNS int AS
                'select (extract(year from $1) * 12 + extract(month from $1))::int'
                    language sql immutable
            """
        )


from datetime import datetime
from pathlib import Path

def initialize(record_root: str, train_method: str):
    """Initialize the folders for storing logs and checkpoints. Also decides the names of runs.

    Args:
        record_root: root location for storing records.
        train_method: method used for training.

    Returns:
        The component parts of the initialization.
    """
    record_root = Path(record_root)
    record_root.mkdir(exist_ok=True)

    record_path = record_root / train_method
    record_path.mkdir(exist_ok=True)

    run_number = sum(location.is_dir() for location in record_path.iterdir()) + 1
    time_string = str(datetime.now()).split('.')[0].replace(':', '-')
    run_name = f'Trial {run_number:02d}  {time_string}'

    record_path = record_path / run_name
    record_path.mkdir(exist_ok=False)

    checkpoint_path = record_path / 'checkpoints'
    log_path = record_path / 'logs'

    checkpoint_path.mkdir(exist_ok=False)
    log_path.mkdir(exist_ok=False)

    print(f'Created directories for {record_path}')
    print('Starting', run_name)

    return run_number, run_name, log_path, checkpoint_path


from tkinter import *
from tkinter import messagebox

from decimal import Decimal
import math

from PIL import Image, ImageTk

class support:
    def __init__ ( self ) :
        self.EPrefixList = [ [ "k" , "M" , "G" , "T" ], [ "m" , "u" , "n" , "p" ] ]
        self.EPrefixDic = { "k" : 1E3 , "M" : 1E6 , "G" : 1E9 , "T" : 1E12,
                            "m" : 1E-3 , "u" : 1E-6 , "n" : 1E-9 , "p" : 1E-12 }
        self.trueValueDic = { "k" : "E3" , "M" : "E6" , "G" : "E9" , "T" : "E12",
                            "m" : "E-3" , "u" : "E-6" , "n" : "E-9" , "p" : "E-12" }
        self.unrecognizableChars = "abcdefghijloqrstvwxyzABCDEFHIJKLNOPQRSUV!@#$%^&*()_+={}[]|\;:?/><,~`"

    def makeENotation ( self , value , format = "%s" ):
        self.value = value
        self.sign = ""
        if self.value < 0:
            self.value = -self.value
            self.sign = "-"
        try:
            self.exponent = int ( math.floor ( math.log10( self.value )))
        except:
            self.exponent = 1
        self.Eexponent = self.exponent - ( self.exponent % 3 )
        self.Evalue = self.value / ( 10 ** self.Eexponent )
        if self.Eexponent == 0:
            self.Eexponent_value = ""
        else:
            self.Eexponent_value = "e%s" % self.Eexponent
        return ( "%s" + format + "%s" ) % ( self.sign, self.Evalue, self.Eexponent_value )

    def make4Decimals ( self, value ):
        self.value = value
        self.__EPrefixValue = self.makeEPrefix( self.value )
        self.__tempList = self.__EPrefixValue.split(" ")
        self.dropped = float(math.floor( float( self.__tempList[0]) * 10 ** 4 ) / 10 ** 4)
        if len(self.__tempList) > 1:
            self.__partialResult = self.dropped * self.EPrefixDic[ self.__tempList[1] ]
        else:
            self.__partialResult = self.dropped
        print( self.__partialResult )
        self.__result = self.makeENotation( self.__partialResult )
        return self.__result

    def makeEPrefix ( self , value , seperator = " " ) :
        self.value = float(value)
        try:
            self.EPrefixType = int ( math.floor ( math.log10( math.fabs(self.value) ) / 3 ) )
        except:
            self.EPrefixType = 0
        if self.EPrefixType != 0:
            self.tempPointer = self.EPrefixType/ math.fabs ( self.EPrefixType )
            if self.tempPointer == 1:
                try:
                    EPrefix = self.EPrefixList[0][ self.EPrefixType - 1 ]
                except:
                    EPrefix = self.EPrefixList[0][-1]
                    self.EPrefixType = len ( self.EPrefixList[0] )
            elif self.tempPointer == -1:
                try:
                    EPrefix = self.EPrefixList[1][ -self.EPrefixType - 1]
                except:
                    EPrefix = self.EPrefixList[1][-1]
                    self.EPrefixType = -len( self.EPrefixList[1] )
            adjusted = self.make4Decimals(float ( self.value * math.pow( 1000 , -self.EPrefixType )))
            self.result = "{adjusted}{seperator}{EPrefix}".format(adjusted = adjusted,
                                                                  seperator = seperator,
                                                                  EPrefix = EPrefix)
        else:
            self.result = "{value}".format(value = value)

        return self.result

    def trueValue( self, data ):
        self.data = str( data )
        self.dataAsList = list( data )
        self.tempList = list( self.trueValueDic )
        self.tempPrefix = None
        for i in range ( len ( self.dataAsList ) ):
            try:
                if self.dataAsList[i] == " ":
                    self.dataAsList.remove(" ")
                if self.dataAsList[i] in self.unrecognizableChars:
                    return False
            except:
                pass

        for i in range ( len ( self.tempList ) ):
            if self.tempList[i] in self.dataAsList:
                self.tempPrefix = self.tempList[i]
                self.dataAsList.remove( self.tempList[i] )
                break
        self.splitTest = self.data.split(self.tempPrefix)
        print(self.splitTest)
        if len(self.splitTest) > 1 and self.splitTest[1] != "" and self.splitTest[1] != " ":
            return False
        if self.tempPrefix != None:
            self.data = float ("".join( self.dataAsList ) + self.trueValueDic[ self.tempPrefix ])
        else:
            self.data = float ( "".join( self.dataAsList ) )
        return self.data

s = support()

class circuitSolver:
    def __init__(self):
        pass

    def step1( self, SourceVx , R1 , Vx):
        self.SourceVx = SourceVx
        self.R1 = R1
        self.Vx = -Vx

        self.s1Result = []

        self.s1I2A = -self.SourceVx * self.Vx
        self.s1Result.append( self.s1I2A )

        self.temp_s1I1 = self.R1
        self.s1I2B = -self.R1
        self.s1I2 = self.s1I2A + self.s1I2B
        self.s1Result.append( self.s1I2 )

        try:
            self.s1I1 = -self.s1I2 / self.temp_s1I1
        except ZeroDivisionError:
            self.s1I1 = 0
        self.s1Result.append( float(s.make4Decimals(self.s1I1)))

        return self.s1Result

    def step2( self, R3 , R1 , R4 , s1Result):
        self.R3 = R3
        self.R1 = R1
        self.R4 = R4
        self.s1Result = s1Result

        self.s2Result = []

        self.s2R3I2 = self.R3
        self.s2R1I2 = self.R1
        self.temp_s2R1I1 = -self.R1
        self.s2R4I2 = self.R4
        self.s2R4I3 = -self.R4

        self.s2R1I1 = self.temp_s2R1I1 * self.s1Result
        self.s2Result.append( self.s2R1I1 )

        self.s2TotalI2 = self.s2R3I2 + self.s2R1I2 + self.s2R1I1 + self.s2R4I2
        self.s2Result.append( self.s2TotalI2 )

        self.s2I2 = -self.s2R4I3 / self.s2TotalI2
        self.s2Result.append( float(s.make4Decimals(self.s2I2)))

        return self.s2Result

    def step3( self, R4 , R2 , V0 , s2I2 ):
        self.R4 = R4
        self.R2 = R2
        self.V0 = V0
        self.s2I2 = s2I2

        self.s3Result = []

        self.s3R4I3 = self.R4
        self.temp_s3R4I2 = -self.R4
        self.s3R2I3 = self.R2

        self.s3R4I2 = self.temp_s3R4I2 * self.s2I2
        self.s3Result.append(self.s3R4I2)
        self.temp_s3I3 = self.s3R4I3 + self.s3R2I3
        self.s3Result.append(self.temp_s3I3)

        self.total_s3I3 = self.temp_s3I3 + self.s3R4I2
        self.s3Result.append(self.total_s3I3)

        self.s3I3 = (-self.V0) / self.total_s3I3
        self.s3Result.append( float(s.make4Decimals(self.s3I3)))

        return self.s3Result

    def step4 ( self, s3Result , V0 ):
        self.s3I3 = s3Result
        self.V0 = V0

        self.s4Result = []

        self.s4I0 = -self.s3I3
        self.s4Rth = self.V0 / self.s4I0
        print ( self.s4I0)
        self.s4Result.append(float(s.make4Decimals(self.s4Rth)))

        return self.s4Result

    def step5 ( self , I1 , R3 , R1 , R4 , SourceVx):
        self.I1 = I1
        self.R3 = R3
        self.R1 = R1
        self.R4 = R4
        self.SourceVx = SourceVx

        self.s5Result = []

        self.temp_s5R3I1 = -self.R3
        self.temp_s5R1I3 = -self.R1

        self.temp_s5RI2 = self.R3 + self.R1 + self.R4
        self.s5Result.append( self.temp_s5RI2 )
        self.s5R3I1 = self.I1 * self.temp_s5R3I1 # 20
        self.s5Result.append(self.s5R3I1)

        try:
            self.s5SVx = self.temp_s5R1I3 * (self.SourceVx / self.R1)
        except ZeroDivisionError:
            self.s5SVx = 0
        self.s5Result.append(self.s5SVx)
        try:
            self.s5R1I2 = self.temp_s5R1I3 * ( self.R1 / self.R1)
        except ZeroDivisionError:
            self.s5R1I2 = 0
        self.s5Result.append(self.s5R1I2)

        self.s5RI2 = self.temp_s5RI2 + self.s5R1I2
        self.s5Result.append(self.s5RI2)

        self.s5R1VxA = self.s5SVx * ( self.R3 * self.I1 )
        self.s5Result.append(self.s5R1VxA)
        self.s5R1VxB = self.s5SVx * (-self.R3 )
        self.s5Result.append(self.s5R1VxB)

        self.s5WholeNumber = -(self.s5R3I1 + self.s5R1VxA)
        self.s5Result.append(self.s5WholeNumber)

        self.s5RI2 = self.s5RI2 + self.s5R1VxB
        self.s5Result.append(self.s5RI2)

        self.s5I2 = self.s5WholeNumber / self.s5RI2
        self.s5Result.append( float(s.make4Decimals(self.s5I2)))

        return self.s5Result

    def step6 ( self , R3 , R1 , R4 , SourceVx ):
        self.R3 = R3
        self.R1 = R1
        self.R4 = R4
        self.SourceVx = SourceVx

        self.s6Result = []

        try:
            self.s6VxI3 = 2 * ( self.R1 / self.SourceVx )
        except ZeroDivisionError:
            self.s6VxI3 = 0
        self.s6Result.append(self.s6VxI3)
        try:
            self.s6VxI2 =  2 * (-( self.R1 / self.SourceVx ))
        except ZeroDivisionError:
            self.s6VxI2 = 0
        self.s6Result.append(self.s6VxI2)

        self.s6R1I2 = 2 * (-self.R1)
        self.s6Result.append(self.s6R1I2)

        self.s6R1I3 = 2 * (-self.R1 * -1)
        self.s6Result.append(self.s6R1I3)

        self.s6R4I2 = 2 * (-self.R4)
        self.s6Result.append(self.s6R4I2)

        self.partial_s6RI2 = self.s6R1I2 + self.s6R4I2
        self.s6Result.append(self.partial_s6RI2)

        self.s6RI2 = self.partial_s6RI2 + (-self.s6VxI2)
        self.s6Result.append(self.s6RI2)

        self.s6RI3 = self.s6R1I3 + (-self.s6VxI3)
        self.s6Result.append(self.s6RI3)

        try:
            self.s6I3 = (-self.s6RI2) / self.s6RI3
        except:
            self.s6I3 = 0
        self.s6Result.append( float(s.make4Decimals(self.s6I3)))

        return self.s6Result

    def step7 ( self , SourceVx , R1 , s6I3 ):
        self.SourceVx = SourceVx
        self.R1 = self.R1
        self.s6I3 = s6I3

        self.s7Result = []

        self.s7I2 = self.R1 * ( self.s6I3 - 1 )
        self.s7Result.append(self.s7I2)

        try:
            self.s7result = self.s7I2 / self.SourceVx
        except ZeroDivisionError:
            self.s7result = 0
        self.s7Result.append( float(s.make4Decimals(self.s7result)))

        return self.s7Result

    def step8 ( self , s7result , s5I2 ):
        self.s7result = s7result
        self.s5I2 = s5I2
        self.s8Result = []

        self.s8result = self.s7result * self.s5I2
        self.s8Result.append( float(s.make4Decimals(self.s8result)))

        return self.s8Result

    def solve ( self , SourceVx , CurrentSource , R1 , R2 , R3 , R4 ):
        self.sSourceVx = SourceVx
        self.sCurrentSource = CurrentSource
        self.sV0 = 1
        self.sR1 = R1
        self.sR2 = R2
        self.sR3 = R3
        self.sVx = R3
        self.sR4 = R4

        self.solutionData = []

        self.s1resultList = self.step1( self.sSourceVx , self.sR1 , self.sVx)
        self.solutionData.append( self.s1resultList )
        self.s1result = self.s1resultList[-1]

        self.s2resultList = self.step2( self.sR3 , self.sR1 , self.sR4 , self.s1result)
        self.solutionData.append( self.s2resultList )
        self.s2result = self.s2resultList[-1]

        self.s3resultList = self.step3( self.sR4 , self.sR2 , self.sV0 , self.s2result )
        self.solutionData.append( self.s3resultList )
        self.s3result = self.s3resultList[-1]
        #print( self.s3resultList[-1])

        self.s4resultList = self.step4( self.s3result , self.sV0 )
        self.solutionData.append( self.s4resultList )
        self.s4result = self.s4resultList[-1]

        self.s5resultList = self.step5( self.sCurrentSource , self.sR3 , self.sR1 , self.sR4 , self.sSourceVx)
        self.solutionData.append( self.s5resultList )
        self.s5result = self.s5resultList[-1]

        self.s6resultList = self.step6( self.sR3 , self.sR1 , self.sR4 , self.sSourceVx )
        self.solutionData.append( self.s6resultList )
        self.s6result = self.s6resultList[-1]

        self.s7resultList = self.step7( self.sSourceVx , self.sR1 , self.s6result )
        self.solutionData.append( self.s7resultList )
        self.s7result = self.s7resultList[-1]

        self.s8resultList = self.step8( self.s7result , self.s5result )
        self.solutionData.append( self.s8resultList )
        self.s8result = self.s8resultList[-1]

        return self.solutionData

cS= circuitSolver()

class circuitUI:
    def __init__( self ):
        self.mcUI_width = 500
        self.mcUI_height = 500

        self.createGUI()

    def filterEntry(self , entry):
        self.entry = entry
        self.entryAsList = list ( self.entry )

        for i in range ( len ( self.entry ) ):
            if self.entryAsList[i] == "\n" :
                del self.entryAsList[i]
        self.filterResult = "".join(self.entryAsList)
        return self.filterResult

    def mainCircuit( self ):
        self.mcUI_backgroundImage_open = Image.open( "background5.jpg" )
        self.mcUI_backgroundImage_resized = self.mcUI_backgroundImage_open.resize( (510 , 510), Image.ANTIALIAS )
        self.mcUI_backgroundImage = ImageTk.PhotoImage( self.mcUI_backgroundImage_resized )
        self.mcUI_backgroundImage_LBL = Label( self.mC , image = self.mcUI_backgroundImage )
        self.mcUI_backgroundImage_LBL.place( x = -2 , y = -2 )

        self.mcUI_mainCircuitImage_open = Image.open( "mainCircuit.png" )
        self.mcUI_mainCircuitImage_resized = self.mcUI_mainCircuitImage_open.resize( (480 , 300), Image.ANTIALIAS )
        self.mcUI_mainCircuitImage = ImageTk.PhotoImage( self.mcUI_mainCircuitImage_resized )
        self.mcUI_mainCircuitImage_LBL = Label( self.mC , image = self.mcUI_mainCircuitImage )
        self.mcUI_mainCircuitImage_LBL.place( x = 10 , y = 50 )

        self.TheveninsText = Label ( text = "THEVENIN'S THEOREM" , bg = "lightblue" , fg = "black" , width = "20" , height = "1" ,
                               font = ( "Courier" , 25 , "bold" ))
        self.TheveninsText.place ( x = 50 , y = 4 )

        self.mcUI_SolveBTN = Button ( self.mC , font = ( "Courier" , 15 , "bold" ) , text = "SOLVE" , width = "20"
                                , height = "50" ,bg = "green" , fg = "black" , command = self.solveBTN_clicked )
        self.mcUI_SolveBTN.place ( x = 130 , y = 370 , height = 40 )

        self.mcUI_ExitBTN = Button ( self.mC , font = ( "Courier" , 15 , "bold" ) , text = "EXIT PROGRAM" , width = "20"
                                , height = "50" ,bg = "green" , fg = "black" , command = self.ext )
        self.mcUI_ExitBTN.place ( x = 130 , y = 430 , height = 40 )

        self.mcUI_SourceVx_Entry = Text ( self.mC , bd = 0 , bg = "LightGrey" , width = "9" , height = "1" , font = "Arial" )
        self.mcUI_SourceVx_Entry.place( x = 195 , y = 100 )

        self.mcUI_Vx_LBL = Label ( text = "Vx" , bg = "white" , fg = "black" , width = "2" , height = "1" ,
                               font = ( "Arial" , 8 , "bold" ))
        self.mcUI_Vx_LBL.place ( x = 280 , y = 100 , )

        self.mcUI_R1_Entry = Text ( self.mC , bd = 0 , bg = "LightGrey" , width = "9" , height = "1" , font = "Arial" )
        self.mcUI_R1_Entry.place( x = 195 , y = 195 )

        self.mcUI_R2_Entry = Text ( self.mC , bd = 0 , bg = "LightGrey" , width = "9" , height = "1" , font = "Arial" )
        self.mcUI_R2_Entry.place( x = 380 , y = 195 )

        self.mcUI_CurrentSource_Entry = Text ( self.mC , bd = 0 , bg = "LightGrey" , width = "5" , height = "1" , font = "Arial" )
        self.mcUI_CurrentSource_Entry.place( x = 15 , y = 238 )

        self.mcUI_R3_Entry = Text ( self.mC , bd = 0 , bg = "LightGrey" , width = "9" , height = "1" , font = "Arial" )
        self.mcUI_R3_Entry.place( x = 180 , y = 260 )

        self.mcUI_R4_Entry = Text ( self.mC , bd = 0 , bg = "LightGrey" , width = "9" , height = "1" , font = "Arial" )
        self.mcUI_R4_Entry.place( x = 335 , y = 271 )

        self.mcUI_ohmsSymbol1_LBL = Label ( text = "Ω" , bg = "white" , fg = "black" , width = "1" , height = "1" ,
                               font = ( "Arial" , 8 , "bold" ))
        self.mcUI_ohmsSymbol1_LBL.place( x= 280 , y = 195 )

        self.mcUI_ohmsSymbol2_LBL = Label ( text = "Ω" , bg = "white" , fg = "black" , width = "1" , height = "1" ,
                               font = ( "Arial" , 8 , "bold" ))
        self.mcUI_ohmsSymbol2_LBL.place( x= 465 , y = 195 )

        self.mcUI_ohmsSymbol3_LBL = Label ( text = "Ω" , bg = "white" , fg = "black" , width = "1" , height = "1" ,
                               font = ( "Arial" , 8 , "bold" ))
        self.mcUI_ohmsSymbol3_LBL.place( x= 265 , y = 260 )

        self.mcUI_ohmsSymbol4_LBL = Label ( text = "Ω" , bg = "white" , fg = "black" , width = "1" , height = "1" ,
                               font = ( "Arial" , 8 , "bold" ))
        self.mcUI_ohmsSymbol4_LBL.place( x= 420 , y = 271 )

    def solveBTN_clicked( self ):
        self.solve_Error = False
        if messagebox.askyesno( "Solve Circuit?" , "Are your Inputs final?" )== True :
            try:
                self.mcUI_SourceVx = float (s.trueValue( self.filterEntry( self.mcUI_SourceVx_Entry.get( "0.0" , END ) ) ))
                if self.mcUI_SourceVx == False:
                    messagebox.showinfo( "Input Error Detected" , "Unrecognizable character detected at SourceVx Entry." )
                    self.solve_Error = True
                self.mcUI_R1 = float (s.trueValue( self.filterEntry( self.mcUI_R1_Entry.get( "0.0" , END ) ) ))
                if self.mcUI_R1 == False:
                    messagebox.showinfo( "Input Error Detected" , "Unrecognizable character detected at R1 Entry." )
                    self.solve_Error = True
                self.mcUI_R2 = float (s.trueValue( self.filterEntry( self.mcUI_R2_Entry.get( "0.0" , END ) ) ))
                if self.mcUI_R2 == False:
                    messagebox.showinfo( "Input Error Detected" , "Unrecognizable character detected at R2 Entry." )
                    self.solve_Error = True
                self.mcUI_CurrentSource = float (s.trueValue( self.filterEntry( self.mcUI_CurrentSource_Entry.get( "0.0" , END ) ) ))
                if self.mcUI_CurrentSource == False:
                    messagebox.showinfo( "Input Error Detected" , "Unrecognizable character detected at Current Source Entry." )
                    self.solve_Error = True
                self.mcUI_R3 = float (s.trueValue( self.filterEntry( self.mcUI_R3_Entry.get( "0.0" , END ) ) ))
                if self.mcUI_R3 == False:
                    messagebox.showinfo( "Input Error Detected" , "Unrecognizable character detected at R3 Entry." )
                    self.solve_Error = True
                self.mcUI_R4 = float (s.trueValue( self.filterEntry( self.mcUI_R4_Entry.get( "0.0" , END ) ) ))
                if self.mcUI_R4 == False:
                    messagebox.showinfo( "Input Error Detected" , "Unrecognizable character detected at R4 Entry." )
                    self.solve_Error = True
            except:
                self.solve_Error = True
                messagebox.showinfo( "Error Detected" , "Please make sure you are inputting the values right." )
            if self.solve_Error == False :
                self.mcUI_mainCircuitImage_LBL.destroy()
                self.TheveninsText.destroy()
                self.mcUI_SolveBTN.destroy()
                self.mcUI_ExitBTN.destroy()
                self.mcUI_SourceVx_Entry.destroy()
                self.mcUI_Vx_LBL.destroy()
                self.mcUI_R1_Entry.destroy()
                self.mcUI_R2_Entry.destroy()
                self.mcUI_CurrentSource_Entry.destroy()
                self.mcUI_R3_Entry.destroy()
                self.mcUI_R4_Entry.destroy()
                self.mcUI_ohmsSymbol1_LBL.destroy()
                self.mcUI_ohmsSymbol2_LBL.destroy()
                self.mcUI_ohmsSymbol3_LBL.destroy()
                self.mcUI_ohmsSymbol4_LBL.destroy()
                self.mcUI_backgroundImage_LBL.destroy()

                self.solutionData = cS.solve( self.mcUI_SourceVx , self.mcUI_CurrentSource ,
                                              self.mcUI_R1 , self.mcUI_R2 , self.mcUI_R3 , self.mcUI_R4 )
                self.circuitSolution( self.solutionData )

    def delay1( self ):
        self.csUI_firstRedrawImage_open = Image.open( "redraw1.png" )
        self.csUI_firstRedrawImage_resized = self.csUI_firstRedrawImage_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_firstRedrawImage = ImageTk.PhotoImage( self.csUI_firstRedrawImage_resized )
        self.csUI_firstRedrawImage_LBL = Label( self.mC , image = self.csUI_firstRedrawImage )
        self.csUI_firstRedrawImage_LBL.place( x = 10 , y = 5 )

        self.csUI_delay11_LBL = Label ( text = str(s.makeEPrefix(self.mcUI_SourceVx)) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay11_LBL.place ( x = 80 , y = 5 )

        self.csUI_delay12_LBL = Label ( text = str(s.makeEPrefix(self.mcUI_R1)) + "Ω" , bg = "white" , fg = "black" , width = "10" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay12_LBL.place ( x = 90 , y = 90 )

        self.csUI_delay13_LBL = Label ( text = str(s.makeEPrefix(self.mcUI_R2)) + "Ω" , bg = "white" , fg = "black" , width = "10" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay13_LBL.place ( x = 180 , y = 90 )

        self.csUI_delay14_LBL = Label ( text = str(s.makeEPrefix(self.mcUI_R3)) + "Ω" , bg = "white" , fg = "black" , width = "10" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay14_LBL.place ( x = 10 , y = 140 )

        self.csUI_delay15_LBL = Label ( text = str(s.makeEPrefix(self.mcUI_R4)) + "Ω" , bg = "white" , fg = "black" , width = "10" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay15_LBL.place ( x = 170 , y = 140 )

    def delay2( self ):
        self.csUI_solution1Image_open = Image.open( "solution1.png" )
        self.csUI_solution1Image_resized = self.csUI_solution1Image_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_solution1Image = ImageTk.PhotoImage( self.csUI_solution1Image_resized )
        self.csUI_solution1Image_LBL = Label( self.mC , image = self.csUI_solution1Image )
        self.csUI_solution1Image_LBL.place( x = 10 , y = 215 )

        self.csUI_sol11_LBL = Label ( text = str(-self.mcUI_SourceVx) + "Vx + (" + str(self.mcUI_R1) + ")(i1 - i2) = 0" , bg = "white" , fg = "black" , width = "30" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol11_LBL.place ( x = 15 , y = 240 )

        self.csUI_sol12_LBL = Label ( text = "Vx = " + str(self.mcUI_R1/self.mcUI_SourceVx) + "i1 + (" + str(-self.mcUI_R1/self.mcUI_SourceVx) + "i2) " , bg = "white" , fg = "black" , width = "30" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol12_LBL.place ( x = 15 , y = 265 )

        self.csUI_sol13_LBL = Label ( text = " i1 = " + str(self.solutionData[0][-1]) +" i2", bg = "white" , fg = "black" , width = "30" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol13_LBL.place ( x = 15 , y = 305 )

        self.csUI_sol14_LBL = Label ( text = " i1 = " + str(self.solutionData[0][-1]) +" i2", bg = "white" , fg = "black" , width = "30" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol14_LBL.place ( x = 15 , y = 305 )

        self.csUI_sol15_LBL = Label ( text = str(self.mcUI_R3) + " + (" + str(self.mcUI_R1) + ")(i2 -i1) + (" + str(self.mcUI_R4) + ")(i2 - i3) = 0" , bg = "white" , fg = "black" , width = "40" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol15_LBL.place ( x = 15 , y = 355 )

        self.csUI_sol16_LBL = Label ( text = str(self.mcUI_R4) + "(i3 -i2) + (" + str(self.mcUI_R1) + "i3) + 1 = 0 " , bg = "white" , fg = "black" , width = "40" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol16_LBL.place ( x = 15 , y = 375 )

        self.csUI_solution2Image_open = Image.open( "solution2.png" )
        self.csUI_solution2Image_resized = self.csUI_solution2Image_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_solution2Image = ImageTk.PhotoImage( self.csUI_solution2Image_resized )
        self.csUI_solution2Image_LBL = Label( self.mC , image = self.csUI_solution2Image )
        self.csUI_solution2Image_LBL.place( x = 10 , y = 425 )

        self.csUI_sol21_LBL = Label ( text = "i3 = " + str(s.makeEPrefix(self.solutionData[2][-1])) + "A" , bg = "white" , fg = "black" , width = "40" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol21_LBL.place ( x = 25 , y = 450 )

        self.csUI_sol22_LBL = Label ( text = str(s.makeEPrefix(-self.solutionData[2][-1])) + "A" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol22_LBL.place ( x = 100 , y = 473 )

        self.csUI_sol23_LBL = Label ( text = "1V" , bg = "white" , fg = "black" , width = "2" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol23_LBL.place ( x = 120 , y = 490 )

        self.csUI_sol24_LBL = Label ( text = str(s.makeEPrefix(-self.solutionData[2][-1])) + "A" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol24_LBL.place ( x = 100 , y = 510 )

        self.csUI_sol25_LBL = Label ( text = str(s.makeEPrefix( s.make4Decimals(1 / (-self.solutionData[2][-1])))) + " ohms" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol25_LBL.place ( x = 170 , y = 500 )

        self.csUI_sol26_LBL = Label ( text = " i1 = " + str(s.makeEPrefix( self.mcUI_CurrentSource )) , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol26_LBL.place ( x = 100 , y = 550 )

        self.csUI_sol27_LBL = Label ( text = str(-self.mcUI_SourceVx) + "Vx + (" + str(self.mcUI_R1) + ")(i3 - i2) = 0 "  , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol27_LBL.place ( x = 100 , y = 580 )

        self.csUI_sol27_LBL = Label ( text = str(-self.mcUI_SourceVx) + "Vx + (" + str(self.mcUI_R1) + ")(i3 - i2) = 0 "  , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol27_LBL.place ( x = 100 , y = 600 )

    def delay3( self ):
        self.csUI_secondRedrawImage_open = Image.open( "redraw2.png" )
        self.csUI_secondRedrawImage_resized = self.csUI_secondRedrawImage_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_secondRedrawImage = ImageTk.PhotoImage( self.csUI_secondRedrawImage_resized )
        self.csUI_secondRedrawImage_LBL = Label( self.mC , image = self.csUI_secondRedrawImage )
        self.csUI_secondRedrawImage_LBL.place( x = 340 , y = 5 )

        self.csUI_solution3Image_open = Image.open( "solution3.png" )
        self.csUI_solution3Image_resized = self.csUI_solution3Image_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_solution3Image = ImageTk.PhotoImage( self.csUI_solution3Image_resized )
        self.csUI_solution3Image_LBL = Label( self.mC , image = self.csUI_solution3Image )
        self.csUI_solution3Image_LBL.place( x = 340 , y = 215 )

        self.csUI_sol31_LBL = Label ( text = str(self.solutionData[4][0]) + " + (" + str(-self.mcUI_R3) + "i2) + (" + str(-self.mcUI_R1) + "i3) = 0"  , bg = "white" , fg = "black" , width = "30" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol31_LBL.place ( x = 350 , y = 245 )

        self.csUI_sol32_LBL = Label ( text = " i2 = " + str(self.solutionData[4][-1])  , bg = "white" , fg = "black" , width = "25" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol32_LBL.place ( x = 425 , y = 310 )

        self.csUI_sol33_LBL = Label ( text = " Vx = Voc = " + str(self.solutionData[7][0]) + "V"  , bg = "white" , fg = "black" , width = "25" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol33_LBL.place ( x = 425 , y = 350 )

        self.csUI_solution4Image_open = Image.open( "solution4.png" )
        self.csUI_solution4Image_resized = self.csUI_solution4Image_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_solution4Image = ImageTk.PhotoImage( self.csUI_solution4Image_resized )
        self.csUI_solution4Image_LBL = Label( self.mC , image = self.csUI_solution4Image )
        self.csUI_solution4Image_LBL.place( x = 340 , y = 425 )

        self.csUI_sol34_LBL = Label ( text = " Vx = " + str( s.makeEPrefix( s.make4Decimals(self.solutionData[7][0]))) + "V"  , bg = "white" , fg = "black" , width = "25" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol34_LBL.place ( x = 400 , y = 500 )

        self.csUI_sol35_LBL = Label ( text = " Rth = " + str( s.makeEPrefix( s.make4Decimals(self.solutionData[3][0]))) + " ohms"  , bg = "white" , fg = "black" , width = "25" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_sol35_LBL.place ( x = 400 , y = 530 )

        self.csUI_delay31_LBL = Label ( text = str(s.makeEPrefix( s.make4Decimals(self.mcUI_SourceVx))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay31_LBL.place ( x = 470 , y = 5 )

        self.csUI_delay32_LBL = Label ( text = str(s.makeEPrefix( s.make4Decimals(self.mcUI_R1))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay32_LBL.place ( x = 470 , y = 95 )

        self.csUI_delay33_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals( self.mcUI_R2))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay33_LBL.place ( x = 565 , y = 95 )

        self.csUI_delay34_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals( self.mcUI_CurrentSource))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay34_LBL.place ( x = 380 , y = 90 )

        self.csUI_delay35_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals( self.mcUI_R3))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay35_LBL.place ( x = 385 , y = 138 )

        self.csUI_delay36_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals( self.mcUI_R4))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 8))
        self.csUI_delay36_LBL.place ( x = 560 , y = 140 )

    def delay4( self ):
        pass

    def delay5( self ):

        self.csUI_thirdRedrawImage_open = Image.open( "thevenin.png" )
        self.csUI_thirdRedrawImage_resized = self.csUI_thirdRedrawImage_open.resize( (320 , 200), Image.ANTIALIAS )
        self.csUI_thirdRedrawImage = ImageTk.PhotoImage( self.csUI_thirdRedrawImage_resized )
        self.csUI_thirdRedrawImage_LBL = Label( self.mC , image = self.csUI_thirdRedrawImage )
        self.csUI_thirdRedrawImage_LBL.place( x = 670 , y = 5 )

        self.csUI_delay51_LBL = Label ( text = str(s.makeEPrefix(self.solutionData[3][-1])) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10))
        self.csUI_delay51_LBL.place ( x = 750 , y = 25 )

        self.csUI_delay52_LBL = Label ( text = str(s.makeEPrefix(self.solutionData[-1][-1])) + "V" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10))
        self.csUI_delay52_LBL.place ( x = 738 , y = 115 )

    def delay6( self ):
        self.csUI_delay61_LBL = Label ( text = "RESISTOR" , bg = "lightGreen" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay61_LBL.place ( x = 672 , y = 222 )

        self.csUI_delay611_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.mcUI_R1))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay611_LBL.place ( x = 672 , y = 252 )

        self.csUI_delay612_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.mcUI_R3))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay612_LBL.place ( x = 672 , y = 282 )

        self.csUI_delay613_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.mcUI_R4))) + "Ω" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay613_LBL.place ( x = 672 , y = 312 )

        self.csUI_delay614_LBL = Label ( text = "" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay614_LBL.place ( x = 672 , y = 342 )

        self.csUI_delay62_LBL = Label ( text = "CURRENT" , bg = "lightGreen" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay62_LBL.place ( x = 781 , y = 222 )

        self.csUI_delay621_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.solutionData[2][-1]))) + "A" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay621_LBL.place ( x = 781 , y = 252 )

        self.csUI_delay622_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.mcUI_CurrentSource))) + "A" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay622_LBL.place ( x = 781 , y = 282 )

        self.csUI_delay623_LBL = Label ( text = str(s.makeEPrefix(self.solutionData[4][-1])) + "A" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay623_LBL.place ( x = 781 , y = 312 )

        self.csUI_delay624_LBL = Label ( text = "" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay624_LBL.place ( x = 781 , y = 342 )

        self.csUI_delay63_LBL = Label ( text = "VOLTAGE" , bg = "lightGreen" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay63_LBL.place ( x = 890 , y = 222 )

        self.voltage1 = (self.solutionData[-1][-1]) * ( self.mcUI_R3 / self.mcUI_R4 )

        self.voltage2 = (self.solutionData[-1][-1]) * ( self.mcUI_R1 / self.mcUI_R4 )

        self.csUI_delay631_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.voltage1))) + "V" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay631_LBL.place ( x = 890 , y = 252 )

        self.csUI_delay632_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.solutionData[-1][-1]))) + "V" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay632_LBL.place ( x = 890 , y = 282 )

        self.csUI_delay633_LBL = Label ( text = str(s.makeEPrefix(s.make4Decimals(self.voltage2))) + "V" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay633_LBL.place ( x = 890 , y = 312 )

        self.csUI_delay634_LBL = Label ( text = "" , bg = "white" , fg = "black" , width = "12" , height = "1" ,
                               font = ( "Arial" , 10 , "bold"))
        self.csUI_delay634_LBL.place ( x = 890 , y = 342 )

    def delay7( self ):
        self.csUI_backBTN = Button ( self.mC , font = ( "Courier" , 15 , "bold" ) , text = "BACK" , width = "20"
                                , height = "50" ,bg = "green" , fg = "black" , command = self.backBTN1 )
        self.csUI_backBTN.place ( x = 200 , y = 650 , height = 40 )

        self.csUI_exitBTN = Button ( self.mC , font = ( "Courier" , 15 , "bold" ) , text = "EXIT PROGRAM" , width = "20"
                                , height = "50" ,bg = "green" , fg = "black" , command = self.ext )
        self.csUI_exitBTN.place ( x = 520 , y = 650 , height = 40 )

    def circuitSolution( self , solutionData ):
        self.solutionData = solutionData

        self.mcUI_width = 1000
        self.mcUI_height = 700

        self.monitorWidth = self.mC.winfo_screenwidth()
        self.mcUI_Xplacement = ( (self.monitorWidth/2) - (self.mcUI_width/2) )

        self.csUI_backgroundImage_open = Image.open( "background8.jpg" )
        self.csUI_backgroundImage_resized = self.csUI_backgroundImage_open.resize( (1010 , 710), Image.ANTIALIAS )
        self.csUI_backgroundImage = ImageTk.PhotoImage( self.csUI_backgroundImage_resized )
        self.csUI_backgroundImage_LBL = Label( self.mC , image = self.csUI_backgroundImage )
        self.csUI_backgroundImage_LBL.place( x = -2 , y = -2 )

        self.mC.geometry("%dx%d+%d+%d" % (self.mcUI_width, self.mcUI_height, self.mcUI_Xplacement, 0) )

        self.mC.after( 800 , self.delay1 )
        self.mC.after( 1600 , self.delay2 )
        self.mC.after( 2600 , self.delay3 )
        self.mC.after( 3400 , self.delay4 )
        self.mC.after( 4400 , self.delay5 )
        self.mC.after( 5000 , self.delay6 )
        self.mC.after( 5800 , self.delay7 )

    def ext( self ):
        if messagebox.askyesno( "Exit Program" , "Are you sure you want to Exit the Program?" )== True :
            self.mC.destroy()

    def backBTN1( self ):
        self.mC.destroy()
        self.createGUI()

    def createGUI( self ):
        self.mcUI_width = 500
        self.mcUI_height = 500
        self.mC = Tk()

        self.monitorWidth = self.mC.winfo_screenwidth()
        self.monitorHeight = self.mC.winfo_screenheight()

        self.mcUI_Xplacement = ( (self.monitorWidth/2) - (self.mcUI_width/2) )
        self.mcUI_Yplacement = ( (self.monitorHeight/2) - (self.mcUI_height/2) )

        self.mC.geometry("%dx%d+%d+%d" % (self.mcUI_width, self.mcUI_height, self.mcUI_Xplacement, self.mcUI_Yplacement) )
        self.mC.config( bg = "orange" )
        self.mC.resizable( width = False , height = False )
        self.mC.title( "Circuit Solver" )

        self.mainCircuit()

    def run(self):
        self.mC.mainloop()

cg = circuitUI()
cg.run()