from neo4j import GraphDatabase
from lxml import etree, objectify
import mwparserfromhell
import spacy
import re
import sys
import math
import enchant
import argparse

"""
The interface to the Neo4J database.
"""
class Neo4JInterface:
    def __init__(self, uri, user, password):
        self.driver = GraphDatabase.driver(uri, auth=(user, password))

    def close(self):
        self.driver.close()

    def print_create_page(self, w_id, title, text, page_type):
        # Calls the private create_page method, and uses it to create a page.
        # Requires the ID of the wiki page, the title, text, and the type of page.
        with self.driver.session() as session:
            result = session.write_transaction(
                self._create_page, w_id, title, text, page_type)
            print(result)

    def print_create_relationship(self, link_from, link_to, relation):
        # Creates a relationship between two pages.
        with self.driver.session() as session:
            result = session.write_transaction(
                self._create_relationship, link_from, link_to, relation)
            if result != None: print(result, "with relation:", relation)

    @staticmethod
    def _create_page(tx, w_id, title, text, page_type):
        query = "MERGE (n:$PTYPE { id: $id, name: $name })".replace("$PTYPE", page_type)
        result = tx.run(query +
                        "ON CREATE SET n.text = $text  "
                        "ON MATCH SET n.text = $text  "
                        "RETURN n.name, n.id ", id=w_id, name=title, text=text, ptype=page_type)
        return result.single()[0]

    @staticmethod
    def _create_relationship(tx, link_from, link_to, relation):
        # Apparently the $RELATION won't be replaced by the tx.run variable substitution
        # mechanism, therfore I've adopted this janky approach.
        query = ("MATCH (from { name: $link_from }) "
                 "MATCH (to { name: $link_to }) "
                 "MERGE (from)-[rel:$RELATION]->(to)".replace("$RELATION", relation))

        query += " RETURN from.name, to.name"
        result = tx.run(query, link_from=link_from, link_to=link_to)
        result = result.single()
        return result

class Page:
    def __init__(self, w_id, title, text):
        self.w_id = w_id
        self.title = title
        self.text = text
        self.wikicode = mwparserfromhell.parse(text)
        self.full_links = self.links()
        self.partial_links = self.lookup_links()
        self.templates = self.wikicode.filter_templates()

    def links(self):
        r = []
        for link in self.wikicode.filter_wikilinks():
            link = link.title
            if not link.startswith("File:"):
                # If there is an anchor in the page, we remove it.
                r.append(link.split("#", 1)[0])
        return r

    def lookup_links(self):
        """
        Returns a list with all the links split into their word components.
        This is to enable easier lookups, as NP chunks will likely split the word up.
        And there will be other components in the NP chunks, muddying lookup.
        """
        r = []
        for link in self.full_links:
            for y in link.split(" "):
                r.append(y)
        return r

    def process_text(self):
        """
        Converts the text from Wikicode into plain text.
        """
        filtered = self.wikicode.strip_code(normalize=True)
        # Ensures all the words are split.
        filtered = filtered.replace("\n", " ").split(" ")

        # The RS Wiki places an image at the start of most articles.
        # The image's text is "left" in the Wikicode, but it isn't.
        # This is our crude attempt at filtering it out.
        if filtered[0].startswith("left"):
            del filtered[0]

        # strip_code isn't fully perfect on our dataset. Occasionally, remnants of images
        # sneak through as "thumb|XXXpx|Word", so we try and catch these instances, and
        # extract the word from it, or otherwise remove the broken word entirely.
        i = 0
        while i < len(filtered):
            if "thumb|" in filtered[i]:
                filtered[i] = filtered[i].split("|")[-1]
            if "File:" in filtered[i] or filtered[i].endswith("|left"):
                del filtered[i]
                i -= 1
            i += 1

        return " ".join(map(str, filtered)).strip()

    def rel_standardise(self, rel):
        """
        Changes relationships to a standard format, and changes any spaces to underscores.
        """
        return rel.upper().strip().replace(" ", "_")

    def find_link_relation_word(self, max_deps, nlp, dictionary):
        """
        It takes the current page, filters it by links, processes with spaCy NLP,
        loops over all NP chunks, checks if it is a link, and finds the relation word
        that links the current page to the link. It restricts the amount of relation words
        per link depending on the value of max_dependencies.
        """
        link_dependency = {}

        # Parses the text with the spaCy NLP that is passed through.
        doc = nlp(self.process_text())

        for chunk in doc.noun_chunks:
            # If the dependency type ends with "obj", it finds if there are
            # any links within the NP chunk.

            # If there are any links, it ensures they are complete links (i.e. not just
            # part of a link). After that, it'll add the link and dependency to the
            # {link, set of dependencies}.
            if chunk.root.dep_.endswith("obj") and chunk.root.head.text.isalpha():
                link = []
                dependency = self.rel_standardise(chunk.root.head.text)
                for word in chunk.text.split(" "):
                    if word in self.partial_links:
                        link.append(word)
                link = " ".join(link)
                if link in self.full_links and dictionary.check(dependency) and len(dependency) > 1:
                    if link in link_dependency:
                        if len(link_dependency[link]) >= max_deps:
                            # Finds the minimum length word in the set.
                            min_word = min(link_dependency[link], key=len)
                            # If the new dependency is bigger, we'll substitute it in.
                            if len(min_word) < len(dependency):
                                link_dependency[link].remove(min_word)
                                link_dependency[link].add(dependency)
                        else:
                            link_dependency[link].add(dependency)
                    else:
                        link_dependency[link] = {dependency}

        return link_dependency

    def infobox_link_dep(self):
        """
        Finds the Infobox template within a page, and returns any links present within
        the parameter value, along with the name of the parameter it originates from.
        """
        link_dependency = {}
        for template in self.templates:
            # Not always the first link in a page.
            if str(template.name).lower().startswith("infobox"):
                for param in template.params:
                    for link in param.value.filter_wikilinks():
                        link = link.title.split("#", 1)[0]
                        if not link.startswith("File:") and not link == title:
                            dependency = self.rel_standardise(str(param.name))
                            link_dependency[link] = {dependency}
        return link_dependency

if __name__ == "__main__":
    # Parses the arguments for input file.
    parser = argparse.ArgumentParser()
    parser.add_argument('input', type=str,
                        help='name of input filename')
    parser.add_argument('neo4j_address', type=str,
                        help='address of the neo4j server')
    parser.add_argument('neo4j_username', type=str,
                        help='username of neo4j server')
    parser.add_argument('neo4j_password', type=str,
                        help='neo4j db password')
    args = parser.parse_args()

    neoInst = Neo4JInterface(args.neo4j_address, args.neo4j_username, args.neo4j_password)
    # The file that will be processed.
    xmldoc = etree.parse(args.input)
    root = xmldoc.getroot()

    # Creates an instance of the en_US dictionary.
    dictionary = enchant.Dict("en_US")

    # Strips the tags of namespaces. Makes traversal easier.
    # We can still do this and be far more efficient than Minidom.
    for elem in root.iterdescendants():
        elem.tag = etree.QName(elem).localname

    # Creates an iterator for all the page elements, so I can iterate over them.
    itemlist = root.iterfind("page")

    # Setup and load spaCy model
    nlp = spacy.load("en_core_web_sm")

    print("Parsing file.")

    for item in itemlist:
        # Retrieves the page ID, title and page text.
        w_id = item.find('id').text
        title = item.find('title').text
        text = item.find('revision').find('text').text
        page_type = "Page"

        PageInst = Page(w_id, title, text)

        for template in PageInst.templates:
            # If the infobox is annotated with a type, use it as the page type
            if str(template.name).lower().startswith("infobox") and len(template.name) > 2:
                page_type = template.name.split(" ")[-1].capitalize()

        neoInst.print_create_page(w_id, title, text, page_type)

    print("Creating relationships")
    # As the iterator is reset, we'll instantiate it again.
    itemlist = root.iterfind("page")
    for item in itemlist:
        # Retrieves the page ID, title and page text.
        w_id = item.find('id').text
        title = item.find('title').text
        text = item.find('revision').find('text').text

        # Creates a page object
        PageInst = Page(w_id, title, text)
        # Finds links on each page, with a relation word that links them together.
        link_dependency = PageInst.find_link_relation_word(2, nlp, dictionary)
        info_link_dependency = PageInst.infobox_link_dep()

        # Overrides any links from the unstructured links with the structured links.
        for link in info_link_dependency:
            link_dependency[link] = info_link_dependency[link]

        # Writes it all into the database.
        for link in link_dependency:
            for relation in link_dependency[link]:
                neoInst.print_create_relationship(title, link, relation)
    neoInst.close()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Custom TabBar and TabWidget.
