# Python
import pytest
from unittest import mock

# AWX
from awx.main.utils.filters import SmartFilter, ExternalLoggerEnabled

# Django
from django.db.models import Q

@pytest.mark.parametrize(
    'params, logger_name, expected',
    [
        # skip all records if enabled_flag = False
        ({'enabled_flag': False}, 'awx.main', False),
        # skip all records if the host is undefined
        ({'enabled_flag': True}, 'awx.main', False),
        # skip all records if underlying logger is used by handlers themselves
        ({'enabled_flag': True}, 'awx.main.utils.handlers', False),
        ({'enabled_flag': True, 'enabled_loggers': ['awx']}, 'awx.main', True),
        ({'enabled_flag': True, 'enabled_loggers': ['abc']}, 'awx.analytics.xyz', False),
        ({'enabled_flag': True, 'enabled_loggers': ['xyz']}, 'awx.analytics.xyz', True),
    ],
)
def test_base_logging_handler_skip_log(params, logger_name, expected, dummy_log_record):
    filter = ExternalLoggerEnabled(**params)
    dummy_log_record.name = logger_name
    assert filter.filter(dummy_log_record) is expected, (params, logger_name)

class Field(object):
    def __init__(self, name, related_model=None, __prevent_search__=None):
        self.name = name
        self.related_model = related_model
        self.__prevent_search__ = __prevent_search__

class Meta(object):
    def __init__(self, fields):
        self._fields = {f.name: f for f in fields}
        self.object_name = 'Host'
        self.fields_map = {}
        self.fields = self._fields.values()

    def get_field(self, f):
        return self._fields.get(f)

class mockObjects:
    def filter(self, *args, **kwargs):
        return Q(*args, **kwargs)

class mockUser:
    def __init__(self):
        print("Host user created")
        self._meta = Meta(fields=[Field(name='password', __prevent_search__=True)])

class mockHost:
    def __init__(self):
        print("Host mock created")
        self.objects = mockObjects()
        fields = [Field(name='name'), Field(name='description'), Field(name='created_by', related_model=mockUser())]
        self._meta = Meta(fields=fields)