Tabs like ChromeOS for Python3 Qt5 with Extras like UnDock / ReDock Tabs,
Pin / UnPin Tabs, On Mouse Hover Previews for all Tabs except current Tab,
Colored Tabs, Change Position, Change Shape, Fading Transition effect,
Close all Tabs to the Right, Close all Tabs to the Left, Close all other Tabs,
Mouse Hover Tracking, Add Tab Plus Button, Limit Maximum of Tabs, and more.
"""

from PyQt5.QtCore import QEvent, QTimeLine, QTimer

from PyQt5.QtGui import QBrush, QColor, QCursor, QPainter, QRadialGradient

from PyQt5.QtWidgets import (QColorDialog, QDialog, QInputDialog, QLabel,
                             QMainWindow, QMenu, QMessageBox, QTabBar,
                             QTabWidget, QToolButton, QVBoxLayout)

##############################################################################

class FaderWidget(QLabel):

    """Custom Placeholder Fading Widget for tabs on TabWidget."""

    def __init__(self, parent):
        """Init class."""
        super(FaderWidget, self).__init__(parent)
        self.timeline, self.opacity, self.old_pic = QTimeLine(), 1.0, None
        self.timeline.valueChanged.connect(self.animate)
        self.timeline.finished.connect(self.close)
        self.timeline.setDuration(750)  # 500 ~ 750 Ms is Ok, Not more.

    def paintEvent(self, event):
        """Overloaded paintEvent to set opacity and pic."""
        painter = QPainter(self)
        painter.setOpacity(self.opacity)
        if self.old_pic:
            painter.drawPixmap(0, 0, self.old_pic)

    def animate(self, value):
        """Animation of Opacity."""
        self.opacity = 1.0 - value
        return self.hide() if self.opacity < 0.1 else self.repaint()

    def fade(self, old_pic, old_geometry, move_to):
        """Fade from previous tab to new tab."""
        if self.isVisible():
            self.close()
        if self.timeline.state():
            self.timeline.stop()
        self.setGeometry(old_geometry)
        self.move(1, move_to)
        self.old_pic = old_pic
        self.timeline.start()
        self.show()

class TabBar(QTabBar):

    """Custom tab bar."""

    def __init__(self, parent=None, *args, **kwargs):
        """Init class custom tab bar."""
        super(TabBar, self).__init__(parent=None, *args, **kwargs)
        self.parent, self.limit = parent, self.count() * 2
        self.menu, self.submenu = QMenu("Tab Options"), QMenu("Tabs")
        self.tab_previews = True
        self.menu.addAction("Tab Menu").setDisabled(True)
        self.menu.addSeparator()
        self.menu.addAction("Set Tab Text", self.set_text)
        self.menu.addAction("Set Tab Color", self.set_color)
        self.menu.addAction("Set Limits", self.set_limit)
        self.menu.addSeparator()
        self.menu.addAction("Change Tab Shape", self.set_shape)
        self.menu.addAction("Top or Bottom Position", self.set_position)
        self.menu.addAction("Pin or Unpin Tab", self.set_pinned)
        self.menu.addAction("Undock Tab", self.make_undock)
        self.menu.addAction("Toggle Tabs Previews", self.set_tab_previews)
        self.menu.addSeparator()
        self.menu.addAction("Close this Tab",
                            lambda: self.removeTab(self.currentIndex()))
        self.menu.addAction("Close all Tabs to the Right",
                            self.close_all_tabs_to_the_right)
        self.menu.addAction("Close all Tabs to the Left",
                            self.close_all_tabs_to_the_left)
        self.menu.addAction("Close all other Tabs", self.close_all_other_tabs)
        self.menu.addSeparator()
        self.menu.addMenu(self.submenu)
        self.menu.aboutToShow.connect(self.build_submenu)
        self.tabCloseRequested.connect(
            lambda: self.removeTab(self.currentIndex()))
        self.setMouseTracking(True)
        self.installEventFilter(self)

    def eventFilter(self, obj, event):
        """Custom Events Filder for detecting clicks on Tabs."""
        if obj == self:
            if event.type() == QEvent.MouseMove:
                index = self.tabAt(event.pos())
                self.setCurrentIndex(index)
                return True
            else:
                return QTabBar.eventFilter(self, obj, event)  # False
        else:
            return QMainWindow.eventFilter(self, obj, event)

    def mouseDoubleClickEvent(self, event):
        """Handle double click."""
        self.menu.exec_(QCursor.pos())

    def set_tab_previews(self):
        """Toggle On/Off the Tabs Previews."""
        self.tab_previews = not self.tab_previews
        return self.tab_previews

    def close_all_tabs_to_the_right(self):
        """Close all tabs to the Right."""
        for i in range(self.currentIndex() + 1, self.count()):
            if self.count() > 2:
                self.removeTab(self.count() - 1)

    def close_all_tabs_to_the_left(self):
        """Close all tabs to the Left."""
        for i in range(self.currentIndex()):
            if self.count() > 2:
                self.removeTab(0)

    def close_all_other_tabs(self):
        """Close all other tabs."""
        self.close_all_tabs_to_the_right()
        self.close_all_tabs_to_the_left()

    def make_undock(self):
        """Undock Tab from TabWidget to a Dialog,if theres more than 2 Tabs."""
        msg = "Needs more than 2 Tabs to allow Un-Dock Tabs !."
        return self.parent.make_undock() if self.count(
            ) > 2 else QMessageBox.warning(self, "Error", msg)

    def set_shape(self):
        """Handle set Shape on Tabs."""
        self.parent.setTabShape(0 if self.parent.tabShape() else 1)

    def set_position(self):
        """Handle set Position on Tabs."""
        self.parent.setTabPosition(0 if self.parent.tabPosition() else 1)

    def set_text(self):
        """Handle set Text on Tabs."""
        text = str(QInputDialog.getText(
            self, "Tab Options Dialog", "Type Tab Text:",
            text=self.tabText(self.currentIndex()))[0]).strip()[:50]
        if text:
            self.setTabText(self.currentIndex(), text)

    def set_color(self):
        """Handle set Colors on Tabs."""
        color = QColorDialog.getColor()
        if color:
            self.setTabTextColor(self.currentIndex(), color)

    def set_pinned(self):
        """Handle Pin and Unpin Tabs."""
        index = self.currentIndex()
        if self.tabText(index) == "":
            self.setTabText(index, self.tabToolTip(index))
            self.tabButton(index, 1).show()
        else:
            self.setTabToolTip(index, self.tabText(index))
            self.setTabText(index, "")
            self.tabButton(index, 1).hide()

    def build_submenu(self):
        """Handle build a sub-menu on the fly with the list of tabs."""
        self.submenu.clear()
        self.submenu.addAction("Tab list").setDisabled(True)
        for index in tuple(range(self.count())):
            action = self.submenu.addAction("Tab {0}".format(index + 1))
            action.triggered.connect(
                lambda _, index=index: self.setCurrentIndex(index))

    def set_limit(self):
        """Limit the Maximum number of Tabs that can coexist, TBD by Dev."""
        limit = int(QInputDialog.getInt(
            self, "Tab Options Dialog", "How many Tabs is the Maximum ?:",
            self.count() * 2, self.count() * 2, 99)[0])
        if limit:
            self.limit = limit
            return limit

class TabWidget(QTabWidget):

    """Custom tab widget."""

    def __init__(self, parent=None, *args, **kwargs):
        """Init class custom tab widget."""
        super(TabWidget, self).__init__(parent=None, *args, **kwargs)
        self.parent, self.previews, self.timer = parent, [], QTimer(self)
        self.fader, self.previous_pic = FaderWidget(self), None
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(lambda: [_.close() for _ in self.previews])
        self.setTabBar(TabBar(self))
        self.setMovable(False)
        self.setTabsClosable(True)
        self.setTabShape(QTabWidget.Triangular)
        self.addtab, self.menu_0 = QToolButton(self), QToolButton(self)
        self.addtab.setText(" + ")
        self.addtab.setToolTip("Add Tabs")
        self.menu_0.setText(" ? ")
        self.menu_0.setToolTip("Menu")
        font = self.addtab.font()
        font.setBold(True)
        self.addtab.setFont(font)
        self.menu_0.setFont(font)
        # self.addtab.clicked.connect(self.addTab)
        # self.menu_0.clicked.connect(self.show_menu)
        self.setCornerWidget(self.addtab, 1)
        self.setCornerWidget(self.menu_0, 0)

##############################################################################

if __name__ in '__main__':
    from PyQt5.QtWidgets import QApplication, QCalendarWidget
    app = QApplication([])
    gui = TabWidget()
    for i in range(9):
        gui.addTab(QLabel("
Tab {0} !".format(i))
                   if i % 2 else QCalendarWidget(), " Tab {0} ! ".format(i))
    gui.show()
exit(app.exec_())


from PyQt5 import uic
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QProgressBar
from  PyQt5.QtWidgets import QFileDialog
from  PyQt5.QtWidgets import QSizePolicy
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSignal

import sys
import re
import numpy as np
import MO_Func as mof

class Appmap(QWidget):
    sig_log=pyqtSignal(list)
    xlist=[]
    ylist=[]
    zlist=[]
    replaced_list=[]
    def __init__(self,mainthread):
        super().__init__()
        self.mainthread=mainthread
        self.UILoader()
        self.Restyle()
        self.SignalSlotBinding()
        self.show()
#——————————————————————————————————#
    def UILoader(self):
        self.ui=uic.loadUi('PI_GUI_App_Map.ui',self)
    def Restyle(self):
        self.setWindowTitle('Approach Curve-Map')
        with open(r'appmap_his.txt','r') as file:
            history=file.readlines()
        self.lineEdit_xp.setText(history[0])
        self.lineEdit_yp.setText(history[1])
        self.lineEdit_monitee.setText(history[2])
        self.lineEdit_stbr.setText(history[3])
        # self.lineEdit_xp.setText('0')
        # self.lineEdit_yp.setText('0')
        self.combo_zp.addItem('450,350,300,250,200,150,125,100,90,80,70,60,50,45,40,35,30,25,20,15,10,8,6,4,2,0')
        self.combo_zp.addItem('0,2,4,6,8,10,15,20,25,30,35,40,45,50,60,70,80,90,100,125,150,200,250,300,350,450')
        self.combo_zp.setCurrentText(self.combo_zp.itemText(0))
        # self.lineEdit_monitee.setText(r'C:\Users\jy1u18\OneDrive - University of Southampton\PhD\Second Project\Electrochemistry')
        # self.lineEdit.setText('dis,dis')
    def SignalSlotBinding(self):
        self.checkBox.clicked.connect(self.RenameSwitch)
        self.proceed.clicked.connect(self.StartExp)
        self.toolButton.clicked.connect(self.FileBrowser)

##### GUI Slots
    def RenameSwitch(self):
        if self.checkBox.isChecked():
            self.label_3.setEnabled(True)
            self.lineEdit_stbr.setEnabled(True)
        else:
            self.label_3.setEnabled(False)
            self.lineEdit_stbr.setEnabled(False)

    def StartExp(self):
        permission=False
        self.SaveRecord()
        permission=self.StatusCheck()
        if permission==True:
            self.ExpMonitor()
            if self.checkBox.isChecked():
                self.RenameMonitor()

    def SaveRecord(self):
        file=open(r'appmap_his.txt','w')
        file.close()
        with open(r'appmap_his.txt','a') as file:
            for widget in [self.lineEdit_xp, self.lineEdit_yp,self.lineEdit_monitee,self.lineEdit_stbr]:
                text=widget.text()
                file.write(text)

    def StatusCheck(self):
        try:
            self.mainthread.ServoCheck()
            self.list_read(widget=self.lineEdit_xp,tlist=self.xlist,ty=int)
            self.list_read(widget=self.lineEdit_yp,tlist=self.ylist,ty=int)
            self.list_read(widget=self.combo_zp,tlist=self.zlist,ty=int)
            self.num3d=len(self.xlist)*len(self.ylist)*len(self.zlist)
            self.num2d=len(self.xlist)*len(self.ylist)
            self.filename=self.lineEdit_monitee.text().rstrip()
            print(self.filename)
            self.list_read(widget=self.lineEdit_stbr,tlist=self.replaced_list,ty=str)
            self.count_file=self.filename+r'\count.txt'
            return True
        except Exception as arg_err:
            if arg_err==FileNotFoundError:
                self.mainthread.LogWriter('Create a count.txt file in the target directory first.')
                self.mainthread.LogWriter(arg_err)
            elif arg_err==ValueError('qSVO of a device returned False'):
                self.mainthread.LogWriter('Turn on servo of each axis first.')
                self.mainthread.LogWriter(arg_err)
            else:
                self.mainthread.LogWriter('Unknown Error.')
                self.mainthread.LogWriter(arg_err)

    def ExpMonitor(self):
        self.ProgressBar()
        self.mon_thrd=mof.ExpMonitor(self.mainthread,self.xlist,self.ylist,self.zlist,self.num3d,self.count_file)
        self.mainthread.threadlist.append(self.mon_thrd)
        self.mon_thrd.sig_ascent.connect(self.Signal_Ascent)
        self.mon_thrd.sig_complete.connect(self.ExpComplete)
        self.mon_thrd.sig_progressbar.connect(self.progressbar.setValue)
        # self.mon_thrd.sig_error.connect(lambda: self.msgrunning.cancel())
        self.mon_thrd.start()
        self.proceed.setEnabled(False)

    def RenameMonitor(self):
        self.rename_thrd=mof.RenameMonitor(self.mainthread,self.filename,self.replaced_list,self.zlist)
        self.mainthread.threadlist.append(self.rename_thrd)
        self.rename_thrd.start()

    def FileBrowser(self):
        path=self.lineEdit_monitee.text()
        self.filename=QFileDialog.getExistingDirectory(None,'Monitor Folder',path)
        if self.filename=='':
            pass
        else:
            self.lineEdit_monitee.setText(self.filename)

##### Monitor Thread Slots
    def ThreadError(self,string):
        self.thread_error=QMessageBox()
        self.thread_error.setIcon(QMessageBox.Warning)
        self.thread_error.setText(string)
        self.thread_error.setStandardButtons(QMessageBox.Ok)
        self.thread_error.setWindowTitle('Error')
        self.thread_error.show()

    def Signal_Ascent(self,paraset):
        index=paraset[0]
        step=paraset[1]
        if paraset[1]==0:
            vel=0.001
        elif paraset[1]>0.1:
            vel=float(format(np.abs(paraset[1]/2),'.4f'))
        else:
            vel=float(format(np.abs(paraset[1]),'.4f'))
        self.mainthread.MoveTo(index,step,vel)

    def ExpComplete(self):
        self.mainthread.LogWriter('Experiments done!')
        try:
            self.mon_thrd.terminate()
            self.rename_thrd.terminate()
        except Exception as arg_err:
            self.mainthread.LogWriter('Thread Terminating Error: ')
            self.mainthread.LogWriter(arg_err)
        self.proceed.setEnabled(True)
        self.progressbar.deleteLater()
        self.progresslabel.deleteLater()
        QApplication.processEvents()

    def ProgressBar(self):
        self.progressbar=QProgressBar()
        self.progressbar.setValue(0)
        self.progressbar.setAlignment(Qt.AlignCenter)
        self.progresslabel=QLabel()
        self.progresslabel.setText(
            'Approach Curve experiments running. Do not close this window while running! '
            )
        self.progresslabel.setAlignment(Qt.AlignCenter)
        sizePolicy=QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        self.progresslabel.setSizePolicy(sizePolicy)

        self.verticalLayout.addWidget(self.progressbar)
        self.verticalLayout.addWidget(self.progresslabel)

##### Auxilary  Function
    def list_read(self,widget,tlist,ty=int):
        try:
            try:
                string=widget.text()
            except Exception:
                string=widget.currentText()
            res=[]
            element=string.split(",")
            sets=[]
            num=[]
            for ele in element:
                if '(' in ele:
                    sets.append(ele)
                else:
                    num.append(ty(ele))
            res+=list(map(ty, num))
            for i in sets:
                numset=re.findall(r'[(](.*?)[)]', i)
                rangepara=numset[0].split(' ')
                rangepara=list(map(ty, rangepara))
                res+=np.arange(rangepara[0],rangepara[1]+1,rangepara[2]).tolist()
            tlist[:]=res
        except Exception as arg_err:
            self.mainthread.LogWriter('Input parameter error:')
            self.mainthread.LogWriter(arg_err)
            self.reading_error=QMessageBox()
            self.reading_error.setIcon(QMessageBox.Critical)
            self.reading_error.setText('Potentially input error, please check your inputs\n See log widget for more infomation.')
            self.reading_error.setStandardButtons(QMessageBox.Ok)
            self.reading_error.setWindowTitle('Error')
            self.reading_error.show()
        return res

    def closeEvent(self,event):
        try:
            self.mon_thrd.terminate()
            self.rename_thrd.terminate()
            self.mainthread.LogWriter('Thread terminated.')
        except Exception as arg_err:
            if type(arg_err)!=AttributeError:
                self.mainthread.LogWriter(arg_err)

if __name__=='__main__':
    app = QApplication(sys.argv)
    win=QWidget()
    ui=Appmap(win)
    sys.exit(app.exec_())


import numpy as np
from collections import defaultdict
import random
# !pip3 install git+https://github.com/slremy/netsapi --user --upgrade
# from netsapi.challenge import *
from environment.challenge import *
# os.environ["http_proxy"] = "http://127.0.0.1:1081/"
# os.environ["https_proxy"] = "http://127.0.0.1:1081/"

class CEM(object):
    def __init__(self,env):
        self.env = env
        self.best_policy = None
        self.best_reward = -1e9
        self.policies = []
        self.rewards = []

    def choose_policy1m0(self):
        x = np.zeros((10))
        for i in range(5):
            r = np.random.uniform(0, 1)
            x[2*i] = r
            x[2*i+1] = 1 - r
        policy = {i+1: [float(x[i*2]), float(x[i*2+1])] for i in range(5)}
        return x, policy

    def choose_policy_uniform(self):
        x = np.random.uniform(size=(10))
        policy = {i+1: [float(x[i*2]), float(x[i*2+1])] for i in range(5)}
        return x, policy

    def encode(self, p):
        policy = {i+1: [float(p[i*2]), float(p[i*2+1])] for i in range(5)}
        return policy

    def choose_policy(self):
        if len(self.policies) < 10:
            # p = np.random.randint(0, 2, size=(10))
            # p, policy = self.choose_policy1m0()
            p = np.random.uniform(size=(10,))
            policy = self.encode(p)
        else:
            idx = np.argsort(np.array(self.rewards))
            hp = np.array(self.policies)[idx[-3:]]
            hr = np.array(self.rewards)[idx[-3:]]
            p = np.zeros((10,))
            print(self.rewards)
            print(hr)
            for i in range(10):
                mean = np.mean(hp[:, i])
                std = np.std(hp[:, i])
                p[i] = np.random.normal(mean, std)
                print(std)
            p = np.clip(p, 0, 1)
            policy = self.encode(p)
        return p, policy

    def update(self, p, reward):
        if reward > self.best_reward:
            self.best_policy = self.encode(p)
            self.best_reward = reward
        self.policies.append(p)
        self.rewards.append(reward)

    def train(self):
        for _ in range(20): #Do not change
            self.env.reset()
            p, policy = self.choose_policy()
            r = self.env.evaluatePolicy(policy)
            self.update(p, r)

    def generate(self):
        best_policy = None
        best_reward = -float('Inf')
        self.train()
        best_policy = self.best_policy
        best_reward = self.env.evaluatePolicy(best_policy)

        print(best_policy, best_reward)

        return best_policy, best_reward

EvaluateChallengeSubmission(ChallengeSeqDecEnvironment, CEM, "CEM4seqsubmission.csv")
EvaluateChallengeSubmission(ChallengeProveEnvironment, CEM, "CEM4prosubmission.csv")


# Opus/UrbanSim urban simulation software.
# Copyright (C) 2010-2011 University of California, Berkeley, 2005-2009 University of Washington
# See opus_core/LICENSE

import gc
import os
import sys
import shutil
import tempfile

from numpy import arange

from opus_core.variables.attribute_type import AttributeType
from opus_core.store.attribute_cache import AttributeCache
from opus_core.coefficients import Coefficients
from opus_core.storage_factory import StorageFactory
from opus_core.opus_package import OpusPackage
from opus_core.store.attribute_cache import AttributeCache
from opus_core.simulation_state import SimulationState
from opus_core.logger import logger

from opus_core.session_configuration import SessionConfiguration
from urbansim.datasets.gridcell_dataset import GridcellDataset

from biocomplexity.datasets.land_cover_dataset import LandCoverDataset
from biocomplexity.models.land_cover_change_model import LandCoverChangeModel
from biocomplexity.equation_specification import EquationSpecification
from biocomplexity.opus_package_info import package
from biocomplexity.constants import Constants
from biocomplexity.examples.lccm_runner_sample import LccmConfiguration
from biocomplexity.tools.lc_convert_to_flt2 import ConvertToFloat
from biocomplexity.tools.lc_convert2 import LCCMInputConvert
from opus_core.chunk_specification import ChunkSpecification

class Simulation(object):
    """ Import data from urbansim cache directory, and compute the following
    computed variables: devt, de, commden, house_den, comm_add and house_add.
    """

    package_path = OpusPackage().get_path_for_package("biocomplexity")
    #lct_attribute = "biocomplexity.land_cover.lct_recoded"
    lct_attribute = "lct"
    possible_lcts = range(1,15)

    def _clean_up_land_cover_cache(self, path):
        if os.path.exists(path):
            shutil.rmtree(path)

    def _get_previous_year(self, current_year, years):
        current_year_index = -1
        for i in range(len(years)):
            if current_year == years[i]:
                current_year_index = i
        if i <= 0 or i >= len(years):
            logger.log_error("invalid year " + str(current_year))
        return years[current_year_index-1]

    def _generate_input_land_cover(self, current_year, base_directory,
                         urbansim_cache_directory, years, output_directory,
                         convert_flt, convert_input):
        if current_year == years[0]:
            if not convert_input:
                return base_directory
            else:

                package_dir_path = package().get_package_path()
                command = os.path.join(package_dir_path, "tools", "lc_convert.py")
                status = os.system(command + ' %s -i "%s" -o "%s"' % ('input data',  base_directory, self.temp_land_cover_dir))
                assert(status == 0, "generate input failed")
                return self.temp_land_cover_dir

        previous_year = self._get_previous_year(current_year, years)

        if not convert_flt:
            logger.start_block("Copy data from %s to temp land cover folder" % urbansim_cache_directory)
            try:
                self._copy_invariants_to_temp_land_cover_dir(os.path.join(urbansim_cache_directory, str(previous_year)))
            finally:
                logger.end_block()
            return self.temp_land_cover_dir

#        package_dir_path = package().get_package_path()
#        command = os.path.join(package_dir_path, "tools", "lc_convert.py")
        flt_directory_in = os.path.join(output_directory, str(previous_year))
        flt_directory_out = self.temp_land_cover_dir
        LCCMInputConvert()._convert_lccm_input(flt_directory_in, flt_directory_out)
#        status = os.system(command + ' %d -i "%s" -o "%s"' % (previous_year, flt_directory_in, flt_directory_out))
#        assert(status == 0, "generate input failed")
        return self.temp_land_cover_dir

    def _get_max_index(self, land_cover_path):
        land_covers = LandCoverDataset(in_storage=StorageFactory().get_storage("flt_storage", storage_location=land_cover_path))
        return land_covers.size()

    def _copy_invariants_to_temp_land_cover_dir(self, land_cover_path):
        logger.log_status("temp input land cover data in " + self.temp_land_cover_dir)
        land_covers = LandCoverDataset(in_storage=StorageFactory().get_storage("flt_storage", storage_location=land_cover_path),
                                   out_storage=StorageFactory().get_storage("flt_storage", storage_location=self.temp_land_cover_dir),
                                   out_table_name='land_covers', debuglevel=4)
        logger.log_status("Land cover dataset created.... ") # added dec 4, 2009
        land_covers.flush_dataset() # added dec 4, 2009
        land_covers.write_dataset(attributes=AttributeType.PRIMARY)

    def _generate_output_flt(self, current_year, urbansim_cache_directory,
                              output_directory, convert_flt):
        if not convert_flt:
            return

        package_dir_path = package().get_package_path()
        command = os.path.join(package_dir_path, "tools", "lc_convert_to_flt.py")
        flt_directory_in = os.path.join(urbansim_cache_directory, str(current_year))
        flt_directory_out = os.path.join(output_directory, str(current_year))
        status = os.system(sys.executable + ' ' + command + ' %d -i "%s" -o "%s"' % (current_year, flt_directory_in, flt_directory_out))
        assert(status == 0, "generate output failed")

    def _generate_output_flt2(self, current_year, urbansim_cache_directory,
                             output_directory, convert_flt):
        if not convert_flt:
            return
        flt_directory_in = os.path.join(urbansim_cache_directory, str(current_year))
        flt_directory_out = os.path.join(output_directory, str(current_year))

        ConvertToFloat()._create_flt_file(current_year, flt_directory_in, flt_directory_out)

    def run(self, base_directory, urbansim_cache_directory, years, output_directory, temp_folder,
            coefficients_name, specification_name, convert_flt=True, convert_input=False):
        """ run the simulation
                base_directory: directory contains all years folder of lccm.
                urbansim_cache_directory: directory contains all years folder of urbansim cache.
                years: lists of year to run."""
        model = LandCoverChangeModel(self.possible_lcts, submodel_string=self.lct_attribute,
                                     choice_attribute_name=self.lct_attribute, debuglevel=4)
        coefficients = Coefficients()
        storage = StorageFactory().get_storage('tab_storage',
            storage_location=os.path.join(self.package_path, 'data'))
        coefficients.load(in_storage=storage, in_table_name=coefficients_name)
        specification = EquationSpecification(in_storage=storage)
        specification.load(in_table_name=specification_name)
        specification.set_variable_prefix("biocomplexity.land_cover.")
        constants = Constants()
        simulation_state = SimulationState()
        simulation_state.set_cache_directory(urbansim_cache_directory)
        attribute_cache = AttributeCache()
        SessionConfiguration(new_instance=True,
                             package_order=['biocomplexity', 'urbansim', 'opus_core'],
                             in_storage=AttributeCache())

        ncols = LccmConfiguration.ncols

        if temp_folder is None:
            self.temp_land_cover_dir = tempfile.mkdtemp()
        else:
            self.temp_land_cover_dir = temp_folder

        for year in years:
            land_cover_path = self._generate_input_land_cover(year, base_directory, urbansim_cache_directory,
                                                              years, output_directory, convert_flt, convert_input)
            #max_size = 174338406 (orig) - act. int: 19019944 (37632028 incl NoData)
            max_size = self._get_max_index(land_cover_path) # 1st instance of lc_dataset - but looks like a 'lite' version
            offset = min(LccmConfiguration.offset, max_size)
            s = 0
            t = offset
            while (s < t and t <= max_size):
                logger.log_status("Offset: ", s, t)
                index = arange(s,t)

                land_cover_cache_path=os.path.join(urbansim_cache_directory,str(year),'land_covers')
                self._clean_up_land_cover_cache(land_cover_cache_path)

                simulation_state.set_current_time(year)

                # 2nd instance of lc_dataset
                land_covers = LandCoverDataset(in_storage=StorageFactory().get_storage('flt_storage', storage_location=land_cover_path),
                                           out_storage=StorageFactory().get_storage('flt_storage', storage_location=land_cover_path),
                                           debuglevel=4)
                land_covers.subset_by_index(index)
#                land_covers.load_dataset()
                gridcells = GridcellDataset(in_storage=attribute_cache, debuglevel=4)

                agents_index = None
                model.run(specification, coefficients, land_covers, data_objects={"gridcell":gridcells,
                              "constants":constants, "flush_variables":True},
                              chunk_specification = {'nchunks':5}) ## chunk size set here
                land_covers.flush_dataset()
                del gridcells
                del land_covers

#                self._generate_output_flt(year, urbansim_cache_directory, output_directory, convert_flt)
                self._generate_output_flt2(year, urbansim_cache_directory, output_directory, convert_flt)

                if t >= max_size: break
                s = max(t-10*ncols,s)
                t = min(t+offset-10*ncols,max_size)

        # clean up temp storage after done simulation
        shutil.rmtree(self.temp_land_cover_dir)

if __name__ == "__main__":
    base_dir = r"O:\unix\projects\urbansim9\land_cover_change_model\LCCM_4County_converted/1995"
    urbansim_cache  = r"D:\urbansim_cache\2006_02_10__13_06"
    Simulation().run(base_dir, urbansim_cache, [2005])


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#~~~                            Python Functions                            ~~~#
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

# Topics Covered:
# - Using Functions
# - Defining Functions
# - Function Scope
# - Lambda Function Expressions

############################### Using Functions ###############################

# Function Vocabulary
#
# - run (execute inside of a statement)/ invoke / call
# - argument (values passed to a function)
# - return value (the value a function produces)

# We've already used some built-in functions

type('abc')
print('Hey there!')

# TODO: take a look at the code snippet below:
max([1, 2, 3])

# What is the function name? MAX
# Where is the function invocation? Gets the maximum number
# What is the return value? 3

# TODO: What will the output of the following code be? Why? Explain step-by-step
type(max([1, 2, 3]))
#   Type identifies the class. Integer. It seeks the maximum amoung these integers.

# TODO: What will the output of the following code be? Why?
type(max)
# shows that max is a function.

# What other built-in functions do you know?
# upper, lower, pow
############################## Defining Functions ##############################

# Function Vocabulary
#Function is a reusable piece of code that takes an input and gives output
# - Function Definition- INCREMENT: takes a number and returns the number plus one.
# - Function Name
# - Parameter
# - Function Body- indented  lines, guts of the function.

def increment(n):
    return n + 1

# TODO: What is the difference between the increment function above and the one below?
def increment(n):
    print(n + 1)

# increment(increment(3)) returns 5.
# substition model of evaluation
# a function invocation is replaced with its return value.

# TODO: define a function named is_weekend. This function should accept a string and return true if the string is either saturday or sunday, false otherwise.
is_weekend = ['M', 'T', 'W', 'R', 'F', 'SA', 'SU']
if is_weekend.startswith('S'):
    True
else:
    False

def is_weekend(some_day):
    some_day = some_day.lower()
    return some_day == 'saturday' or some_day == 'sunday'

# TODO: test out your is_weekend function with various values.

is_weekend('friday')
is_weekend('tuesday')
is_weekend('saturday')

# TODO: Use your is_weekend function in combination with input() and an if statement to prompt the user for a day of the week and tell them whether or not it is a weekend.

user_input = input('Please enter a weekday: ')
if is_weekend(user_input):
    print('It\s a weekend')
else:
    print('It\s a weekday.')
# TODO: Create a function named nonzero. It should accept a number and return true if the number is anythong other than zero, false otherwise.

nonzero = input('Type a number: ')
if input != 0:
    print('Nice')
else:
    print('Pahaha')

def nonzero(x):
    return x != 0
nonzero(123)

# TODO: Use your nonzero function in combination with the built-in input function and an if statement to prompt the user for a number and print a message displaying whether or not the number is zero.

user_input = int(input('please enter a number: '))
if nonzero(user_input):
    print('It is not zero!')
else:
    print('That\s a zero')

# TODO: Transfer the work you have done into a function named explain_nonzero. Calling this function should prompt the user and display the message as before.

def explain_nonzero():
    user_input = int(input('please enter a number: '))
    if nonzero(user_input):
        print('It is not zero!')
    else:
        print('That\s a zero')

## Default Parameter Values and Keyword Arguments ##

# - Positional Argument
# - Keyword Argument

def add(x, y):
    return x + y

def sayhello(name="Innis"):
    return f"Hello, {name}!"

# TODO: call the say hello function and don't pass any arguments
sayhello()
# TODO: call the say hello function and pass your name as a string argument both positionally and as a keyword argument.
sayhello("Nick")
sayhello(name="Nick")
## Docstrings ##
def sayhello(name="Innis"):
    "Provides a friendly greeting."
    return f"Hello, {name}!"

# Aside: built-in help with help() (or ? in ipython)

################################ Function Scope ################################
#
# - scope refers to defining variables inside/outside of functions
# - scope defines where a variable can be referenced
# - global and local scope

# TODO: look at the example below. What do expect will happen when you run it?
def f():
    x = 123
f()
print(x)

# TODO: look at the example below. What do expect will happen when you run it?
x = 123
def f():
    print(x)
f()

# TODO: look at the example below. What do expect will happen when you run it?
x = 123
def f(x):
    return x + 1
print(f(12))

# TODO: What is the difference between local and global scope? Which is preferred?

# TODO: Take a look at the code below. Before running it, think about what you would expect to happen. Explain step by step how the python code is executing.
def changeit(x):
    x = x + 1

x = 42
print(x)
changeit(x)
print(x)

## Function Scope Example ##
def fill_nulls(df):
    return df.fillna(0)

def drop_outliers(df):
    outlier_cutoff = 3
    return df[df.zscore().abs() < outlier_cutoff]

def prep_dataframe(df):
    df = fill_nulls(df)
    df = drop_outliers(df)
    return

# Data Prep example: https://github.com/CodeupClassroom/darden-nlp-exercises/blob/main/nlp_prepare.py
# The specifics here aren't important right now, just pay attention to the overall shape of functions and how local scope is used.

############################### Lambda Functions ###############################
#
# - A function as an expression
# - used for "throw away", or one-off, functions

def increment(n):
    return n + 1
# same as
increment = lambda n: n + 1

# lambda structure
# lambda --> (followed by) the thing --> : --> what the thing should do.

# Use case: sorting (min, max)
#
# Python doesn't know how to compare dictionaries, but it does know how to compare strings or numbers

students = [
    {"name": "Ada Lovelace", "grade": 87},
    {"name": "Thomas Bayes", "grade": 89},
    {"name": "Christine Darden", "grade": 99},
    {"name": "Annie Easley", "grade": 94},
    {"name": "Marie Curie", "grade": 97},
]

# sort by name
sorted(students, key=lambda s: s["name"])

# TODO: write the code necessary to sort by grade
sorted(students, key=lambda s: s["grade"])

# TODO: Write the code necessary to sort the list of student dictionaries by student last name.
sorted(students, key=lambda s: s["name"].split()[-1])
# Hint: You will need to write a function that takes in a student dictionary and returns just the last name.
# Hint: You can use the .split string method to seperate the first name and the last name.


"""Unit tests for nautobot_golden_config utilities helpers."""

import logging
from unittest.mock import MagicMock, patch

from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from django.template import engines
from jinja2 import exceptions as jinja_errors
from nautobot.dcim.models import Device, Platform, Location, LocationType
from nautobot.extras.models import DynamicGroup, GitRepository, GraphQLQuery, Status, Tag
from nornir_nautobot.exceptions import NornirNautobotException
from nautobot_golden_config.models import GoldenConfigSetting
from nautobot_golden_config.tests.conftest import create_device, create_helper_repo, create_orphan_device
from nautobot_golden_config.utilities.helper import (
    get_device_to_settings_map,
    get_job_filter,
    null_to_empty,
    render_jinja_template,
)

class HelpersTest(TestCase):  # pylint: disable=too-many-instance-attributes
    """Test Helper Functions."""

    def setUp(self):
        """Setup a reusable mock object to pass into GitRepo."""
        self.repository_obj = MagicMock()
        self.repository_obj.path = "/fake/path"
        GitRepository.objects.all().delete()
        create_helper_repo(name="backup-parent_region-1", provides="backupconfigs")
        create_helper_repo(name="intended-parent_region-1", provides="intendedconfigs")
        create_helper_repo(name="test-jinja-repo", provides="jinjatemplate")

        create_helper_repo(name="backup-parent_region-2", provides="backupconfigs")
        create_helper_repo(name="intended-parent_region-2", provides="intendedconfigs")
        create_helper_repo(name="test-jinja-repo-2", provides="jinjatemplate")

        create_helper_repo(name="backup-parent_region-3", provides="backupconfigs")
        create_helper_repo(name="intended-parent_region-3", provides="intendedconfigs")
        create_helper_repo(name="test-jinja-repo-3", provides="jinjatemplate")

        # Since we enforce a singleton pattern on this model, nuke the auto-created object.
        GoldenConfigSetting.objects.all().delete()

        self.content_type = ContentType.objects.get(app_label="dcim", model="device")

        dynamic_group1 = DynamicGroup.objects.create(
            name="test1 location site-4",
            content_type=self.content_type,
            filter={"location": ["Site 4"]},
        )
        dynamic_group2 = DynamicGroup.objects.create(
            name="test2 location site-4",
            content_type=self.content_type,
            filter={"location": ["Site 4"]},
        )
        dynamic_group3 = DynamicGroup.objects.create(
            name="test3 location site-all",
            content_type=self.content_type,
            filter={},
        )
        graphql_query = GraphQLQuery.objects.create(
            name="testing",
            query="""
              query ($device_id: ID!) {
                device(id: $device_id){
                  name
                }
              }
            """,
        )
        self.test_settings_a = GoldenConfigSetting.objects.create(
            name="test_a",
            slug="test_a",
            description="test_a",
            weight=1000,
            backup_repository=GitRepository.objects.get(name="backup-parent_region-1"),
            intended_repository=GitRepository.objects.get(name="intended-parent_region-1"),
            jinja_repository=GitRepository.objects.get(name="test-jinja-repo"),
            # Limit scope to orphaned device only
            dynamic_group=dynamic_group1,
            sot_agg_query=graphql_query,
        )

        self.test_settings_b = GoldenConfigSetting.objects.create(
            name="test_b",
            slug="test_b",
            description="test_b",
            weight=2000,
            backup_repository=GitRepository.objects.get(name="backup-parent_region-2"),
            intended_repository=GitRepository.objects.get(name="intended-parent_region-2"),
            jinja_repository=GitRepository.objects.get(name="test-jinja-repo-2"),
            # Limit scope to orphaned device only
            dynamic_group=dynamic_group2,
            sot_agg_query=graphql_query,
        )

        self.test_settings_c = GoldenConfigSetting.objects.create(
            name="test_c",
            slug="test_c",
            description="test_c",
            weight=1000,
            backup_repository=GitRepository.objects.get(name="backup-parent_region-3"),
            intended_repository=GitRepository.objects.get(name="intended-parent_region-3"),
            jinja_repository=GitRepository.objects.get(name="test-jinja-repo-3"),
            dynamic_group=dynamic_group3,
            sot_agg_query=graphql_query,
        )

        create_device(name="test_device")
        create_orphan_device(name="orphan_device")
        self.job_result = MagicMock()
        self.data = MagicMock()
        self.logger = logging.getLogger(__name__)
        self.device_to_settings_map = get_device_to_settings_map(queryset=Device.objects.all())

    def test_null_to_empty_null(self):
        """Ensure None returns with empty string."""
        result = null_to_empty(None)
        self.assertEqual(result, "")

    def test_null_to_empty_val(self):
        """Ensure if not None input is returned."""
        result = null_to_empty("test")
        self.assertEqual(result, "test")

    @patch("nautobot.dcim.models.Device")
    def test_render_jinja_template_success(self, mock_device):
        """Simple success test to return template."""
        worker = render_jinja_template(mock_device, "logger", "fake-template-contents")
        self.assertEqual(worker, "fake-template-contents")

    @patch("nautobot.dcim.models.Device")
    def test_render_jinja_template_success_render_context(self, mock_device):
        """Test that device object is passed to template context."""
        platform = "mock_platform"
        mock_device.platform = platform
        rendered_template = render_jinja_template(mock_device, "logger", "{{ obj.platform }}")
        self.assertEqual(rendered_template, platform)

    @patch("nautobot.dcim.models.Device")
    def test_render_jinja_template_success_with_filter(self, mock_device):
        """Test custom template and jinja filter are accessible."""
        rendered_template = render_jinja_template(mock_device, "logger", "{{ data | return_a }}")
        self.assertEqual(rendered_template, "a")

    @patch("nautobot.dcim.models.Device")
    def test_render_filters_work(self, mock_device):
        """Test Jinja filters are still there."""
        # This has failed because of import issues in the past, see #607 for an example failure and fix.
        self.assertIn("is_ip", engines["jinja"].env.filters)
        self.assertIn("humanize_speed", engines["jinja"].env.filters)
        rendered_template = render_jinja_template(mock_device, "logger", "{{ '10.1.1.1' | is_ip }}")
        self.assertEqual(rendered_template, "True")
        rendered_template = render_jinja_template(mock_device, "logger", "{{ 100000 | humanize_speed }}")
        self.assertEqual(rendered_template, "100 Mbps")

    @patch("nautobot_golden_config.utilities.logger.NornirLogger")
    @patch("nautobot.dcim.models.Device", spec=Device)
    def test_render_jinja_template_exceptions_undefined(self, mock_device, mock_nornir_logger):
        """Use fake obj key to cause UndefinedError from Jinja2 Template."""
        with self.assertRaises(NornirNautobotException):
            with self.assertRaises(jinja_errors.UndefinedError):
                render_jinja_template(mock_device, mock_nornir_logger, "{{ obj.fake }}")
        mock_nornir_logger.error.assert_called_once()

    @patch("nautobot_golden_config.utilities.logger.NornirLogger")
    @patch("nautobot.dcim.models.Device")
    def test_render_jinja_template_exceptions_syntaxerror(self, mock_device, mock_nornir_logger):
        """Use invalid templating to cause TemplateSyntaxError from Jinja2 Template."""
        with self.assertRaises(NornirNautobotException):
            with self.assertRaises(jinja_errors.TemplateSyntaxError):
                render_jinja_template(mock_device, mock_nornir_logger, "{{ obj.fake }")
        mock_nornir_logger.error.assert_called_once()

    @patch("nautobot_golden_config.utilities.logger.NornirLogger")
    @patch("nautobot.dcim.models.Device")
    @patch("nautobot_golden_config.utilities.helper.render_jinja2")
    def test_render_jinja_template_exceptions_templateerror(self, template_mock, mock_device, mock_nornir_logger):
        """Cause issue to cause TemplateError form Jinja2 Template."""
        with self.assertRaises(NornirNautobotException):
            with self.assertRaises(jinja_errors.TemplateError):
                template_mock.side_effect = jinja_errors.TemplateRuntimeError
                render_jinja_template(mock_device, mock_nornir_logger, "template")
        mock_nornir_logger.error.assert_called_once()

    def test_get_backup_repository_dir_success(self):
        """Verify that we successfully look up the path from a provided repo object."""
        device = Device.objects.get(name="test_device")
        backup_directory = self.device_to_settings_map[device.id].backup_repository.filesystem_path
        self.assertEqual(backup_directory, "/opt/nautobot/git/backup-parent_region-3")

        device = Device.objects.get(name="orphan_device")
        backup_directory = self.device_to_settings_map[device.id].backup_repository.filesystem_path
        self.assertEqual(backup_directory, "/opt/nautobot/git/backup-parent_region-2")

    def test_get_intended_repository_dir_success(self):
        """Verify that we successfully look up the path from a provided repo object."""
        device = Device.objects.get(name="test_device")
        intended_directory = self.device_to_settings_map[device.id].intended_repository.filesystem_path
        self.assertEqual(intended_directory, "/opt/nautobot/git/intended-parent_region-3")

        device = Device.objects.get(name="orphan_device")
        intended_directory = self.device_to_settings_map[device.id].intended_repository.filesystem_path
        self.assertEqual(intended_directory, "/opt/nautobot/git/intended-parent_region-2")

    def test_get_job_filter_no_data_success(self):
        """Verify we get two devices returned when providing no data."""
        result = get_job_filter()
        self.assertEqual(result.count(), 2)

    def test_get_job_filter_site_success(self):
        """Verify we get a single device returned when providing specific site."""
        result = get_job_filter(data={"location": Location.objects.filter(name="Site 4")})
        self.assertEqual(result.count(), 1)

    def test_get_job_filter_device_object_success(self):
        """Verify we get a single device returned when providing single device object."""
        result = get_job_filter(data={"device": Device.objects.get(name="test_device")})
        self.assertEqual(result.count(), 1)

    def test_get_job_filter_device_filter_success(self):
        """Verify we get a single device returned when providing single device filter."""
        result = get_job_filter(data={"device": Device.objects.filter(name="test_device")})
        self.assertEqual(result.count(), 1)

    def test_get_job_filter_tag_success(self):
        """Verify we get a single device returned when providing tag filter that matches on device."""
        result = get_job_filter(data={"tags": Tag.objects.filter(name="Orphaned")})
        self.assertEqual(result.count(), 1)

    def test_get_job_filter_tag_success_and_logic(self):
        """Verify we get a single device returned when providing multiple tag filter that matches on device."""
        device = Device.objects.get(name="orphan_device")
        device_2 = Device.objects.get(name="test_device")
        content_type = ContentType.objects.get(app_label="dcim", model="device")
        tag, _ = Tag.objects.get_or_create(name="second-tag")
        tag.content_types.add(content_type)
        device.tags.add(tag)
        device_2.tags.add(tag)
        # Default tag logic is an `AND` not and `OR`.
        result = get_job_filter(data={"tags": Tag.objects.filter(name__in=["second-tag", "Orphaned"])})
        self.assertEqual(device.tags.count(), 2)
        self.assertEqual(device_2.tags.count(), 1)
        self.assertEqual(result.count(), 1)

    def test_get_job_filter_status_success(self):
        """Verify we get a single device returned when providing status filter that matches on device."""
        result = get_job_filter(data={"status": Status.objects.filter(name="Offline")})
        self.assertEqual(result.count(), 1)

    def test_get_job_filter_multiple_status_success(self):
        """Verify we get a0 devices returned matching multiple status'."""
        result = get_job_filter(data={"status": Status.objects.filter(name__in=["Offline", "Failed"])})
        self.assertEqual(result.count(), 2)

    def test_get_job_filter_base_queryset_raise(self):
        """Verify we get raise for having a base_qs with no objects due to bad Golden Config Setting scope."""
        Platform.objects.create(name="Placeholder Platform")
        for golden_settings in GoldenConfigSetting.objects.all():
            dynamic_group = DynamicGroup.objects.create(
                name=f"{golden_settings.name} group",
                content_type=self.content_type,
                filter={"platform": ["placeholder-platform"]},
            )
            golden_settings.dynamic_group = dynamic_group
            golden_settings.validated_save()
        with self.assertRaises(NornirNautobotException) as failure:
            get_job_filter()
        self.assertEqual(failure.exception.args[0][:8], "`E3015:`")

    def test_get_job_filter_filtered_devices_raise(self):
        """Verify we get raise for having providing site that doesn't have any devices in scope."""
        location_type = LocationType.objects.create(name="New Location Type Site")
        Location.objects.create(name="New Site", status=Status.objects.get(name="Active"), location_type=location_type)
        with self.assertRaises(NornirNautobotException) as failure:
            get_job_filter(data={"location": Location.objects.filter(name="New Site")})
        self.assertEqual(failure.exception.args[0][:8], "`E3016:`")

    def test_get_job_filter_device_no_platform_raise(self):
        """Verify we get raise for not having a platform set on a device."""
        device = Device.objects.get(name="test_device")
        device.platform = None
        device.status = Status.objects.get(name="Active")
        device.validated_save()
        with self.assertRaises(NornirNautobotException) as failure:
            get_job_filter()
        self.assertEqual(failure.exception.args[0][:8], "`E3017:`")

    def test_device_to_settings_map(self):
        """Verify Golden Config Settings are properly mapped to devices."""
        test_device = Device.objects.get(name="test_device")
        orphan_device = Device.objects.get(name="orphan_device")
        self.assertEqual(self.device_to_settings_map[test_device.id], self.test_settings_c)
        self.assertEqual(self.device_to_settings_map[orphan_device.id], self.test_settings_b)
        self.assertEqual(get_device_to_settings_map(queryset=Device.objects.none()), {})


# Game classes
# import ZAJ_Blackjack.Classes
from ZAJ_Blackjack.Classes import Card
from ZAJ_Blackjack.Classes import Deck
from ZAJ_Blackjack.Classes import Player
# Game functions
from ZAJ_Blackjack.Game_Functions import eval_hand
from ZAJ_Blackjack.Game_Functions import prompt_player
from ZAJ_Blackjack.Game_Functions import place_bet

import os

# Welcome player, ask if want to play
print('Welcome to the (simplified) Blackjack game!!')
continue_game = prompt_player('Continue game')

if continue_game == 'No':
    pass

# If player chooses 'Yes'
elif continue_game == 'Yes':

    ## Get player's name ##
    player_name = input('Please enter your name:\n')

    ##### 0 - INITIALIZATIONS OF PLAYERS #####
    player = Player(player_name, 3000)
    print(f'{player.name} joined the game with ${player.money}')
    dealer = Player('Dealer', -1)

    ##### MAIN GAME LOOP #####
    while continue_game == 'Yes': # and (player.money>0)
        ## Clear the prompt ##
        #clear_output()  # Remember, this only works in jupyter!
        os.system('cls')

        ##### INITIALIZATIONS OF PLAYER'S HANDS #####
        player.hand = []
        dealer.hand = []

        ###############################
        ##### 1 - BEGIN NEW ROUND #####
        ###############################

        ## (1.a) Initialize deck and shuffle ##
        main_deck = Deck()
        main_deck.shuffle_deck()

        ## (1.b) Player places bet ##
        # Gets updated in Part 4
        player_bet = place_bet(player)
        player.cur_bet = player_bet

        ## (1.c) Dealer distributes 4 cards ##
        for i in range(2):
            player.receive_card(main_deck.deal_card())
            print(f'{player.name} received a card.')
            dealer.receive_card(main_deck.deal_card())
            print(f'{dealer.name} received a card.')
        print('\n')

        ## (1.d) Display initial hands##
        player.display_hand(True)
        dealer.display_hand(True)

        ## (1.e) Compute hand values and initialize state variables for loops below ##
        player_hand_val = eval_hand(player.hand)
        dealer_hand_val = eval_hand(dealer.hand)

        # Updated in Part 2
        player_bust = False

        # If player got a Blackjack, skip his turn
        if (player_hand_val == 21):
            print(f'{player.name} has a BLACKJACK!\n')
            player_turn = False
        elif (player_hand_val<21):
            player_turn = True

        ###############################
        ##### 2 - PLAYER'S TURN   #####
        ###############################

        ## SECOND GAME LOOP ##
        while player_turn and not player_bust:
            # There's a problem below. The player could have been dealt a Blackjack from beginning.

            ## (2.b) Prompt player for next move ##
            # Ask if player wants to hit or stand
            player_input = prompt_player('Next move')

            # If player stands
            if player_input == 'Stand':
                print(f'{player.name} stands.')

                # Break while loop
                player_turn = False

            ## (2.c) If player hits ##
            elif player_input == 'Hit':
                print(f'{player.name} hits.')

                # Player receives a new card
                player.receive_card(main_deck.deal_card())

                # Display new hand
                player.display_hand(False)

                ## (2.d) Player's current hand ##

                # Evaluate Player's current hand
                player_hand_val = eval_hand(player.hand)

                # If player is bust, announce and break loop
                if (player_hand_val > 21):
                    print(f'{player.name} is BUST!\n')
                    player_bust = True
                    player_turn = False

                # If player has a Blackjack, announce and break loop
                elif (player_hand_val == 21):
                    print(f'{player.name} has a BLACKJACK!\n')
                    player_turn = False

        ###############################
        ##### 3 - DEALER'S TURN   #####
        ###############################

        ## (3.a) Display Dealer's hand ##
        dealer_bust = False
        dealer.display_hand(False)
        dealer_hand_val = eval_hand(dealer.hand)

        ## (3.b) Decide if Dealer's turn ##
        # Dealer has a Blackjack
        if (dealer_hand_val == 21):
            print(f'{dealer.name} has a BLACKJACK!\n')
            dealer_turn = False

        # Player is bust, Dealer does nothing
        elif player_bust and (dealer_hand_val <21):
            dealer_turn = False

        # Dealer will hit
        elif (not player_bust) and (dealer_hand_val < 21) and (dealer_hand_val <= player_hand_val):
            dealer_turn = True

        ## (3.c) Start Dealer's HITTING loop ##
        # To enter this loop, must have player_bust = False
        while dealer_turn:
            # Deal new card to dealer
            dealer.receive_card(main_deck.deal_card())

            # Display Dealer's new hand
            dealer.display_hand(False)
            dealer_hand_val = eval_hand(dealer.hand)

            ## (3.d) Decide dealer_turn value ##
            # Dealer has a Blackjack, announce and break loop
            if (dealer_hand_val == 21):
                print(f'{dealer.name} has a BLACKJACK!\n')
                dealer_turn = False

            # Dealer is BUST, announce and break loop
            elif (dealer_hand_val > 21):
                print(f'{dealer.name} is BUST!\n')
                dealer_bust = True
                dealer_turn = False

            elif (dealer_hand_val < 21) and (dealer_hand_val <= player_hand_val):
                dealer_turn = True

        ###############################
        ##### 4 - DETERMINE WINNER   ##
        ###############################

        ## (4.a) PUSH cases ##
        if (player_hand_val==dealer_hand_val) or (player_bust and dealer_bust):
            print('PUSH!! No winner this round...\n')

            # Reinitialize player's bet (Just in case)
            player_bet =0
            player.cur_bet = 0

        ## (4.b) LOSING cases
        elif (player_bust or (player_hand_val<dealer_hand_val)) and (not dealer_bust):
            print(f'{player.name} has LOST!!\n')

            # Subtract player's bet from wallet
            player.lose_round()
            player_bet = 0
            player.cur_bet = 0

        ## (4.c) WINNING cases
        elif (dealer_bust or (player_hand_val>dealer_hand_val)) and (not player_bust):
            print(f'{player.name} has WON ${player_bet}!! Congratulations!!\n')

            # Subtract player's bet from wallet
            player.win_round()
            player_bet = 0
            player.cur_bet = 0

        ##### END OF ROUND - CHECK PLAYER'S WALLET AND ASK IF PLAYER WANTS TO CONTINUE #####
        print(f'{player.name} has ${player.money}.\n')
        if (player.money>0):
            continue_game = prompt_player('Continue game')
        elif (player.money == 0):
            print(f'{player.name} has no funds left. Game over.\n')
            continue_game = 'No'