@mock.patch('awx.main.utils.filters.get_model', return_value=mockHost())
class TestSmartFilterQueryFromString:
    @mock.patch('awx.api.filters.get_fields_from_path', lambda model, path: ([model], path))  # disable field filtering, because a__b isn't a real Host field
    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            ('facts__facts__blank=""', Q(**{u"facts__facts__blank": u""})),
            ('"facts__facts__ space "="f"', Q(**{u"facts__facts__ space ": u"f"})),
            ('"facts__facts__ e "=no_quotes_here', Q(**{u"facts__facts__ e ": u"no_quotes_here"})),
            ('a__b__c=3', Q(**{u"a__b__c": 3})),
            ('a__b__c=3.14', Q(**{u"a__b__c": 3.14})),
            ('a__b__c=true', Q(**{u"a__b__c": True})),
            ('a__b__c=false', Q(**{u"a__b__c": False})),
            ('a__b__c=null', Q(**{u"a__b__c": None})),
            ('ansible_facts__a="true"', Q(**{u"ansible_facts__contains": {u"a": u"true"}})),
            ('ansible_facts__a__exact="true"', Q(**{u"ansible_facts__contains": {u"a": u"true"}})),
            # ('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})),
            # ('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
        ],
    )
    def test_query_generated(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

    @pytest.mark.parametrize(
        "filter_string",
        [
            'ansible_facts__facts__facts__blank=ansible_facts__a__b__c__ space  =ggg',
        ],
    )
    def test_invalid_filter_strings(self, mock_get_host_model, filter_string):
        with pytest.raises(RuntimeError) as e:
            SmartFilter.query_from_string(filter_string)
        assert str(e.value) == u"Invalid query " + filter_string

    @pytest.mark.parametrize(
        "filter_string",
        [
            'created_by__password__icontains=pbkdf2search=foo or created_by__password__icontains=pbkdf2',
            'created_by__password__icontains=pbkdf2 or search=foo',
        ],
    )
    def test_forbidden_filter_string(self, mock_get_host_model, filter_string):
        with pytest.raises(Exception) as e:
            SmartFilter.query_from_string(filter_string)
        "Filtering on password is not allowed." in str(e)

    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            (u'(a=abc\u1F5E3def)', Q(**{u"a": u"abc\u1F5E3def"})),
            (u'(ansible_facts__a=abc\u1F5E3def)', Q(**{u"ansible_facts__contains": {u"a": u"abc\u1F5E3def"}})),
        ],
    )
    def test_unicode(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            ('(a=b)', Q(**{u"a": u"b"})),
            ('a=b and c=d', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})),
            ('(a=b and c=d)', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})),
            ('a=b or c=d', Q(**{u"a": u"b"}) | Q(**{u"c": u"d"})),
            ('(a=b and c=d) or (e=f)', (Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})) | (Q(**{u"e": u"f"}))),
            (
                'a=b or a=d or a=e or a=z and b=h and b=i and b=j and b=k',
                Q(**{u"a": u"b"})
                | Q(**{u"a": u"d"})
                | Q(**{u"a": u"e"})
                | Q(**{u"a": u"z"}) & Q(**{u"b": u"h"}) & Q(**{u"b": u"i"}) & Q(**{u"b": u"j"}) & Q(**{u"b": u"k"}),
            ),
        ],
    )
    def test_boolean_parenthesis(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            ('ansible_facts__a__b__c[]=3', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [3]}}}})),
            ('ansible_facts__a__b__c[]=3.14', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [3.14]}}}})),
            ('ansible_facts__a__b__c[]=true', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [True]}}}})),
            ('ansible_facts__a__b__c[]=false', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [False]}}}})),
            ('ansible_facts__a__b__c[]="true"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [u"true"]}}}})),
            ('ansible_facts__a__b__c[]="hello world"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [u"hello world"]}}}})),
            ('ansible_facts__a__b__c[]__d[]="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": [u"foobar"]}]}}}})),
            ('ansible_facts__a__b__c[]__d="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": u"foobar"}]}}}})),
            ('ansible_facts__a__b__c[]__d__e="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": u"foobar"}}]}}}})),
            ('ansible_facts__a__b__c[]__d__e[]="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": [u"foobar"]}}]}}}})),
            ('ansible_facts__a__b__c[]__d__e__f[]="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": {u"f": [u"foobar"]}}}]}}}})),
            (
                '(ansible_facts__a__b__c[]__d__e__f[]="foobar") and (ansible_facts__a__b__c[]__d__e[]="foobar")',
                Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": {u"f": [u"foobar"]}}}]}}}})
                & Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": [u"foobar"]}}]}}}}),
            ),
            # ('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})),
            # ('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
        ],
    )
    def test_contains_query_generated(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            # ('a__b__c[]="true"', Q(**{u"a__b__c__contains": u"\"true\""})),
            ('ansible_facts__a="true"', Q(**{u"ansible_facts__contains": {u"a": u"true"}})),
            # ('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})),
            # ('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
        ],
    )
    def test_contains_query_generated_unicode(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            ('ansible_facts__a=null', Q(**{u"ansible_facts__contains": {u"a": None}})),
            ('ansible_facts__c="null"', Q(**{u"ansible_facts__contains": {u"c": u"\"null\""}})),
        ],
    )
    def test_contains_query_generated_null(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

    @pytest.mark.parametrize(
        "filter_string,q_expected",
        [
            ('group__search=foo', Q(Q(**{u"group__name__icontains": u"foo"}) | Q(**{u"group__description__icontains": u"foo"}))),
            (
                'search=foo and group__search=foo',
                Q(
                    Q(**{u"name__icontains": u"foo"}) | Q(**{u"description__icontains": u"foo"}),
                    Q(**{u"group__name__icontains": u"foo"}) | Q(**{u"group__description__icontains": u"foo"}),
                ),
            ),
            (
                'search=foo or ansible_facts__a=null',
                Q(Q(**{u"name__icontains": u"foo"}) | Q(**{u"description__icontains": u"foo"})) | Q(**{u"ansible_facts__contains": {u"a": None}}),
            ),
        ],
    )
    def test_search_related_fields(self, mock_get_host_model, filter_string, q_expected):
        q = SmartFilter.query_from_string(filter_string)
        assert str(q) == str(q_expected)

'''
#('"facts__quoted_val"="f\"oo"', 1),
#('facts__facts__arr[]="foo"', 1),
#('facts__facts__arr_nested[]__a[]="foo"', 1),
'''


from __future__ import absolute_import

from builtins import next
from builtins import str
from qgis.PyQt.QtCore import Qt, pyqtSlot
from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox, QApplication
from qgis.core import QgsFeature, QgsFeatureRequest
from .Ui_SimOptimizerDlg import Ui_SimOptimizerDlg
from . import OptimizationFile
from . import SimControllerDlg
from . import anneal
import os
import math

class SimOptimizerDlg(QDialog):

    def __init__(self, iface):
        QDialog.__init__(self)
        # Set up the user interface from Designer.
        self.ui = Ui_SimOptimizerDlg()
        self.ui.setupUi(self)
        self.iface = iface
        self.mc = iface.mapCanvas()
        self.layers = self.mc.layers() #Only returns visible (active) layers
        self.ui.textSimulation.document().setMaximumBlockCount(500)
        self.ui.textOptimization.document().setMaximumBlockCount(500)
        self.ui.btnRun.setEnabled(False)

    @pyqtSlot()
    def on_btnBrowse_clicked(self):
        self.ui.btnRun.setEnabled(False)
        f, __ = QFileDialog.getOpenFileName(self,
                                        'Specify Simulation Optimization File:',
                                        os.getcwd(),
                                        '*.gso')

        if f != '':
            self.ofilename = f
            self.ui.tbxFile.setText(self.ofilename)
            os.chdir(os.path.dirname(str(f)))
            self.CheckOptimizationFile()

    @pyqtSlot()
    def on_tbxFile_editingFinished(self):
        self.ui.btnRun.setEnabled(False)
        self.ofilename = self.ui.tbxFile.text()
        self.CheckOptimizationFile()

    def CheckOptimizationFile(self):

        #Open optimization file
        if not os.path.exists(self.ofilename):
            QMessageBox.critical(self,'Simulation Optimizer','Optimization file does not exist.')
            return
        else:
            self.ofile = OptimizationFile.OptimizationFile()
            ret = self.ofile.ReadFile(self.ofilename)
            if ret:
                QMessageBox.critical(self,'Simulation Optimizer','Error reading optimization file.')
                return
            self.logfile = self.ofilename + '.log'
            f = open(self.logfile, 'w')
            f.close()

        #Check control file
        self.sim = SimControllerDlg.SimControllerDlg(self.iface)
        self.sim.cfilename = self.ofile.ControlFile
        if self.sim.CheckControlFile():
            return

        #Check base layer
        if self.ofile.BaseLayer != self.sim.cfile.BaseLayer:
            QMessageBox.warning(self,'Simulation Optimizer',
                                'Different base layers in control and optimization files.  Using control file base layer')

        #Check that optimization parameters are input attributes in the control file
        for key1 in sorted(self.ofile.OptAttributes.keys()):
            found = 0
            for key2 in sorted(self.sim.cfile.AttributeCode.keys()):
                if self.ofile.OptAttributes[key1][0] == self.sim.cfile.AttributeCode[key2][0]:
                    found = 1
                    break
            if not found:
                QMessageBox.critical(self,'Simulation Optimizer',
                                     'Optimization parameter not input attribute in control file: %s' % self.ofile.OptAttributes[key1][0])
                return

        #Check measured data attributes in the base layer
        for key in sorted(self.ofile.ObjAttributes.keys()):
            bfindx = self.sim.bprovider.fieldNameIndex(self.ofile.ObjAttributes[key][0])
            if bfindx < 0:
                QMessageBox.critical(self,'Simulation Optimizer',
                                     'Missing measured data attribute in base layer: %s' % self.ofile.ObjAttributes[key][0])
                return

        #Check that simulated data attributes are output attributes in the control file
        for key1 in sorted(self.ofile.ObjAttributes.keys()):
            found = 0
            for key2 in sorted(self.sim.cfile.AttributeType.keys()):
                if self.ofile.ObjAttributes[key1][1] == self.sim.cfile.AttributeType[key2][0]:
                    found = 1
                    break
            if not found:
                QMessageBox.critical(self,'Simulation Optimizer',
                                     'Simulated data attribute is not output attribute in control file: %s'
                                     % self.ofile.ObjAttributes[key1][1])
                return

        #Enable Run button
        self.ui.btnRun.setEnabled(True)

    @pyqtSlot()
    def on_btnRun_clicked(self):

        #Initializations
        b1 = 0
        self.ui.ProgressBar.setValue(0)
        self.setCursor(Qt.WaitCursor)
        featreq = QgsFeatureRequest()
        if self.ui.cbxOnlySelected.isChecked():
            self.selectedIDs = self.sim.blayer.selectedFeatureIds()
        else:
            self.selectedIDs = []
            for bfeat in self.sim.bprovider.getFeatures():
                self.selectedIDs.append(bfeat.id())
        self.selectedIDs.sort()
        b2 = len(self.selectedIDs)

        #Set up optimization and run
        x0 = []
        lower = []
        upper = []
        if self.ui.cbxDoGroup.isChecked():
            for key in sorted(self.ofile.OptAttributes.keys()):
                x0.append(float(self.ofile.OptAttributes[key][1]))
                lower.append(float(self.ofile.OptAttributes[key][2]))
                upper.append(float(self.ofile.OptAttributes[key][3]))

            string = 'Optimizing grouped features\n'
            string += 'Iter Temperature  Eval  Prob  Acc  Dec   BestEval    CurEval  Parameters....'
            f = open(self.logfile, 'a')
            f.write(string + '\n')
            f.close()
            self.ui.textOptimization.append(string)
            opt = Optimize(x0,lower,upper,T0=self.ofile.T0,Tf=self.ofile.Tf,dwell=self.ofile.dwell,
                           feps=self.ofile.feps,maxeval=self.ofile.maxeval,maxiter=self.ofile.maxiter,
                           maxaccept=self.ofile.maxaccept,m=self.ofile.m,n=self.ofile.n,
                           quench=self.ofile.quench,boltzmann=self.ofile.boltzmann)
            opt.init(self.sim, self.selectedIDs, self.ui, self.ofile, self.logfile, self.iface)
            solution = opt.run()
            self.UpdateGIS(solution, self.selectedIDs)
            self.WriteResult(solution)
            self.ui.ProgressBar.setValue(float(b2)/float(b2) * 100.0)

        else: #Run optimization for individual features

            for featid in self.selectedIDs:
                b1+=1
                x0[:] = []
                lower[:] = []
                upper[:] = []
                bfeat = next(self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
                for key in sorted(self.ofile.OptAttributes.keys()):
                    x0.append(float(self.ofile.OptAttributes[key][1]))
                    lower.append(float(self.ofile.OptAttributes[key][2]))
                    upper.append(float(self.ofile.OptAttributes[key][3]))

                string = 'Optimizing feature ID#: %d\n' % featid
                string += 'Iter Temperature  Eval  Prob  Acc  Dec   BestEval    CurEval  Parameters....'
                f = open(self.logfile, 'a')
                f.write(string + '\n')
                f.close()
                self.ui.textOptimization.append(string)
                opt = Optimize(x0,lower,upper,T0=self.ofile.T0,Tf=self.ofile.Tf,dwell=self.ofile.dwell,
                               feps=self.ofile.feps,maxeval=self.ofile.maxeval,maxiter=self.ofile.maxiter,
                               maxaccept=self.ofile.maxaccept,m=self.ofile.m,n=self.ofile.n,
                               quench=self.ofile.quench,boltzmann=self.ofile.boltzmann)
                opt.init(self.sim, [bfeat.id()], self.ui, self.ofile, self.logfile, self.iface)
                solution = opt.run()
                self.UpdateGIS(solution, [bfeat.id()])
                self.WriteResult(solution)
                self.ui.ProgressBar.setValue(float(b1)/float(b2) * 100.0)

        if self.ui.cbxOnlySelected.isChecked():
            self.sim.blayer.selectByIds(self.selectedIDs)
        else:
            self.sim.blayer.removeSelection()

        self.setCursor(Qt.ArrowCursor)

    def WriteResult(self, result):
        string = '%4d ' % result[0]
        string += '%11.5f ' % result[1]
        string += '%5d ' % result[2]
        string += '%5.3f ' % result[3]
        string += '%4d ' % result[4]
        string += '%4d ' % result[5]
        string += ('%10.4f ' % result[7])
        string += '           '
        for i in result[6]:
            string += '%10.4f ' % i
        string += '\nRMSE: ' + str(result[7]) + '\n'
        string += result[8]

        f = open(self.logfile, 'a')
        f.write(string + '\n\n')
        f.close()
        self.ui.textOptimization.append(string + '\n')

    def UpdateGIS(self, solution, bfeatids):

        bfeat = QgsFeature()
        featreq = QgsFeatureRequest()
        i=0
        attr={}
        for featid in bfeatids:
            i+=1
            attr.clear()
            bfeat = next(self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
            for key in sorted(self.ofile.OptAttributes.keys()):
                bfindx = self.sim.bprovider.fieldNameIndex(self.ofile.OptAttributes[key][0])
                ftype = str(self.sim.bprovider.fields()[bfindx].typeName())
                if ftype in ['Integer','Integer64']:
                    value = int(solution[6][key])
                elif ftype in ['Real', 'Double']:
                    value = float(solution[6][key])
                if int(self.ofile.OptAttributes[key][4]) in [0,i]:
                    attr.update({bfindx:value})
            result = self.sim.bprovider.changeAttributeValues({bfeat.id():attr})
            if not result:
                self.setCursor(Qt.ArrowCursor)
                QMessageBox.critical(self, 'Simulation Optimizer', 'Could not change attribute value2.')
                return
        self.sim.blayer.selectByIds(bfeatids)
        QApplication.processEvents()

        #Run simulations
        for featid in bfeatids:
            self.sim.ui.cbxOnlySelected.setChecked(1)
            self.sim.blayer.selectByIds([featid])
            self.sim.on_btnRun_clicked()
            self.ui.textSimulation.append(self.sim.p.stdout)
            self.ui.textSimulation.append(self.sim.p.stderr)

    @pyqtSlot()
    def on_btnExit_clicked(self):
        self.close()

class Optimize(anneal.Anneal):

    def init(self, sim, bfeatids, ui, ofile, logfile, iface):
        self.sim = sim
        self.bfeatids = list(bfeatids)
        self.ui = ui
        self.ofile = ofile
        self.logfile = logfile
        self.iface = iface

    def evaluate(self):

        #Write parameters to GIS
        bfeat = QgsFeature()
        featreq = QgsFeatureRequest()
        i=0
        attr = {}
        for featid in self.bfeatids:
            i+=1
            attr.clear()
            bfeat = next(self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
            for key in sorted(self.ofile.OptAttributes.keys()):
                bfindx = self.sim.bprovider.fieldNameIndex(self.ofile.OptAttributes[key][0])
                ftype = str(self.sim.bprovider.fields()[bfindx].typeName())
                if ftype in ['Integer','Integer64']:
                    value = int(self.current.x[key])
                elif ftype in ['Real', 'Double']:
                    value = float(self.current.x[key])
                if int(self.ofile.OptAttributes[key][4]) in [0,i]:
                    attr.update({bfindx:value})
            result = self.sim.bprovider.changeAttributeValues({bfeat.id():attr})
            if not result:
                self.setCursor(Qt.ArrowCursor)
                QMessageBox.critical(self, 'Simulation Optimizer', 'Could not change attribute value1.')
                return

        #Can't get attribute table repainting to work for all conditions.
        self.sim.blayer.selectByIds(self.bfeatids)
        QApplication.processEvents()

        #Run simulations
        for featid in self.bfeatids:
            self.sim.ui.cbxOnlySelected.setChecked(1)
            self.sim.blayer.selectByIds([featid])
            self.sim.on_btnRun_clicked()
            self.ui.textSimulation.append(self.sim.p.stdout)
            self.ui.textSimulation.append(self.sim.p.stderr)

        #Calculate error
        sqrerr = []
        for featid in self.bfeatids:
            bfeat = next(self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
            for key in sorted(self.ofile.ObjAttributes.keys()):
                measured = float(bfeat.attribute(self.ofile.ObjAttributes[key][0]))
                simulated = float(bfeat.attribute(self.ofile.ObjAttributes[key][1]))
                factor = float(self.ofile.ObjAttributes[key][2])
                error = (simulated - measured) * factor
                #error = (simulated - measured) / measured
                #error = (simulated - measured)
                sqrerr.append(error*error)

        sumsq = sum(sqrerr) / len(sqrerr)
        rmse = math.sqrt(sumsq)

        #Output
        string = '%4d ' % self.iterat
        string += '%11.5f ' % self.T
        string += '%5d ' % self.feval
        string += '%5.3f ' % self.p
        string += '%4d ' % self.accepted
        string += '%4d ' % self.declined
        if self.best.cost:
            string += ('%10.4f ' % self.best.cost)
        else:
            string += ('%10.4f ' % rmse)
        string += ('%10.4f ' % rmse)
        for i in self.best.x:
            string += '%10.4f ' % i
        for i in self.current.x:
            string += '%10.4f ' % i
        self.ui.textOptimization.append(string)
        f = open(self.logfile, 'a')
        f.write(string + '\n')
        f.close()

        return rmse

    def constrain(self):
        pass


from enum import Enum

from roid import (
    CommandsBlueprint,
    Response,
    ResponseFlags,
    Interaction,
    ButtonStyle,
    InvokeContext, Option,
)
from roid.objects import Channel, ChannelType, MemberPermissions as MemberPerms
from roid.helpers import check, require_user_permissions
from roid.exceptions import AbortInvoke, Forbidden, NotFound, DiscordServerError

from crunchy.app import CommandHandler
from crunchy.tools import assetloader
from crunchy.config import DISCORD_API, SUPPORT_SERVER_URL

REQUIRED_PERMISSIONS = MemberPerms.MANAGE_GUILD | MemberPerms.MANAGE_WEBHOOKS
NOT_ENOUGH_DATA = AbortInvoke(
    content="<:HimeSad:676087829557936149> Oops! You've not given me enough information to work with here.",
    flags=ResponseFlags.EPHEMERAL,
)

class EventType(Enum):
    """The type of event to register with the API."""

    News = "news"
    Releases = "releases"

events_blueprint = CommandsBlueprint()

async def get_webhook_url(
    app: CommandHandler,
    channel: Channel,
    sub_type: EventType,
) -> str:
    """
    Creates a webhook in the given channel and returns the computed URL
    from the response.

    Any issue with the request is returned with a roid.exception's HTTPException
    subclass.

    Args:
        app:
            The slash commands app which has a http handler.

        channel:
            The channel to target the webhook creation.

        sub_type:
            Which event type the webhook belongs to (news or releases).

    Returns:
        A formatted webhook execution url.
    """

    avatar = assetloader.get_base64_asset("crunchy-128.webp")
    data = await app.http.request(
        "POST",
        f"/channels/{channel.id}/webhooks",
        pass_token=True,
        json={
            "name": f"Crunchy Anime {sub_type.name}",
            "avatar": f"data:image/webp;base64,{avatar}",
        },
    )

    return f"{DISCORD_API}/webhooks/{data['id']}/{data['token']}"

async def submit_webhook(
    app: CommandHandler,
    sub_type: EventType,
    guild_id: int,
    webhook_url: str,
):
    """
    Submits a webhook to the Crunchy API.

    Args:
        app:
            The slash commands app with the client attribute linking to the CrunchyApi
            handler.

        sub_type:
            Which event type the webhook belongs to (news or releases).

        guild_id:
            The id of the guild the webhook belongs to.

        webhook_url:
            The url of the webhook.
    """
    payload = {
        "guild_id": str(guild_id),
        "webhook_url": webhook_url,
    }

    await app.client.request("POST", f"/events/{sub_type.value}/update", json=payload)

@require_user_permissions(REQUIRED_PERMISSIONS)
@events_blueprint.command(
    "add-news-channel",
    description=(
        "Add Crunchy's news webhook to a channel of "
        "your choice to get the latest Anime news."
    ),
    defer_register=False,
)
async def add_news_channel(
    app: CommandHandler,
    interaction: Interaction,
    channel: Channel = Option(channel_types=[ChannelType.GUILD_TEXT]),
) -> Response:
    url = await get_webhook_url(
        app=app,
        channel=channel,
        sub_type=EventType.News,
    )

    await submit_webhook(
        app=app,
        sub_type=EventType.News,
        guild_id=interaction.guild_id,
        webhook_url=url,
    )

    return Response(
        content=(
            f"<:exitment:717784139641651211> All done! I'll send"
            f" to <#{channel.id}> when I get some news."
        ),
        flags=ResponseFlags.EPHEMERAL,
        components=[[test_button]],
        component_context={"channel_id": channel.id, "webhook_url": url},
    )

@require_user_permissions(REQUIRED_PERMISSIONS)
@events_blueprint.command(
    "add-release-channel",
    description=(
        "Add Crunchy's release webhook to a channel of "
        "your choice to get the latest Anime release details."
    ),
    defer_register=False,
)
async def add_release_channel(
    app: CommandHandler,
    interaction: Interaction,
    channel: Channel = Option(channel_types=[ChannelType.GUILD_TEXT]),
) -> Response:
    url = await get_webhook_url(
        app=app,
        channel=channel,
        sub_type=EventType.Releases,
    )

    await submit_webhook(
        app=app,
        sub_type=EventType.Releases,
        guild_id=interaction.guild_id,
        webhook_url=url,
    )

    return Response(
        content=(
            f"<:exitment:717784139641651211> All done! I'll send to "
            f"<#{channel.id}> when a new Anime episode is out!"
        ),
        flags=ResponseFlags.EPHEMERAL,
        components=[[test_button]],
        component_context={"channel_id": channel.id, "webhook_url": url},
    )

@events_blueprint.button("ðŸš€ Test", style=ButtonStyle.PRIMARY, oneshot=True)
async def test_button(app: CommandHandler, ctx: InvokeContext):
    """
    A button that sends a test POST request to the webhook with a test message.

    If The request fails the error handler takes care of the responses otherwise
    it responds as a sucess.
    """
    try:
        channel_id = ctx["channel_id"]
        webhook_url = ctx["webhook_url"]
    except KeyError:
        return Response(
            content=(
                f"Oops! Something has gone awfully wrong in the (events:test_button:KeyError) handler, "
                f"please contact the developer @ {SUPPORT_SERVER_URL}"
            )
        )

    await app.http.request(
        "POST",
        f"{webhook_url}?wait=true",
        pass_token=False,
        json={"content": "ðŸš€ Testing, testing, I think we're ready!"},
    )

    return Response(
        content=f"I've sent a test message! If it appears in <#{channel_id}>",
        flags=ResponseFlags.EPHEMERAL,
    )

@test_button.error
async def on_button_error(_: Interaction, e: Exception):
    if isinstance(e, NotFound):
        return Response(
            content=(
                "<:HimeSad:676087829557936149> Weird!? This webhook seems to have "
                "been delete between me creating and you clicking the test button!"
            ),
            flags=ResponseFlags.EPHEMERAL,
        )

    if isinstance(e, DiscordServerError):
        return Response(
            content=(
                "<:HimeSad:676087829557936149> Oh no! Discord seem to be having some "
                "issues right now, this doesn't mean your event feed hasn't been "
                "added it just means we aren't able to test it right now."
            ),
            flags=ResponseFlags.EPHEMERAL,
        )

@add_news_channel.error
@add_release_channel.error
async def on_command_error(_: Interaction, e: Exception):
    if isinstance(e, Forbidden):
        return Response(
            content=(
                "<:HimeSad:676087829557936149> Oops! Looks like I'm missing permissions "
                "to do this. Make sure I have the permission `MANAGE_WEBHOOKS` and try again."
            ),
            flags=ResponseFlags.EPHEMERAL,
        )

    raise e


# Code (c) Andrew Balaschak, 2023
# Run program on 'movie-lens-data-small' folder to process a 50 movie dataset

import os
import numpy as np
import pandas as pd
import time
from scipy.spatial.distance import cosine

# Supress warning
from warnings import simplefilter
simplefilter(action="ignore", category=pd.errors.PerformanceWarning)

ROOT_DIR = os.path.dirname(__file__)
USE_SMALL_DATA = False

####################################################################################################
# a) Construct the profile of each item (i.e., movie). At the minimum, you should use the ratings given by each user for a given item (i.e., movie).
# Optionally, you can use other information (e.g., genre information for each movie and tag information given by user for each movie) creatively.
# If you use this additional information, you should explain your methodology in the submitted report.
start_time = time.time()
print("Loading Data...", end = " ")

# Read in the relevant csv files
if(USE_SMALL_DATA):
    movies = pd.read_csv(os.path.join(ROOT_DIR, 'movie-lens-data-small', 'movies.csv'), header=0, usecols=["movieId", "title"])
    ratings = pd.read_csv(os.path.join(ROOT_DIR, 'movie-lens-data-small', 'ratings.csv'), header=0)
else:
    movies = pd.read_csv(os.path.join(ROOT_DIR, 'movie-lens-data', 'movies.csv'), header=0, usecols=["movieId", "title"])
    ratings = pd.read_csv(os.path.join(ROOT_DIR, 'movie-lens-data', 'ratings.csv'), header=0)

# Merge the movies table with the ratings table
merged_movies = pd.merge(movies, ratings, on="movieId")

# Create table of userId and movie title with rating as value
movie_ratings = merged_movies.pivot_table(index='userId', columns='movieId', values='rating')
print("\t\t\t%s seconds" % (time.time() - start_time))

####################################################################################################
# b) Compute similarity score for all item-item (i.e., movie-movie) pairs.
# You will employ the centered cosine similarity metric that we discussed in class.
start_time = time.time()
print("Calculating Similarity...", end = " ")

# Center user's ratings
for i in range(movie_ratings.shape[0]):
    average_rating = np.nanmean(movie_ratings.iloc[i,:])
    movie_ratings.iloc[i,:] = movie_ratings.iloc[i,:] - average_rating
    movie_ratings.iloc[i,:] = movie_ratings.iloc[i,:].fillna(0)

# New dataframe for item-item similarity
movie_similarity = pd.DataFrame(index=movie_ratings.columns, columns=movie_ratings.columns)
movie_similarity = movie_similarity.fillna(0)

# Calculate cosine similarity
for i in range(0, movie_ratings.columns.size):
    for j in range(i, movie_ratings.columns.size):
        dot = np.dot(movie_ratings.iloc[:,i], movie_ratings.iloc[:,j])
        magnitude = np.linalg.norm(movie_ratings.iloc[:,i]) * np.linalg.norm(movie_ratings.iloc[:,j])
        movie_similarity.at[i+1,j+1] = dot/magnitude
        movie_similarity.at[j+1,i+1] = dot/magnitude

print("\t\t%s seconds" % (time.time() - start_time))
movie_similarity.to_csv(os.path.join(ROOT_DIR, 'similarity.csv'))

####################################################################################################
# c) Compute the neighborhood set N for each item (i.e. movie). You will select the movies that have highest similarity score for the given movie.
# Please employ a neigborhood of size 5. Break ties using lexicographic ordering over movie-ids.
start_time = time.time()
print("Calculating Neighborhood...", end = " ")

# New dataframe for neighborhood set
neighborhood_movieId = pd.DataFrame(index=movie_similarity.columns, columns=range(6))
neighborhood_similarity = pd.DataFrame(index=movie_similarity.columns, columns=range(6))

for i in range(0, movie_similarity.columns.size):
    neighborhood_movieId.iloc[i] = movie_similarity.iloc[0:,i].sort_values(ascending=False)[:6].index
    neighborhood_similarity.iloc[i] = movie_similarity.iloc[0:,i].sort_values(ascending=False)[:6]

# Since each movie is most similar to itself, drop the first column
neighborhood_movieId.drop(columns=neighborhood_movieId.columns[0], axis=1, inplace=True)
neighborhood_similarity.drop(columns=neighborhood_similarity.columns[0], axis=1, inplace=True)

print("\t\t%s seconds" % (time.time() - start_time))

####################################################################################################
# d) Estimate the ratings of other users who didn’t rate this item (i.e., movie) using the neighborhood set. Repeat for each item (i.e., movie).
start_time = time.time()
print("Estimating Ratings...", end = " ")

# Index = userId
# Column = movieId
# Value = estimated rating
estimated_ratings = pd.DataFrame(index=range(671), columns=range(1, movie_similarity.columns.size+1))
estimated_ratings.index.name = 'userId'
estimated_ratings.columns.name = 'movieId'
estimated_ratings = estimated_ratings.fillna(0)

print()
print(movie_ratings)

for i in range(0, movie_ratings.shape[0]):
    for j in range(0, movie_ratings.columns.size):
        if(movie_ratings.iloc[i,j] == 0):
            # Estimate rating for user i rating movie j
            numerator = 0
            denominator = 0
            for k in range(5):
                temp_movieId = neighborhood_movieId.at[j+1, k+1]
                numerator += movie_ratings.at[i+1, temp_movieId]
            denominator = neighborhood_similarity.iloc[[j]].sum(axis=1)[1]
            estimated_ratings.at[i,j] = numerator / denominator

print("\t\t\t%s seconds" % (time.time() - start_time))

####################################################################################################
# e) Compute the recommended items (movies) for each user. Pick the top-5 movies with highest estimated ratings.
# Break ties using lexicographic ordering over movie-ids.
# Your program should output top-5 recommendations for each user.
start_time = time.time()
print("Computing Recommendations...", end = " ")

# Now all we have to do here is sort the user's movie ratings and pick the top 5, just like with the neighborhood
for i in range(0, estimated_ratings.shape[0]):
    estimated_ratings.iloc[i] = estimated_ratings.iloc[0:,i].sort_values(ascending=False)[:6].index

print("\t\t%s seconds" % (time.time() - start_time))

print(estimated_ratings)
movie_similarity.to_csv(os.path.join(ROOT_DIR, 'estimated_ratings.csv'))


from __future__ import annotations
import openai
# from asyncstdlib import enumerate, sorted
from discord import Member, User, TextChannel, Thread, Message, Interaction, Embed, Color
from discord.ext.commands import Bot
from naruto.utils.config import Config
from dataclasses import dataclass
from typing import Union, List

@dataclass
class AIThread:
    op: Union[User, Member]
    topic: str
    channel: Thread

    async def close(self, interaction: Interaction) -> AIThread:
        await interaction.response.send_message("Closing...")
        await self.channel.delete()
        ThreadManager.threads.remove(self)
        return self

class ThreadManager:

    threads: List[AIThread] = []

    def __init__(self, bot: Bot) -> None:
        self.client = bot
        openai.api_key = Config.OPENAI_KEY

    async def last_messages(self, limit: int, channel: Thread) -> str:
        messages = channel.history(limit=limit)
        mystr = []
        iterable = [response async for response in messages if response.author.bot]
        for index, message in enumerate(reversed(iterable)):
            if index == 0:
                mystr.append(f'The first message, written by '
                             f'{"a person" if not message.author.bot else "you"}, says: "{message.content}"')
            else:
                print("occurred")
                mystr.append(f'This is the message after that message, written by '
                             f'{message.author.name if not message.author.bot else "you"}: "{message.content}"')
        return '; '.join(mystr[1:])

    async def conversate(self, message: Message, user: Union[User, Member], channel: Thread) -> str:
        thread = await self.client.fetch_channel(channel.id)
        can_respond = await self.can_respond(user, thread)
        text = await self.prompt_gen(can_respond, message, thread)

        return text

    async def prompt_gen(self, can_respond: bool, message: Message, thread: Thread) -> str:
        text_response = ""
        if can_respond:
            limit = 5 if thread.message_count >= 5 else thread.message_count
            memory = await self.last_messages(limit, thread)
            response = openai.Completion.create(
                engine=Config.MODEL,
                prompt=f"These messages are your memory: {memory}."
                       f"Please respond to the prompt: {message.content} as if you were {Config.CHARACTER}. "
                       f"Respond with less than 185 characters. "
                       f"Be friendly but serious in your responses, and act like {Config.CHARACTER} "
                       f"and naturally like them the character, "
                       f"because you ARE {Config.CHARACTER}.",
                max_tokens=2048,
                temperature=0.75
            )
            text_response = response.choices[0].text
        return text_response

    async def create_thread(self, user: Union[User, Member], topic: str, channel: TextChannel) -> AIThread:
        channel = await channel.create_thread(name=topic)
        embed = Embed(title="Naruto Thread", description=f"**Created by**: ``{user.name}``", color=Color.blue())
        await channel.send(embed=embed)
        thread = AIThread(user, topic, channel)
        self.threads.append(thread)
        return thread

    async def get_thread(self, channel: Thread) -> AIThread:
        for thread in self.threads:
            if thread.channel.id == channel.id:
                return thread

    async def can_respond(self, user: Union[User, Member], channel: Thread) -> bool:
        if not user.bot:
            for thread in self.threads:
                if channel.id == thread.channel.id:
                    return True
            return False

class AI:
    pass


def expanded_form(num):
    num = str(num)
    return " + ".join(str(item) for item in reversed([(int(number) * 10**power) for power,
            number in enumerate(reversed(num))]) if item != 0)

print(expanded_form(70834))

def expanded_form2(num):
    num = list(str(num))
    return " + ".join([i + ("0" *  (len(num) - 1 - r)) for r, i in enumerate(num) if int(i) != 0])
    # where ""0" *  (len(num) - 1 - to_deduct)" is clever manipulation
print(expanded_form2(70834))

contain = [number + 1 for number in range(100)]
print(contain)

container = [1000, 2200, 3345, 4345345, 523451130]


class Solution:
    def permute(self, nums):
        res = []
        self.dfs(nums, [], res)
        return res

    def dfs(self, num, path, res):
        if not num:
            res.append(path)
        else:
            for i in range(len(num)):
                self.dfs(num[:i]+num[i+1:], path+[num[i]], res)


# -*- coding: utf-8 -*-
"""
Created on Tue Jun 29 10:11:23 2021

@author: leona
"""
import numpy as np
import matplotlib.pyplot as plt
import cv2

img = cv2.imread("./Fotos/image3d.jpg")
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
imgg = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
imgg = np.float32(imgg)

imgs = np.zeros((1280,1280))

row, cols = imgs.shape
imgs[:,:] = 255

for i in np.arange(0,1300,200):
    imgs[:,i] = 0
    imgs[i,:] = 0

plt.figure(2)
plt.imshow(np.uint8(imgs), cmap='gray')

mean = 0.0   # some constant
std = 200    # some constant (standard deviation)
noisy_img = img + np.random.normal(mean, std, img.shape)
# noisy_img_clipped = np.uint8(np.clip(noisy_img, 0, 255) )

# img[dist]=[0,0,255]
plt.figure(1)
plt.imshow(np.uint8(noisy_img))
plt.show()

imgg = imgs
imgg = np.float32(imgg)
Sx = np.array([[-1, 0, 1], [-2, 0, 2],[-1, 0, 1]])
Sy = np.array([[-1, -2, -1], [0, 0, 0],[1, 2, 1]])

Ix = cv2.filter2D(imgg, -1, Sx)
Iy = cv2.filter2D(imgg, -1, Sy)

# Ix = cv2.Sobel(imgg,cv2.CV_64F,1,0,ksize=3)  # x
# Iy = cv2.Sobel(imgg,cv2.CV_64F,0,1,ksize=3)  # y

Ixx = Ix*Ix
Iyy = Iy*Iy
Ixy = Ix*Iy

Sxx = cv2.GaussianBlur(Ixx,(5,5), cv2.BORDER_DEFAULT)
Syy = cv2.GaussianBlur(Iyy,(5,5), cv2.BORDER_DEFAULT)
Sxy = cv2.GaussianBlur(Ixy,(5,5), cv2.BORDER_DEFAULT)

r, c = imgg.shape
k = 0.04

R = (Sxx*Syy - Sxy*Sxy) - k*((Sxx + Syy)**2)

# R = np.zeros((r,c))
# for i in np.arange(0,r):
#     for j in np.arange(0,c):
#         M = [[Sxx[i,j], Sxy[i,j]], [Sxy[i,j],Syy[i,j]]]
#         R[i,j] = np.linalg.det(M) - k*((np.trace(M))**2)

# aa = np.zeros((r,c))
# aa[R>0.04*R.max()]=[255]

# t = 10
# dist = np.full((r, c), True, dtype=bool)

# for i in np.arange(0,r):
#     for j in np.arange(0,c):

#         dist[i:i+t, j:j+t] = R[i:i+t, j:j+t] >= (R[i:i+t, j:j+t].max())

imgt = imgg
imgt[R>0.04*R.max()]=[255]
# img[dist]=[0,0,255]
plt.figure(0)
plt.imshow(imgt, cmap = 'gray')
plt.show()

mean = 0.0   # some constant
std = 200    # some constant (standard deviation)
noisy_img = img + np.random.normal(mean, std, img.shape)
# noisy_img_clipped = np.uint8(np.clip(noisy_img, 0, 255) )

# img[dist]=[0,0,255]
plt.figure(1)
plt.imshow(np.uint8(noisy_img))
plt.show()

# u = [0,0]
# p0 = [0,0]
# p1 = [x,y]

# p1 = u + t*p0
for a in [-2,2]:
    for b in np.arange(0,10,2):

        x = np.linspace(-3, 3, 1000)

        y = a*x + b

        plt.figure(2)

        plt.plot(x, y, color='black');

imgs = np.zeros((1280,1280))

row, cols = imgs.shape
imgs[:,:] = 255

for i in np.arange(0,1300,200):
    imgs[:,i] = 0
    imgs[i,:] = 0

plt.figure(2)
plt.imshow(np.uint8(imgs), cmap='gray')


from functools import reduce

def run():
    fib_series = lambda n: reduce(lambda x, u: x+[x[-1]+x[-2]],range(n-2), [0, 1])
    # n = 3
    # fib_series = list(reduce(lambda x: x+[x[-1]+x[-2]],range(n-2), [0, 1]))
    print("Fibonacci series upto 2:")
    print(fib_series(3))
    # print(fib_series)

if __name__ == '__main__':
    run()


from telebot.types import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove

from .db_structer import TeleUsers, University
from .model import get_semester

class Keyboard:
    def __init__(self, bot):
        """
        Handle all telegram keyboard keys
        :param bot: telebot bot API
        attributes:
            back_btn : KeyboardMarkup Button for back
            main_menu: KeyboardMarkup Button for main menu
        """

        self.jilebi = bot
        self.back_btn = KeyboardButton("🔙 Back")
        self.main_menu = KeyboardButton("🔝 Main Menu")

    def send_home(self, message):
        reply_markup = ReplyKeyboardMarkup(True, False)
        reply_markup.row("Get Today Events", "Get Tomorrow events")
        reply_markup.row("Get this week events", "Get next week events")
        reply_markup.row("Get this month events", "Other's Events")
        reply_markup.row("Extra's", "⚙ Settings")
        self.jilebi.send_message(
            message.chat.id, "Select Menu Item", reply_markup=reply_markup
        )
        TeleUsers.objects(pk=message.chat.id).update(unset__selection=1, position=0)

    def send_settings(self, message):
        reply_markup = ReplyKeyboardMarkup(row_width=2)
        user = TeleUsers.objects.only(
            "is_image_result", "calendar", "is_subscriber"
        ).get(pk=message.chat.id)
        buttons = ["🔗 Setup moodle calender link"]
        if user.calendar:
            buttons.append("🔗 Check my moodle calendar link")
        if user.is_subscriber:
            buttons.append("🔕 Unsubscribe Notification")
        else:
            buttons.append("🔔 Subscribe auto Notification")
        if user.is_image_result:
            buttons.append("📝 Get Text based result")
        else:
            buttons.append("🖼 Get Image based result")
        reply_markup.add(*[KeyboardButton(button) for button in buttons])
        reply_markup.row(self.main_menu)
        self.jilebi.send_message(
            message.chat.id, "Select Setting item", reply_markup=reply_markup
        )

    def send_university(self, message):
        reply_markup = ReplyKeyboardMarkup(True, False, row_width=2)
        reply_markup.add(
            *[KeyboardButton(uni) for uni in University.objects.distinct("name")]
        )
        reply_markup.add(self.back_btn)
        self.jilebi.send_message(
            message.chat.id, "Select a university", reply_markup=reply_markup
        )
        TeleUsers.objects(pk=message.chat.id).update(position=1)

    def send_faculty(self, message):
        user = TeleUsers.objects.only("selection").get(pk=message.chat.id)
        reply_markup = ReplyKeyboardMarkup(True, False, row_width=2)
        faculties = (
            University.objects.only("faculty__name")
            .get(name=user.selection.university)
            .faculty
        )
        reply_markup.add(*[KeyboardButton(faculty.name) for faculty in faculties])
        reply_markup.add(self.back_btn, self.main_menu)
        self.jilebi.send_message(
            message.chat.id, "Select the Faculty", reply_markup=reply_markup
        )
        user.update(position=2)

    def send_division(self, message):
        user = TeleUsers.objects.only("selection").get(pk=message.chat.id)
        reply_markup = ReplyKeyboardMarkup(True, False, row_width=2)
        divisions = (
            University.objects.only("faculty__name", "faculty__division__name")
            .get(name=user.selection.university)
            .faculty.get(name=user.selection.faculty)
            .division
        )
        reply_markup.add(*[KeyboardButton(division.name) for division in divisions])
        reply_markup.add(self.back_btn, self.main_menu)
        self.jilebi.send_message(
            message.chat.id, "Select the Division", reply_markup=reply_markup
        )
        user.update(position=3)

    def send_semester(self, message):
        user = TeleUsers.objects.only("selection").get(pk=message.chat.id)
        reply_markup = ReplyKeyboardMarkup(True, False, row_width=2)
        if user.selection.division:
            semesters = (
                University.objects.only(
                    "faculty__name",
                    "faculty__division__name",
                    "faculty__division__semester__name",
                )
                .get(name=user.selection.university)
                .faculty.get(name=user.selection.faculty)
                .division.get(name=user.selection.division)
                .semester
            )
        else:
            semesters = (
                University.objects.only("faculty__name", "faculty__semester__name")
                .get(name=user.selection.university)
                .faculty.get(name=user.selection.faculty)
                .semester
            )

        reply_markup.add(*[KeyboardButton(semester.name) for semester in semesters])
        reply_markup.add(self.back_btn, self.main_menu)
        self.jilebi.send_message(
            message.chat.id, "Select a semester", reply_markup=reply_markup
        )
        user.update(position=4)

    def send_others_menu(self, message):
        semester = get_semester(message.chat.id)
        reply_markup = ReplyKeyboardMarkup()
        buttons = []
        if semester.donor_calendar:
            buttons.extend(["Today Events", "Tomorrow events", "This week events", "Next week events",
                            "This month events"])
            self.jilebi.send_message(
                message.chat.id,
                f"Link Donate by: {semester.donor_name}",
                reply_markup=ReplyKeyboardRemove(),
            )
        else:
            self.jilebi.send_message(
                message.chat.id,
                "If you're a student of this course, please contact me to "
                "donate your link.",
            )
        buttons.append("Modules list")
        reply_markup.add(*[KeyboardButton(button) for button in buttons])
        reply_markup.row(self.back_btn, self.main_menu)
        self.jilebi.send_message(
            message.chat.id, "Select Item: ", reply_markup=reply_markup
        )
        TeleUsers.objects(pk=message.chat.id).update(position=5)

    def send_extras(self, message):
        reply_markup = ReplyKeyboardMarkup()
        reply_markup.row("Submit your module details", "Send Queries/Feedbacks")
        reply_markup.row("🎁 Share Jilebi", "👨🏻💻 Source Code", "Users Count")
        reply_markup.row(self.main_menu)
        self.jilebi.send_message(
            message.chat.id, "Select Item: ", reply_markup=reply_markup
        )

    def ask_division(self, message):
        reply_markup = ReplyKeyboardMarkup(row_width=2, one_time_keyboard=True)
        reply_markup.row("Yes", "No")
        self.jilebi.send_message(
            message.chat.id,
            "Are you have Divisions / Department inside your faculty?",
            reply_markup=reply_markup,
        )


# Solution 1, similar idea as Solution 2
# Only check
class Solution:
    def canTransform(self, start: str, end: str) -> bool:
        s = [i for i, c in enumerate(start) if c != 'X']
        e = [i for i, c in enumerate(end) if c != 'X']

        return (len(s) == len(e) and
            all(start[i] == end[j] and (i >= j if start[i] == 'L' else i <= j)
                for i, j in zip(s, e)))

# Solution 2, observation
# 'L' can only move left and 'R' can only move right
# Since we need to transform from 'start' to 'end', we can
# mark 'X' count difference
# cnt < 0 when we have 'L', cannot match
#   start: XLXX
#   end:   XXXL
# cnt > 0 when we have 'R', cannot match either
#   start: XXXR
#   end:   XRXX

class Solution:
    def canTransform(self, start: str, end: str) -> bool:
        i = j = 0
        m, n = map(len, (start, end))
        cnt = 0

        while i < m and j < n:
            while i < m and start[i] == 'X':
                cnt += 1
                i += 1
            while j < n and end[j] == 'X':
                cnt -= 1
                j += 1

            if i == m and j == n:
                return cnt == 0

            if i == m or j == n:
                return False

            # L can only go left and R can only go right
            if i < m and j < n:
                if start[i] != end[j]:
                    return False
                if start[i] == 'L' and cnt < 0:
                    return False
                if start[i] == 'R' and cnt > 0:
                    return False

                i += 1
                j += 1
        return True

Algorithms/0777 Swap Adjacent in LR String.py


# Trie

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_word = False

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word):
        cur = self.root
        for char in word:
            if char not in cur.children:
                cur.children[char] = TrieNode()
            cur = cur.children[char]
        cur.is_word = True

    def delete(self, word):
        self._delete(self.root, word, 0)

    def _delete(self, node, word, index):   # private method
        if index == len(word):
            if node.is_word:
                node.is_word = False
            return

        char = word[index]
        if char not in node.children:
            return

        child_node = node.children[char]
        self._delete(child_node, word, index + 1)

        if not child_node.children and not child_node.is_word:
            del node.children[char]

    def search(self, word):
        cur = self.root
        for char in word:
            if char not in cur.children:
                return False
            cur = cur.children[char]
        return cur.is_word

    def startsWith(self, prefix) -> bool:
        node = self.root
        for char in prefix:
            if char not in node.children:
                return False
            node = node.children[char]
        return True


import cv2
from cv2 import sqrt
import matplotlib.pyplot as plt
from numpy import zeros_like
import numpy as np
def CIE_lab_nearest_segmentation(image,n_blocks):
    '''
    n_blocks : The category into which the image needs to be divided
    image : BGR image
    return : segmentedFrames,Iplot
    segmentedFrames : (RGB)The set of images after segmentation
    Iplot : (RGB)The distribution of segmented image on axis (a,b)
    '''
    Ilab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
    Ilab = cv2.split(Ilab)
    #Color sample space generation
    sampleAreas = []
    def MouseHandler(event,x,y,flags,param):
        if event != cv2.EVENT_LBUTTONDBLCLK:
            return
        sampleAreas.append((x,y))
    cv2.imshow("image",image)
    cv2.setMouseCallback('image',MouseHandler)
    while len(sampleAreas) < n_blocks:
        cv2.waitKey(20)
    cv2.setMouseCallback('image',lambda*args:None)
    #Calculate average color
    colorMarksLAB = []
    colorMarksBGR = []
    for pix in sampleAreas:
        mask = zeros_like(Ilab[0])
        cv2.circle(mask,pix,10,255,-1)
        a = np.mean(Ilab[1][np.argwhere(mask > 0)])
        b = np.mean(Ilab[2][np.argwhere(mask > 0)])
        colorMarksLAB.append((a,b))
        colorMarksBGR.append(image[mask>0,:].mean(axis=(0)))
    #Calculates the minimum distance between all pixels and all colors
    distance = []
    for color in colorMarksLAB:
        distance.append(sqrt(pow((Ilab[1]-color[0]),2)+pow((Ilab[2]-color[1]),2)))
    distance_min = np.minimum.reduce(distance)
    #Calculates the color label for each pixel
    labels = zeros_like(Ilab[0],dtype= np.uint8)
    for i in range(len(colorMarksLAB)):
        mask = distance_min ==distance[i]
        labels[mask] = i
    #Split and store the original image
    segmentedFrames = []
    for i in range(len(colorMarksLAB)):
        Itmp = zeros_like(image)
        mask = labels == i
        Itmp[mask] = image[mask]
        segmentedFrames.append(Itmp)
    #Displays the color distribution in (a,b) coordinates
    Iplot = np.full((256,256,3),255,dtype=np.uint8)
    for i in range(len(colorMarksLAB)):
        Itmp = zeros_like(image)
        mask = labels == i
        Iplot[Ilab[1][mask],Ilab[2][mask],:] = colorMarksBGR[i]
    for i in range(n_blocks):
        segmentedFrames[i] = cv2.cvtColor(segmentedFrames[i],cv2.COLOR_BGR2RGB)
    Iplot = cv2.cvtColor(Iplot,cv2.COLOR_BGR2RGB)
    return segmentedFrames,Iplot

#input the image
#2 categories
I1 = cv2.imread("pictures/ball2.jpg",cv2.IMREAD_COLOR)
segmentedFrames1,Iplot1 = CIE_lab_nearest_segmentation(I1,2)
I1 = cv2.cvtColor(I1, cv2.COLOR_BGR2RGB)

plt.subplot(221),plt.title('original image'),plt.xticks([]),plt.yticks([])
plt.imshow(I1)
plt.subplot(222),plt.title('segmented image 1'),plt.xticks([]),plt.yticks([])
plt.imshow(segmentedFrames1[0])
plt.subplot(223),plt.title('segmented image 2'),plt.xticks([]),plt.yticks([])
plt.imshow(segmentedFrames1[1])
plt.show()
plt.waitforbuttonpress

#3 categories
I2 = cv2.imread("pictures/ball3.jpg",cv2.IMREAD_COLOR)
segmentedFrames2,Iplot2 = CIE_lab_nearest_segmentation(I2,3)
I2 = cv2.cvtColor(I2, cv2.COLOR_BGR2RGB)

plt.subplot(221),plt.title('original image'),plt.xticks([]),plt.yticks([])
plt.imshow(I2)
plt.subplot(222),plt.title('segmented image 1'),plt.xticks([]),plt.yticks([])
plt.imshow(segmentedFrames2[0])
plt.subplot(223),plt.title('segmented image 2'),plt.xticks([]),plt.yticks([])
plt.imshow(segmentedFrames2[1])
plt.subplot(224),plt.title('segmented image 3'),plt.xticks([]),plt.yticks([])
plt.imshow(segmentedFrames2[2])
plt.show()
plt.waitforbuttonpress


import matplotlib
matplotlib.use('Agg')
import pylab
from pylab import rcParams
import matplotlib.pyplot as plt
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
import pandas as pd
from pandas_datareader import data as pdr
import fix_yahoo_finance as yf
from io import BytesIO
import os

yf.pdr_override()

def start(bot, update):
  update.message.reply_text("Hai, yuk cek record stocks pilihanmu. \n Caranya ketik /help dulu ya")

def helps(bot, update):
  update.message.reply_text("Caranya: <Simbol perusahaan> <tgl mulai> <tgl selesai> \n Format tanggalnya YYYY-MM-DD")

def get_stock(bot, update):
  update.message.reply_text("Sedang diproses, mohon ditunggu...")
  idchat = update['message']['chat']['id']
  text = update['message']['text']
  texts = text.split(" ")
  if (len(texts) == 3):
    s = texts[1]
    e = texts[2]
    data = pdr.get_data_yahoo(texts[0], start=s, end=e)
    close = data['Close']
    all_weekdays = pd.date_range(start=s, end=e, freq='B')
    close = close.reindex(all_weekdays)
    fig = plt.figure(figsize=(15,8))
    ax = fig.add_subplot(111)
    plt.ylabel('Close Price')
    plt.xlabel('Date')
    plt.title("Close Price Stocks: "+str(texts[0]))
    # buffer = BytesIO()
    ax.plot(close.index,close)
    buffer = BytesIO()
    fig.savefig(buffer, format='png')
    buffer.seek(0)
    bot.send_photo(idchat, photo=buffer)
  elif (len(texts) == 4):
    get_stock_multi(bot, update)

def get_stock_multi(bot, update):
  idchat = update['message']['chat']['id']
  text = update['message']['text']
  texts = text.split(" ")
  s = texts[2]
  e = texts[3]
  print("get")
  data1 = pdr.get_data_yahoo(texts[0], start=s, end=e)
  data2 = pdr.get_data_yahoo(texts[1], start=s, end=e)
  close1 = data1['Close']
  close2 = data2['Close']
  all_weekdays = pd.date_range(start=s, end=e, freq='B')
  close1 = close1.reindex(all_weekdays)
  close2 = close2.reindex(all_weekdays)
  fig = plt.figure(figsize=(15,8))
  ax = fig.add_subplot(111)
  plt.ylabel('Close Price')
  plt.xlabel('Date')
  plt.title("Close Price Stocks: "+str(texts[0])+" & "+str(texts[1]))
  ax.plot(close1.index,close1,'r')
  ax.plot(close2.index,close2,'b')
  ax.legend([texts[0], texts[1]])
  buffer = BytesIO()
  fig.savefig(buffer, format='png')
  buffer.seek(0)
  print("get")
  bot.send_photo(idchat, photo=buffer)

def main():
  # Create Updater object and attach dispatcher to it
  TOKEN = "781975723:AAEIsAhOsFRnlGOwbVJJY9nTwWGgSw7-Pc8"
  PORT = int(os.environ.get('PORT','5000'))
  updater = Updater(TOKEN)
  updater.start_webhook(listen="0.0.0.0",
                    port = PORT,
                    url_path=TOKEN)
  dispatcher = updater.dispatcher
  print("Bot started")

  # Add command handler to dispatcher
  start_handler = CommandHandler('start',start)
  help_handler = CommandHandler('help',helps)
  stock_case = MessageHandler(Filters.text, get_stock)
  dispatcher.add_handler(start_handler)
  dispatcher.add_handler(stock_case)
  dispatcher.add_handler(help_handler)

  # Start the bot
  updater.bot.set_webhook("https://still-bastion-47471.herokuapp.com/"+TOKEN)
  updater.idle()
  # updater.start_polling()

  # Run the bot until you press Ctrl-C
  # updater.idle()

if __name__ == '__main__':
  main()


from dataclasses import dataclass, field
from pathlib import Path

from tqdm import tqdm

VALID_CHARACTERS = "йцукенгшщзхъфывапролджэячсмитьбю -"

@dataclass(init=False)
class Sentence:
    """
    Represents one sentence of a text
    """

    words: list[str] = field(default_factory=list)

    def __init__(self, sentence: str) -> None:
        sentence = self.__cleanup_sentence(sentence)
        self.words = list(
            filter(
                lambda word: len(word) > 0,
                sentence.split(),
            )
        )

    def __cleanup_sentence(self, sentence: str) -> str:
        """
        Removes all unnecessary characters from a given string

        Parameters
        ----------
        sentence : str

        Returns
        -------
        str
            Cleaned-up sentence
        """
        return "".join(
            filter(
                lambda c: c in VALID_CHARACTERS,
                sentence.lower().replace("ё", "е"),
            )
        ).strip()

    def __len__(self) -> int:
        return len(self.words)

    def __hash__(self) -> int:
        return hash(" ".join(self.words))

@dataclass
class TextFile:
    """
    Opens a file, cleans up the contents and parses the text into sentences.
    """

    input_file: Path
    sentences: list[Sentence] = field(default_factory=list)

    def __post_init__(self):
        text = self.__get_text()
        self.sentences = list(
            map(lambda sentence: Sentence(sentence), self.__split_into_sentences(text))
        )

    def __get_text(self) -> str:
        """
        Reads text from the file and returns it
        """
        text = ""
        with open(self.input_file, "r") as fh:
            text = fh.read()
        return text

    def __split_into_sentences(self, text: str) -> list[str]:
        text = " ".join(text.splitlines())
        return text.split(".")

@dataclass
class DataLoader:
    """
    Loads and parses all data in a given directory.
    """

    data_dir: Path
    parsed_files: list[TextFile] = field(default_factory=list)

    def __post_init__(self):
        print("Parsing files...")

        self.parsed_files = list(
            map(
                lambda path: TextFile(input_file=path),
                tqdm(self.__get_all_file_paths()),
            )
        )

    def __get_files_recursive(self, path: Path) -> list[Path]:
        """
        Recursively traverses a given directory and saves all text files.

        Parameters
        ----------
        path : Path
            Current directory

        Returns
        -------
        list[Path]
            All text files
        """
        result: list[Path] = []
        for child in path.iterdir():
            if child.is_dir():
                result += self.__get_files_recursive(child)
            else:
                if child.suffix == ".txt":
                    result.append(child)
        return result

    def __get_all_file_paths(self) -> list[Path]:
        """
        Returns all text file paths in `data_dir`.

        Returns
        -------
        list[Path]
            Paths to text files with data inside.
        """
        return self.__get_files_recursive(self.data_dir)


#!/usr/bin/env python

from runtest import TestBase
import subprocess as sp

TDIR='xxx'

class TestCase(TestBase):
    def __init__(self):
        TestBase.__init__(self, 'sleep', """
{"traceEvents":[
{"ts":56466448731,"ph":"B","pid":32537,"name":"main"},
{"ts":56466448731,"ph":"B","pid":32537,"name":"foo"},
{"ts":56466448742,"ph":"B","pid":32537,"name":"bar"},
{"ts":56466448743,"ph":"B","pid":32537,"name":"usleep"},
{"ts":56466450823,"ph":"E","pid":32537,"name":"usleep"},
{"ts":56466450827,"ph":"E","pid":32537,"name":"bar"},
{"ts":56466450834,"ph":"E","pid":32537,"name":"foo"},
{"ts":56466450835,"ph":"E","pid":32537,"name":"main"}
], "metadata": {
"command_line":"uftrace record -d xxx t-sleep ",
"recorded_time":"Mon Oct  3 22:45:57 2016"
} }
""")

    def pre(self):
        record_cmd = '%s record -d %s %s' % (TestBase.ftrace, TDIR, 't-' + self.name)
        sp.call(record_cmd.split())
        return TestBase.TEST_SUCCESS

    def runcmd(self):
        return '%s dump -d %s -t 1ms --chrome' % (TestBase.ftrace, TDIR)

    def post(self, ret):
        sp.call(['rm', '-rf', TDIR])
        return ret

    def sort(self, output):
        """ This function post-processes output of the test to be compared .
            It ignores blank and comment (#) lines and remaining functions.  """
        import json

        result = []
        o = json.loads(output)
        for ln in o['traceEvents']:
            result.append("%s %s" % (ln['ph'], ln['name']))
        return '\n'.join(result)


import logging
import os
import pathlib
import sys
from datetime import datetime

def create_log_directories(algo_name: str):
    project_abs_path = get_project_path()
    experiment_name = get_algorithm_name_by_time(algo_name)
    create_dir(str(pathlib.Path(project_abs_path, "Runs")))
    create_dir(str(pathlib.Path(project_abs_path, "Runs", experiment_name)))
    create_dir(
        str(pathlib.Path(project_abs_path, "Runs", experiment_name, "checkpoints"))
    )

def create_tensorboard_log_dir(algo_name: str):
    project_abs_path = get_project_path()
    experiment_name = get_algorithm_name_by_time(algo_name)
    create_dir(str(pathlib.Path(project_abs_path, "Runs", experiment_name, "runs")))

def get_project_path():
    return str(pathlib.Path(__file__).parent.resolve().parent.parent)

def get_algorithm_name_by_time(algo_name: str):
    today = datetime.now()
    todays_date_full = (
        str(today.year) + "_" + str(today.month) + "_" + str(today.day) + "_"
    )
    todays_date_full += (
        str(today.hour) + "_" + str(today.minute) + "_" + str(today.second)
    )
    return algo_name + "_" + todays_date_full

def create_dir(path):
    try:
        os.makedirs(path)
    except FileExistsError:
        logging.info("Folder is already exist : ", path)
    except Exception as e:
        logging.error("Could not created the agents folder : ", e)


import json
import pathlib
import sys
import csv
from collections import defaultdict
import argparse

import tabulate

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Evaluate results")

    parser.add_argument("data", help="Results file", type=pathlib.Path)
    parser.add_argument("--only", help="Filter by type (single_scc, one_state_scc)")
    parser.add_argument("--latex", help="LaTeX output", action="store_true")
    parser.add_argument(
        "--scatter", help="Instead, write the scatter plot data", type=str
    )
    parser.add_argument(
        "--scatter-to",
        help="Value to replace timeout with in scatter plot",
        type=int,
        default=600,
    )
    args = parser.parse_args()

    with args.data.open(mode="rt") as f:
        results = json.load(f)

    approaches = set()
    data = defaultdict(dict)
    for family, family_results in results.items():
        for instance, instance_data in family_results.get("results", {}).items():
            d = instance_data["data"]
            size = d.get("states", 0)
            if size == "error":
                size = -1
            components = d.get("components", 0)
            if components == "error":
                components = -1
            largest_component = d.get("largest_component", 0)
            if largest_component == "error":
                largest_component = -1
            if args.only == "one_state_scc":
                if largest_component != 1:
                    continue
            elif args.only == "single_scc":
                if largest_component != size:
                    continue

            for approach, approach_result in instance_data.get("results", {}).items():
                approaches.add(approach)
                data[
                    (
                        family_results["type"].lower(),
                        family,
                        size,
                        components,
                        largest_component,
                        instance,
                    )
                ][approach] = approach_result
    approaches = list(sorted(approaches))

    if args.scatter:
        if len(args.scatter.split(",")) != 2:
            sys.exit("Give scatter as <left>,<right>")
        left_name, right_name = args.scatter.split(",")
        if left_name not in approaches:
            sys.exit(f"{left_name} not known")
        if right_name not in approaches:
            sys.exit(f"{right_name} not known")

        writer = csv.writer(sys.stdout)
        writer.writerow([left_name, right_name])
        for key in data.keys():
            model_type, family, size, components, largest_component, instance = key

            left, right = data[key].get(left_name, None), data[key].get(
                right_name, None
            )
            if (
                left is None
                or left.get("type", None) not in {"success", "timeout", "skipped"}
                or right is None
                or right.get("type", None) not in {"success", "timeout", "skipped"}
            ):
                continue
            if left["type"] != "success" and right["type"] != "success":
                continue

            writer.writerow(
                [
                    round(left["time"], 3)
                    if left["type"] == "success"
                    else args.scatter_to,
                    round(right["time"], 3)
                    if right["type"] == "success"
                    else args.scatter_to,
                ]
            )
        sys.exit()

    header = [
        "type",
        "instance",
        "size",
        "components",
        "largest_component",
    ] + approaches
    rows = []
    for key in sorted(data.keys()):
        model_type, family, size, components, largest_component, instance = key
        row = [model_type, f"{family}/{instance}", size, components, largest_component]
        for approach in approaches:
            result = data[key].get(approach, None)
            if result is None or "type" not in result:
                row.append("?")
            else:
                result_type = result["type"]
                if result_type == "error":
                    error_type = result.get("error", "generic")
                    if error_type == "stackoverflow":
                        row.append("Stack Overflow")
                    elif error_type == "memory" or result["code"] == -9:
                        row.append("M/O")
                    elif error_type == "bounds":
                        row.append("Internal error")
                    elif error_type == "convergence":
                        row.append("Convergence error")
                    else:
                        row.append(f"E({result['code']})")
                elif result_type == "timeout":
                    row.append("T/O")
                elif result_type == "skipped":
                    row.append("-")
                elif result_type == "success":
                    row.append(f"{result['time']:.2f}")
                else:
                    row.append(f"?{result_type}?")
        rows.append(row)
    print(tabulate.tabulate(rows, header, tablefmt="latex" if args.latex else "simple"))


"""Routes for the course resource.
"""

from flask import Flask, jsonify, request
from datetime import datetime
import data
from validate import Validation_Put, Validation_Post

d = data.load_data()
app = Flask(__name__)
current_highest_id = 200

@app.route('/course/<int:id>', methods=['GET'])
def get_course(id):
    """Get a course by id.

        :param int id: The record id.
        :return: A single course (see the challenge notes for examples)
        :rtype: object
        """

    """
    -------------------------------------------------------------------------
    Challenge notes:
    -------------------------------------------------------------------------
    1. Bonus points for not using a linear scan on your data structure.
    """
    # YOUR CODE HERE
    if id in d.keys():
        return jsonify({"data": d[id]}),200
    else:
        return jsonify({"message": f"Course {id} does not exist"}),404

@app.route("/course", methods=['GET'])
def get_courses():
    """Get a page of courses, optionally filtered by title words (a list of
        words separated by commas".

        Query parameters: page-number, page-size, title-words
        If not present, we use defaults of page-number=1, page-size=10

        :return: A page of courses (see the challenge notes for examples)
        :rtype: object
        """

    """
    -------------------------------------------------------------------------
    Challenge notes:
    -------------------------------------------------------------------------
    1. Bonus points for not using a linear scan, on your data structure, if
       title-words is supplied
    2. Bonus points for returning resulted sorted by the number of words which
       matched, if title-words is supplied.
    3. Bonus points for including performance data on the API, in terms of
       requests/second.
    """
    # YOUR CODE HERE

    # Included sorting for title-words match
    # Highest to lowest in terms of number of matching words
    # For each number of similar words, sorted in ascending order

    pages = request.args.get('page-size', 200)
    pages = int(pages)
    page_number = request.args.get('page-size', 1)
    words = request.args.get('title-words', '')
    words = words.split(',')
    count = [[] for i in range(len(words) + 1)]
    final = []
    for i in (sorted(d)):
        c = 0
        for j in words:
            if j.lower() in d[i]['title'].lower():
                c += 1
        if c != 0:
            count[c].append(d[i])
    for i in range(len(count) - 1, -1, -1):
        final += count[i]
    print(final)
    if final != [] and pages <= current_highest_id:
        if len(final) > pages:

            return jsonify({"data": final[0:pages],
                            "metadata": {"page_count": int(pages / int(page_number)), "page_number": 1,
                                         "page_size": pages, "record_count": len(final)}}),200
        else:
            return jsonify({"data": final, "metadata": {"page_count": int(pages / int(page_number)), "page_number": 1,
                                                        "page_size": pages, "record_count": len(final)}}),200
    else :
        return jsonify({"message": "No courses found"}), 404

@app.route("/course", methods=['POST'])
def create_course():
    """Create a course.
        :return: The course object (see the challenge notes for examples)
        :rtype: object
        """

    """
    -------------------------------------------------------------------------
    Challenge notes:
    -------------------------------------------------------------------------
    1. Bonus points for validating the POST body fields
    """
    # YOUR CODE HERE
    global current_highest_id
    current_highest_id += 1
    validating = Validation_Post()
    errors = validating.validate(request.get_json())
    if errors:
        message = ''
        for i in errors:
            message += errors[i][0]
        return jsonify(({"message": message})), 404
    date_created = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
    date_updated = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
    new_entry = request.get_json()
    new_entry["date_created"] = date_created
    new_entry["date_updated"] = date_updated
    new_entry["id"] = current_highest_id
    d[current_highest_id] = new_entry
    return jsonify({"data": d[current_highest_id]}),200

@app.route("/course/<int:id>", methods=['PUT'])
def update_course(id):
    """Update a a course.
        :param int id: The record id.
        :return: The updated course object (see the challenge notes for examples)
        :rtype: object
        """

    """
    -------------------------------------------------------------------------
    Challenge notes:
    -------------------------------------------------------------------------
    1. Bonus points for validating the PUT body fields, including checking
       against the id in the URL

    """
    # YOUR CODE HERE
    validating = Validation_Put()

    errors = validating.validate(request.get_json())
    if errors:
        message = ''
        for i in errors:
            message += errors[i][0]
        return jsonify({"message": message}), 404

    else:
        updated_entry = request.get_json()
        if id != updated_entry["id"]:
            return jsonify({"message": "The id does match the payload"}), 404
        else:
            updated_entry["date_updated"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
            updated_entry["date_created"] = d[id]["date_created"]
            d[id]=updated_entry
            return jsonify({"data": d[id]}), 200

@app.route("/course/<int:id>", methods=['DELETE'])
def delete_course(id):
    """Delete a course
        :return: A confirmation message (see the challenge notes for examples)
        """
    """
    -------------------------------------------------------------------------
    Challenge notes:
    -------------------------------------------------------------------------
    None
    """
    # YOUR CODE HERE
    try:
        del d[id]
    except KeyError:
        return jsonify({"message": f"Course {id} does not exist"}), 404
    return jsonify({"message": "The specified course was deleted"}), 200

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


#!/usr/bin python3
""" Display Page parent classes for display section of the Faceswap GUI """

import logging
import tkinter as tk
from tkinter import ttk

from .tooltip import Tooltip
from .utils import get_images

logger = logging.getLogger(__name__)  # pylint: disable=invalid-name

class DisplayPage(ttk.Frame):  # pylint: disable=too-many-ancestors
    """ Parent frame holder for each tab.
        Defines uniform structure for each tab to inherit from """
    def __init__(self, parent, tabname, helptext):
        logger.debug("Initializing %s: (tabname: '%s', helptext: %s)",
                     self.__class__.__name__, tabname, helptext)
        ttk.Frame.__init__(self, parent)
        self.pack(fill=tk.BOTH, side=tk.TOP, anchor=tk.NW)

        self.runningtask = parent.runningtask
        self.helptext = helptext
        self.tabname = tabname

        self.vars = {"info": tk.StringVar()}
        self.add_optional_vars(self.set_vars())

        self.subnotebook = self.add_subnotebook()
        self.optsframe = self.add_options_frame()
        self.add_options_info()

        self.add_frame_separator()
        self.set_mainframe_single_tab_style()
        parent.add(self, text=self.tabname.title())
        logger.debug("Initialized %s", self.__class__.__name__,)

    def add_optional_vars(self, varsdict):
        """ Add page specific variables """
        if isinstance(varsdict, dict):
            for key, val in varsdict.items():
                logger.debug("Adding: (%s: %s)", key, val)
                self.vars[key] = val

    @staticmethod
    def set_vars():
        """ Override to return a dict of page specific variables """
        return dict()

    def add_subnotebook(self):
        """ Add the main frame notebook """
        logger.debug("Adding subnotebook")
        notebook = ttk.Notebook(self)
        notebook.pack(side=tk.TOP, anchor=tk.NW, fill=tk.BOTH, expand=True)
        return notebook

    def add_options_frame(self):
        """ Add the display tab options """
        logger.debug("Adding options frame")
        optsframe = ttk.Frame(self)
        optsframe.pack(side=tk.BOTTOM, padx=5, pady=5, fill=tk.X)
        return optsframe

    def add_options_info(self):
        """ Add the info bar """
        logger.debug("Adding options info")
        lblinfo = ttk.Label(self.optsframe,
                            textvariable=self.vars["info"],
                            anchor=tk.W,
                            width=70)
        lblinfo.pack(side=tk.LEFT, padx=5, pady=5, anchor=tk.W)

    def set_info(self, msg):
        """ Set the info message """
        logger.debug("Setting info: %s", msg)
        self.vars["info"].set(msg)

    def add_frame_separator(self):
        """ Add a separator between top and bottom frames """
        logger.debug("Adding frame seperator")
        sep = ttk.Frame(self, height=2, relief=tk.RIDGE)
        sep.pack(fill=tk.X, pady=(5, 0), side=tk.BOTTOM)

    @staticmethod
    def set_mainframe_single_tab_style():
        """ Configure ttk notebook style to represent a single frame """
        logger.debug("Setting main frame single tab style")
        nbstyle = ttk.Style()
        nbstyle.configure("single.TNotebook", borderwidth=0)
        nbstyle.layout("single.TNotebook.Tab", [])

    def subnotebook_add_page(self, tabtitle, widget=None):
        """ Add a page to the sub notebook """
        logger.debug("Adding subnotebook page: %s", tabtitle)
        frame = widget if widget else ttk.Frame(self.subnotebook)
        frame.pack(padx=5, pady=5, fill=tk.BOTH, expand=True)
        self.subnotebook.add(frame, text=tabtitle)
        self.subnotebook_configure()
        return frame

    def subnotebook_configure(self):
        """ Configure notebook to display or hide tabs """
        if len(self.subnotebook.children) == 1:
            logger.debug("Setting single page style")
            self.subnotebook.configure(style="single.TNotebook")
        else:
            logger.debug("Setting multi page style")
            self.subnotebook.configure(style="TNotebook")

    def subnotebook_hide(self):
        """ Hide the subnotebook. Used for hiding
            Optional displays """
        if self.subnotebook and self.subnotebook.winfo_ismapped():
            logger.debug("Hiding subnotebook")
            self.subnotebook.pack_forget()
            self.subnotebook.destroy()
            self.subnotebook = None

    def subnotebook_show(self):
        """ Show subnotebook. Used for displaying
            Optional displays  """
        if not self.subnotebook:
            logger.debug("Showing subnotebook")
            self.subnotebook = self.add_subnotebook()

    def subnotebook_get_widgets(self):
        """ Return each widget that sits within each
            subnotebook frame """
        logger.debug("Getting subnotebook widgets")
        for child in self.subnotebook.winfo_children():
            for widget in child.winfo_children():
                yield widget

    def subnotebook_get_titles_ids(self):
        """ Return tabs ids and titles """
        tabs = dict()
        for tab_id in range(0, self.subnotebook.index("end")):
            tabs[self.subnotebook.tab(tab_id, "text")] = tab_id
        logger.debug(tabs)
        return tabs

    def subnotebook_page_from_id(self, tab_id):
        """ Return subnotebook tab widget from it's ID """
        tab_name = self.subnotebook.tabs()[tab_id].split(".")[-1]
        logger.debug(tab_name)
        return self.subnotebook.children[tab_name]

class DisplayOptionalPage(DisplayPage):  # pylint: disable=too-many-ancestors
    """ Parent Context Sensitive Display Tab """

    def __init__(self, parent, tabname, helptext, waittime, command=None):
        logger.debug("%s: OptionalPage args: (waittime: %s, command: %s)",
                     self.__class__.__name__, waittime, command)
        DisplayPage.__init__(self, parent, tabname, helptext)

        self.command = command
        self.display_item = None

        self.set_info_text()
        self.add_options()
        parent.select(self)

        self.update_idletasks()
        self.update_page(waittime)

    @staticmethod
    def set_vars():
        """ Analysis specific vars """
        enabled = tk.BooleanVar()
        enabled.set(True)

        ready = tk.BooleanVar()
        ready.set(False)

        modified = tk.DoubleVar()
        modified.set(None)

        tk_vars = {"enabled": enabled,
                   "ready": ready,
                   "modified": modified}
        logger.debug(tk_vars)
        return tk_vars

    # INFO LABEL
    def set_info_text(self):
        """ Set waiting for display text """
        if not self.vars["enabled"].get():
            msg = "{} disabled".format(self.tabname.title())
        elif self.vars["enabled"].get() and not self.vars["ready"].get():
            msg = "Waiting for {}...".format(self.tabname)
        else:
            msg = "Displaying {}".format(self.tabname)
        logger.debug(msg)
        self.set_info(msg)

    # DISPLAY OPTIONS BAR
    def add_options(self):
        """ Add the additional options """
        self.add_option_save()
        self.add_option_enable()

    def add_option_save(self):
        """ Add save button to save page output to file """
        logger.debug("Adding save option")
        btnsave = ttk.Button(self.optsframe,
                             image=get_images().icons["save"],
                             command=self.save_items)
        btnsave.pack(padx=2, side=tk.RIGHT)
        Tooltip(btnsave,
                text="Save {}(s) to file".format(self.tabname),
                wraplength=200)

    def add_option_enable(self):
        """ Add checkbutton to enable/disable page """
        logger.debug("Adding enable option")
        chkenable = ttk.Checkbutton(self.optsframe,
                                    variable=self.vars["enabled"],
                                    text="Enable {}".format(self.tabname),
                                    command=self.on_chkenable_change)
        chkenable.pack(side=tk.RIGHT, padx=5, anchor=tk.W)
        Tooltip(chkenable,
                text="Enable or disable {} display".format(self.tabname),
                wraplength=200)

    def save_items(self):
        """ Save items. Override for display specific saving """
        raise NotImplementedError()

    def on_chkenable_change(self):
        """ Update the display immediately on a checkbutton change """
        logger.debug("Enabled checkbox changed")
        if self.vars["enabled"].get():
            self.subnotebook_show()
        else:
            self.subnotebook_hide()
        self.set_info_text()

    def update_page(self, waittime):
        """ Update the latest preview item """
        if not self.runningtask.get():
            return
        if self.vars["enabled"].get():
            logger.trace("Updating page")
            self.display_item_set()
            self.load_display()
        self.after(waittime, lambda t=waittime: self.update_page(t))

    def display_item_set(self):
        """ Override for display specific loading """
        raise NotImplementedError()

    def load_display(self):
        """ Load the display """
        if not self.display_item:
            return
        logger.debug("Loading display")
        self.display_item_process()
        self.vars["ready"].set(True)
        self.set_info_text()

    def display_item_process(self):
        """ Override for display specific loading """
        raise NotImplementedError()

    def close(self):
        """ Called when the parent notebook is shutting down
            Children must be destroyed as forget only hides display
            Override for page specific shutdown """
        for child in self.winfo_children():
            logger.debug("Destroying child: %s", child)
            child.destroy()


from multiprocessing import Pool
from datetime import datetime, timedelta

def duplicate_date(date_tuple):
    pass

if __name__ == '__main__':

    pool = Pool(3)

    init_date_str = '20200531'
    init_date = datetime.strptime(init_date_str, '%Y%m%d').date()
    date_list = []

    number = 1
    while 1:
        next_date = init_date + timedelta(days=number)
        str_next_date = str(next_date).replace('-', '')

        # 该批次 导入的时间
        if str_next_date >= '20210101':
            date_list.append((number, str_next_date))
        number += 1

        # 该批次 导入的截止时间
        if str_next_date == '20210630':
            break

    try:
        pool.map(duplicate_date, date_list)
        pool.close()
        pool.join()
    except Exception as e:
        logger.info(e)


from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from api_app.models import Junction
from test_util import login

class JunctionTests(APITestCase):
    def test_create_junction(self):
        """
        Test adding a new junction."
        """
        login(self.client)
        url = reverse('junction-list')
        data = {'description': 'Test junction'}
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Junction.objects.count(), 1)
        self.assertEqual(Junction.objects.get().description, 'Test junction')

    def test_duplicate_junction(self):
        """
        Test that adding a junction with an existing description fails."
        """
        login(self.client)
        url = reverse('junction-list')
        data = {'description': 'Test junction'}
        response = self.client.post(url, data, format='json')
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(Junction.objects.count(), 1)


from enum import Enum
from typing import Tuple, Union, NewType

from quantlib.utils import quantlib_err_header

qrangespec = {"bitwidth": 8 , "signed":True}

# The data type representing quantisation granularity. QuantLib modules will
# instantiate a separate quantiser for each of the specified dimensions. The
# dimensions are specified by means of their integer index. These indices are
# collected in a tuple: this choice implies that the quantisation granularity
# will be static throughout training.
QGranularity = NewType('QGranularity', Tuple[int, ...])

# The data type representing how users can specify quantisation granularity:
#   * either they provide the explicit collection of dimension indices
#   * or they provide string shortcuts.
QGranularitySpecType = Union[QGranularity, Tuple[int, ...], str]

def resolve_qgranularity_qgranularityspec(qgranularityspec: QGranularity) -> QGranularity:
    return qgranularityspec

def resolve_tuple_qgranularityspec(qgranularityspec: Tuple[int, ...]) -> QGranularity:
    """Map an explicit index collection (tuple of integers) to a
    ``QGranularity`` object.
    """
    if any(map(lambda i: i < 0, qgranularityspec)):
        raise ValueError(quantlib_err_header() + f"requires non-negative dimension indices, but found the following values: {tuple(i for i in qgranularityspec if i < 0)}.")

    qgranularityspec = tuple(set(qgranularityspec))  # remove duplicate values
    qgranularityspec = tuple(sorted(qgranularityspec))
    qgranularity = QGranularity(qgranularityspec)
    return qgranularity

# String shortcuts must belong to the following list. We assume the NCHW
# ordering of PyTorch.
QGranularityStrSpecOptions = Enum('QGranularityStrSpecOptions',
                                  [
                                      ('PER-ARRAY',              QGranularity(tuple())),
                                      ('PER-OUTCHANNEL_WEIGHTS', QGranularity((0,))),
                                  ])

def resolve_str_qgranularityspec(qgranularityspec: str) -> QGranularity:
    """Map a (supported) string shortcut to a ``QGranularity`` object."""
    qgranularityspec = qgranularityspec.upper()
    try:
        qgranularity = getattr(QGranularityStrSpecOptions, qgranularityspec).value
        return qgranularity
    except AttributeError:
        raise ValueError(f"unsupported QGranularity string specification: {qgranularityspec}.")

# Redirect the general solver to the type-specific solver method.
QGranularitySpecSolvers = Enum('QGranularitySpecSolvers',
                               [
                                   ('QGRANULARITY', resolve_qgranularity_qgranularityspec),
                                   ('TUPLE',        resolve_tuple_qgranularityspec),
                                   ('STR',          resolve_str_qgranularityspec),
                               ])

def resolve_qgranularityspec(qgranularityspec: QGranularitySpecType) -> QGranularity:
    """Resolve user specifications into ``QGranularity`` objects.

    This function uses a strategy pattern to disambiguate different types of
    specifications.
    """
    qgranularityspec_class = qgranularityspec.__class__.__name__.upper()

    try:
        solver = getattr(QGranularitySpecSolvers, qgranularityspec_class)
        qgranularity = solver(qgranularityspec)
        return qgranularity
    except AttributeError:
        raise TypeError(f"unsupported QGranularity specification type: {qgranularityspec_class}.")


import unittest
import subprocess
import ast
import os

from alternatecmds.screenscrapes import getstreams
from test.TwitchEnvVars import TwitchEnvVars
from TwitchPollCommands import get_streams

def scrapematches(item, scrape):
    return item['title'] == scrape[0] and scrape[1].lower() in item['thumbnail_url'].lower()

class testgetstreams(TwitchEnvVars):
    def test_getstreams(self):
        #this test needs client id, and bearer
        self.assertTrue(hasattr(self, 'twitch_client_id'))
        self.assertTrue(hasattr(self, 'twitch_bearer'))

        #get data from API call via python
        args = {}
        args['clientid'] = self.twitch_client_id
        args['oauth'] = self.twitch_bearer
        args['community_id'] = '4912794f-4830-470f-8224-a2f793d4e5b6'

        python_api_results = get_streams(**args)['data']

        #get data from API call with curl
        completion_info = subprocess.run([TwitchEnvVars.bashcmddir + 'get_live_lichess_streams.sh'], stdout=subprocess.PIPE)

        results_dict = ast.literal_eval(completion_info.stdout.decode('utf-8'))
        curl_results = results_dict['data']

        #get data from screen scraping
        screenscrape_results = getstreams.get_streams_info_from_twitch_page('lichess')
        self.assertTrue(len(python_api_results) == len(curl_results) == len(screenscrape_results))

        #python and curl results should match exactly
        for ind, item in enumerate(python_api_results):
            self.assertTrue(curl_results[ind] == item)
            self.assertTrue(scrapematches(item, screenscrape_results[ind]))


"""
Given the head of a singly linked list, reverse the list, and return the reversed list.

Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]

"""

from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reverseList(head: Optional[ListNode]) -> Optional[ListNode]:
    cur = None
    temp = head
    while temp:
        temp_node = temp.next
        temp.next = cur
        cur = temp
        temp = temp_node
    return cur

"""

Time Complexity: O(N)
Space: O(1)

"""


from typing import List

from fastapi import APIRouter, Depends, status
from sqlalchemy.orm import Session

from blog import schemas, oauth2, token
from blog.database import get_db
from blog.repository import blog

router = APIRouter(
    prefix="/blog",
    tags=["Blogs"]
)

@router.get("/", response_model=List[schemas.ShowBlog])
async def all(db: Session = Depends(get_db), current_user: schemas.User = Depends(oauth2.get_current_user)):
    return blog.get_all(db)

@router.post("/", status_code=status.HTTP_201_CREATED)
async def create_blog(request: schemas.Blog, db: Session = Depends(get_db),
                      current_user: schemas.User = Depends(oauth2.get_current_user)):
    return blog.create(request, db, current_user)

@router.get("/{id}", status_code=status.HTTP_200_OK, response_model=schemas.ShowBlog)
async def get_by_id(id: int, db: Session = Depends(get_db),
                    current_user: schemas.User = Depends(oauth2.get_current_user)):
    return blog.get_by_id(id, db)

@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete(id: int, db: Session = Depends(get_db), current_user: schemas.User = Depends(oauth2.get_current_user)):
    return blog.delete(id, db)

@router.put("/{id}", status_code=status.HTTP_202_ACCEPTED)
async def update(id: int, request: schemas.UpdateBlog, db: Session = Depends(get_db),
                 current_user: schemas.User = Depends(oauth2.get_current_user)):
    return blog.update(id, request, db)