print('Thank you! Please come again!')


from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.by import By

import time

import chromedriver_autoinstaller

# 크롬 자동 다운로드, 옵션 설정, 창 생성
def create_chrome():
    chromedriver_autoinstaller.install("./")
    chrome_options = Options()
    chrome_options.add_argument("--incognito")
    chrome_options.add_argument("start-maximized")
    chrome_options.add_argument("--no-sandbox")
    return WebDriver(options=chrome_options)

def openInstagram(url: str):

    # 크롬 창 생성
    driver = create_chrome()
    driver.implicitly_wait(10)

    # 인스타 URL로 이동
    driver.get(url)

    # 인스타 TEXT 추출
    text = driver.find_elements(By.XPATH, "//*[@class='_a9zr']")[0].text

    # 태그 추출
    tags = [i for i in text.split() if i.startswith("#")]

    # 태그 위치 추출
    indexList = []
    for tag in tags:
        indexList.append(text.index(tag))

    # 유니코드 범위 (이 범위를 벗어나면 이모티콘같은 특수 문자)
    SUPPORTED_RANGE_START = 0x0000
    SUPPORTED_RANGE_END = 0xFFFF

    # 특수 문자 제거할 패턴 설정
    special_chars = r"[!@#$%^&*()]"
    text = re.sub(special_chars, "", text)

    # 태그 위치를 기반으로 추출한 텍스트에서 태그를 제거해 rst에 저장
    i = 0
    rst = ""
    while i < len(text):
        try:
            s = text[i]

            # 태그 위치를 기반으로 추출한 텍스트에서 태그 제거
            for index in indexList:
                if i == index:
                    tag = tags[indexList.index(index)]
                    i += len(tag)

            if s != "#":
                # 유니코드 범위를 기반으로 이모티콘 제거
                code_point = ord(s)
                if SUPPORTED_RANGE_START <= code_point <= SUPPORTED_RANGE_END:
                    rst += s
                else:
                    pass

            i += 1
        except:
            i += 1
            pass

    print(rst)

# url format -> https://www.instagram.com/p/~
openInstagram("https://www.instagram.com/p/Ct8JehTPpNe/")


#set up turtle graphics
import turtle
t = turtle.Pen()
turtle.bgcolor("black")
# Set up a list of any 8 valid Python color names
colors = ("red", "yellow", "blue", "green", "orange", "purple", "white", "gray")
#Ask the user's name using turtle's textinput pop-up window
your_name = turtle.textinput("Enter your name", "What is your name?")
# Ask the user for the number os sides, between 1 and 8, with a default of 4
sides = int(turtle.numinput("Number of sides", "How many sides do you want (1-8)?", 4, 1, 8))
# Draw a colorful spiral with the user-specified number of sides
for x in range(100):
    # Only use the right number of colors
    t.pencolor(colors[x%sides%10])
    # don't draw regular spiral line
    t.penup()
    # Change the size to match number of sides
    t.forward(x*4)
    #write user's name
    t.pendown()
    t.write(your_name, font=("Arial", int((x*2 + 4)/4), "bold"))
    #Turn 360 degrees/number of sides,plus1
    t.left(360 / sides + 1)


from django.core.management.base import BaseCommand
import json
import subprocess

try:
    from boto.s3.connection import S3Connection
    from boto.s3.key import Key
except:
    pass

from django.conf import settings
import mimetypes
import os

def call_subprocess(command):
    proc = subprocess.Popen(command,
                        shell=True,
                        stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE,
                        )

def upload_to_s3(css_file):
    bucket_name = settings.AWS_BUCKET_NAME
    conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)

    folder = 'webpack_bundles/'
    bucket = conn.get_bucket(bucket_name=bucket_name)

    filename = css_file.split('/')[-1]
    file_obj = open(css_file, 'r')
    content = file_obj.read()

    key = folder + filename
    bucket = conn.get_bucket(bucket_name=bucket_name)
    mime = mimetypes.guess_type(filename)[0]
    k = Key(bucket)
    k.key = key  # folder + filename
    k.set_metadata("Content-Type", mime)
    k.set_contents_from_string(content)
    public_read = True
    if public_read:
        k.set_acl("public-read")

class Command(BaseCommand):
    args = '<filename>'
    help = 'Loads the initial data in to database'

    def handle(self, *args, **options):
        call_subprocess('./node_modules/.bin/webpack --config webpack.config.js')

        for each in settings.WEB_PACK_FILES:
            directory = settings.BASE_DIR + '/static/webpack_bundles/'
            css_file = max([os.path.join(directory, d) for d in os.listdir(directory) if d.startswith(each['webpack_js']) and d.endswith('css')], key=os.path.getmtime)
            js_file = max([os.path.join(directory, d) for d in os.listdir(directory) if d.startswith(each['webpack_js']) and d.endswith('js')], key=os.path.getmtime)

            if settings.ENABLE_DJANGO_WEBPACK_S3_STORAGES:
                upload_to_s3(css_file)
                upload_to_s3(js_file)

            import re
            regex = r'(.*?<link rel="stylesheet" type="text/css" href=")(.*?)(" id="packer_css"/>.*?<script id="packer_js" src=")(.*?)(" type="text/javascript"></script>.*)'

            with open(each['html_file_name'], 'r+') as f:
                content = f.read()
                m = re.match(regex, content, re.DOTALL)
                href = settings.STATIC_URL + css_file.split('/static/')[-1]
                src = settings.STATIC_URL + js_file.split('/static/')[-1]
                content = m.group(1) + href + m.group(3) + src + m.group(5)

            with open(each['html_file_name'], 'w') as f:
                f.write(content)

        result = {'message': "Successfully Created Compressed CSS, JS Files"}
        return json.dumps(result)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import numpy as np
from sklearn.linear_model import LinearRegression
import pandas as pd
import plotly.graph_objects as go
from sklearn import svm
from sklearn.model_selection import train_test_split
from app import app
from app import server

## Correction et ajout variables
df = pd.read_csv("data/carData.csv")

svar = ('Year', 'Owner','Selling_Price', 'Present_Price', 'Kms_Driven')
vquanti = ('Selling_Price', 'Present_Price', 'Kms_Driven')
vquali = ('Car_Name','Year','Fuel_Type', 'Seller_Type', 'Transmission')

app.layout = html.Div([

    html.Div([
        html.Div([
            html.H1(''' Analyse univariée ''')
            ]),

        html.Div([
            html.Div([
                html.H2(''' Variables qualitatives '''),
                html.Div([
                    html.Div('''Choisir une variable'''),
                    dcc.Dropdown(
                        id='vquali_choose',
                        options=[{'label': i, 'value': i} for i in vquali],
                        value='Year'
                    ),
                ],
                style={'width': '48%', 'display': 'inline-block'}),
                dcc.Graph(id='univariate_quali'),
            ]),

            html.Div([
                html.H2(''' Variables quantitatives '''),
                html.Div([
                    html.Div('''Choisir une variable'''),
                    dcc.Dropdown(
                        id='vquanti_choose',
                        options=[{'label': i, 'value': i} for i in vquanti],
                        value='Selling_Price'
                    ),
                ],
                style={'width': '48%', 'display': 'inline-block'}),
                dcc.Graph(id='univariate_quanti'),
                html.Div('''Les boxplots permettent de voir la répartition des données.
                    On voit d'un seul coup d'oeil où se situent le min, Q1, la médiane, Q3 et le max, ainsi que les valeurs extrêmes.
                '''),
            ]),
            ], style={'columnCount': 2,}
        ),
    ],
    ),

    html.Div([
        html.H1(''' Regression linéaire et SVM'''),
        html.Div([
            html.Div([
                html.Div([
                    html.Div('''Abscisse'''),
                    dcc.Dropdown(
                        id='xaxis-column',
                        options=[{'label': i, 'value': i} for i in svar],
                        value='Year'
                    ),
                ],
                style={'width': '48%', 'display': 'inline-block'}),

                html.Div([
                    html.Div('''Ordonnée'''),
                    dcc.Dropdown(
                        id='yaxis-column',
                        options=[{'label': i, 'value': i} for i in vquanti],
                        value='Selling_Price'
                    ),
                ],
                style={'width': '48%', 'display': 'inline-block'}
                ),
            ]),
        ]),

        html.Div([

            html.Div([
                html.H2(''' Regression linéaire univariée'''),
                html.Div(''' N'ayant observé aucune différence entre les différentes méthodes de régression linéaire univariée, la regression ci-dessous a été réalisé avec sklearn.
            '''),
                dcc.Graph(id='linear'),

            ]),

            html.Div([
                html.H2(''' SVM '''),
                dcc.Graph(id='svm'),
            ]),

        ],
        style={'columnCount': 2,} ),
        html.Div('''Différence entre regression linéaire univariée et SVR univariée : La SVR cherche a maximiser les marges.
        Alors que la régression linéaire cherche à minimiser les erreurs.

            '''),

    ]),

    # html.Div([
    #     html.Div([
    #         html.H1('''Regression linéaire multiple'''),
    #         html.Div([
    #         ], id = 'regmulti' ),
    #     ]),
    # ]),

    html.Div('''Question bonus - Quelles données manque-il à votre analyse ? -
    On pourrait regarder la date du contrôle technique et regarder s'il contient une ou plusieurs reparations à faire.
    On peut aussi se demander à quelle série appartient la voiture ?
    Est-ce que la voiture a t-elle été déjà accidentée ?
    Est-ce que la courroie de distribution a t-elle été changée ?
    ...
    Les données manquantes sont de ce fait, des données techniques sur la voiture.
            '''),

])

## Callback
@app.callback(
    Output('linear', 'figure'),
    [Input('xaxis-column', 'value'),
     Input('yaxis-column', 'value')])
def graph_reg(xvar, yvar):

    x = df[xvar].values.reshape(-1, 1)
    y = df[yvar].values

    X_train, X_test, y_train, y_test = train_test_split(x, y, train_size=0.8, random_state=0)

    model = LinearRegression().fit(x, y)

    x_range = np.linspace(x.min(), x.max(), 100)
    y_range = model.predict(x_range.reshape(-1, 1))

    fig = go.Figure([
        go.Scatter(x=X_train.squeeze(), y=y_train, name='train', mode='markers'),
        go.Scatter(x=X_test.squeeze(), y=y_test, name='test', mode='markers'),
        go.Scatter(x=x_range, y=y_range, name=('Y = %f.X + %f' %(model.coef_, model.intercept_)))
    ])
    fig.update_xaxes(title=xvar)
    fig.update_yaxes(title=yvar)

    return fig

@app.callback(
    Output('univariate_quali', 'figure'),
    [Input('vquali_choose', 'value')])
def graph_quali(var):
    fig = px.histogram(df, x=var)
    return fig

@app.callback(
    Output('univariate_quanti', 'figure'),
    [Input('vquanti_choose', 'value')])
def graph_quanti(var):
    fig = px.box(df, x=var)
    return fig

@app.callback(
    Output('svm', 'figure'),
    [Input('xaxis-column', 'value'),
     Input('yaxis-column', 'value')])
def graph_svm(xvar, yvar):

    x = df[xvar].values.reshape(-1, 1)
    y = df[yvar].values

    X_train, X_test, y_train, y_test = train_test_split(x, y, train_size=0.8, random_state=0)

    model =  svm.SVR(kernel="linear").fit(x, y)

    x_range = np.linspace(x.min(), x.max(), 100)
    y_range = model.predict(x_range.reshape(-1, 1))

    fig = go.Figure([
        go.Scatter(x=X_train.squeeze(), y=y_train, name='train', mode='markers'),
        go.Scatter(x=X_test.squeeze(), y=y_test, name='test', mode='markers'),
        go.Scatter(x=x_range, y=y_range, name=('Y = %f.X + %f' %(model.coef_, model.intercept_)))
    ])
    fig.update_xaxes(title=xvar)
    fig.update_yaxes(title=yvar)

    return fig

# @app.callback(Output('regmulti', 'children'))
# def graph_multi():
#     data = pd.DataFrame(df, columns=['Year','Kms_Driven', 'Selling_Price']),

#     col_transform = pd.DataFrame(df, columns=['Transmission'])
#     dummies = pd.get_dummies(col_transform)

#     xm = np.array(data.join(dummies))

#     ym = df['Selling_Price'].values

#     reg = LinearRegression().fit(xm, ym)
#     print('Sklearn multiple - Coefficients:', reg.coef_)
#     b1 = (reg.intercept_)

#     return  b1

####
if __name__ == '__main__':
    app.run_server(debug=True)