import numpy as numpy
from astropy import units
import math
import warnings
from . import Tools

from .OrderProblem import OrderProblem

__author__ = "Do Kester"
__year__ = 2023
__license__ = "GPL3"
__version__ = "3.2.0"
__url__ = "https://www.bayesicfitting.nl"
__status__ = "Alpha"

#  * This file is part of the BayesicFitting package.
#  *
#  * BayesicFitting is free software: you can redistribute it and/or modify
#  * it under the terms of the GNU Lesser General Public License as
#  * published by the Free Software Foundation, either version 3 of
#  * the License, or ( at your option ) any later version.
#  *
#  * BayesicFitting is distributed in the hope that it will be useful,
#  * but WITHOUT ANY WARRANTY; without even the implied warranty of
#  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  * GNU Lesser General Public License for more details.
#  *
#  * The GPL3 license can be found at <http://www.gnu.org/licenses/>.
#  *
#  *    2018 - 2023 Do Kester

class SalesmanProblem( OrderProblem ):
    """
    Traveling Salesman Problem.

    The parameters give the order in which the nodes are visited.

    The result is a list of distances.

        [dist( x[p[k-1]], x[p[k]] ) for k in range( len( p ) )]

    The number of parameters is equal to the length of the xdata array
    The parameters are initialized at [k for k in range( npars )]

    Examples
    --------
    >>>  tsm = SalesmanProblem( 100 )
    >>> print( tsm )
    TravelingSalesman in 2 dimensions with 100 nodes.
    >>> print( tsm.npars )
    100

    """

    DISNAMES = ["User Defined", "Manhattan", "Euclidic", "Spherical", "Tabulated"]

    def __init__( self, xdata=None, weights=None, distance="euclid", scale=None, table=None,
                  oneway=False, copy=None ):
        """
        Traveling Salesman problem.

        Parameters
        ----------
        xdata : array_like of shape [np,ndim]
            the nodes to be visited
        weights : array_like
            weights on the arrival nodes
        distance : str or callable
            to calculate the distance between point1 and point2
            "manh"   : Manhattan distance (1 norm) (2 or more dimensions)
            "euclid" : Euclidic (2 norm) (2 or more dimensions)
            "spher"  : spherical, distance over sphere (2 dimensions only)
            "table"  : tabulated distance values
            callable of the form callable( xdata, pars )
        scale : None or float
            scale all distances by this number.
            None : take minimum distance as scale
        table : arraylike or None
            table of all distances, Only when distance is "tabulated"
        oneway : bool
            Don't close the loop; cut at position 0.
        copy : SalesmanProblem
            to be copied

        """
        super( ).__init__( xdata=xdata, weights=weights, copy=copy )

        if copy is not None :
            self.distance = copy.distance
            self.disname = copy.disname
            self.scale = copy.scale
            self.oneway = copy.oneway
            return

        self.oneway = oneway

        if callable( distance ) :
            self.distance = distance
            self.disname = self.DISNAMES[0]

        elif isinstance( distance, str ) :
            dis = distance.lower()[0]

            self.disname = self.DISNAMES[2]
            if dis == "e" :
                self.distance = self.euclidic
            elif dis == "m" :
                self.distance = self.manhattan
                self.disname = self.DISNAMES[1]
            elif dis == "s" :
                self.distance = self.spherical
                self.disname = self.DISNAMES[3]
            elif dis == "t" :
                self.distance = self.tabulated
                self.disname = self.DISNAMES[4]
                self.table = table
            else :
                warnings.warn( "Unknown distance ", distance, " Using euclidic in stead" )
                self.distance = self.euclidic
        else :
            warnings.warn( "Unknown distance ", distance, " Using euclidic in stead" )
            self.distance = self.euclidic

        mindis = self.minimumDistance()
        if mindis < 1e-10 :
            print( "SalesmanProblem. minimumDistance less than 1.e-10" )
            mindis = 1.0

        self.scale = scale if scale is not None else mindis

    def copy( self ):
        """ Copy method.  """
        return SalesmanProblem( xdata=self.xdata, weights=self.weights, copy=self )

    def acceptWeight( self ):
        """
        True if the distribution accepts weights.

        """
        return True

    def result( self, params ):
        """
        Calculates the distance between the nodes (xdata) in the order
        given by the parameters (params), multiplied by the weight at the
        starting node (if present), divided by the scale

        Each result is
            res[k] = dis[k] * weight[params[k]] / scale

        Parameters
        ----------
        params : array_like
            values for the parameters.

        Returns
        -------
        An array of distances

        """
        res = self.distance( self.xdata, params ) / self.scale

        if self.oneway :
            res[-1] = 0                     # dont return home.

        if self.weights is None :
            return res
        else :
            return res * self.weights[params]

    def manhattan( self, xdata, pars, roll=1 ) :
        """
        Use Manhattan distances (1-norm)

        Each distance is
            dis[k] = SUM_i ( abs( xdata[pars[k],i] - xdata[pars[k+roll],i] ) )

        Parameters
        ----------
        xdata : array-like of shape (ndata,ndim)
            positional info in several dimensions
        pars : list of indices
            designating the order of the nodess
        roll : int
            number of positions to roll
        """
        xd = xdata[pars]
        r = numpy.abs( xd - numpy.roll( xd, -roll, axis=0 ) )    ## leaving from xd
        return numpy.sum( r, 1 )

    def euclidic( self, xdata, pars, roll=1 ) :
        """
        Use Euclidic distances (2-norm)

        Each distance is
            dis[k] = sqrt( SUM_i ( ( xdata[pars[k],i] - xdata[pars[k+roll],i] )^2 ) )

        Parameters
        ----------
        xdata : array-like of shape (ndata,ndim)
            positional info in several dimensions
        pars : list of indices
            designating the order of the nodes
        roll : int
            number of positions to roll
        """
        xd = xdata[pars]
        r = numpy.square( xd - numpy.roll( xd, -roll, axis=0 ) )        ## leaving from xd
        return numpy.sqrt( numpy.sum( r, 1 ) )

    def spherical( self, xdata, pars, roll=1 ) :
        """
        Use distances over a 2-d unit sphere.

        Each distance is calculated according to the Haversine formula.

        It is assumed that the xdata is in decimal degrees: [longitude, latitude]

        The results are in radian.

        Parameters
        ----------
        xdata : array-like of shape (ndata,2)
            longitude, latitude info
        pars : list of indices
            designating the order of the nodes
        roll : int
            number of positions to roll
        """
        if not hasattr( self, "coslat1" ) :

            xd = xdata * math.pi / 180
            xh = xd / 2

            self.coslat1 = numpy.cos( xd[:,1] )

            self.shlon1 = numpy.sin( xh[:,0] )
            self.chlon1 = numpy.cos( xh[:,0] )
            self.shlat1 = numpy.sin( xh[:,1] )
            self.chlat1 = numpy.cos( xh[:,1] )

        cslat1 = self.coslat1[pars]

        shlon1 = self.shlon1[pars]
        chlon1 = self.chlon1[pars]
        shlat1 = self.shlat1[pars]
        chlat1 = self.chlat1[pars]

        cslat2 = numpy.roll( cslat1, -roll )
        shlon2 = numpy.roll( shlon1, -roll )
        chlon2 = numpy.roll( chlon1, -roll )
        shlat2 = numpy.roll( shlat1, -roll )
        chlat2 = numpy.roll( chlat1, -roll )

        a = ( numpy.square( shlat2 * chlat1 - shlat1 * chlat2 ) +
              cslat1 * cslat2 *
              numpy.square( shlon2 * chlon1 - shlon1 * chlon2 ) )

        # catch round-off error above 1.
        a = numpy.where( a > 1, 1.0, a )

        dis = 2 * numpy.arctan2( numpy.sqrt( a ), numpy.sqrt( 1 - a ) )

        return dis

    def tabulated( self, xdata, pars, roll=1 ) :
        """
        Use tabulated distances from self.table

        Each distance is
            dis[k] = table[ pars[k], pars[k+roll] ]

        Parameters
        ----------
        xdata : array-like of shape (ndata,ndim)
            positional info in several dimensions
        pars : list of indices
            designating the order of the nodess
        roll : int
            number of positions to roll
        """

        r = self.table[ pars, numpy.roll( pars, -roll ) ]
        return r

    def minimumDistance( self ) :
        """
        Return the smallest distance in the data.

        """
        ndata = len( self.xdata[:,0] )
        pars = numpy.arange( ndata, dtype=int )
        md = self.distance( self.xdata, pars ).min()
        for roll in range( 2, ndata ) :
            md = self.distance( self.xdata, pars, roll=roll ).min( initial=md )

        return md

    def baseName( self ):
        """
        Returns a string representation of the model.

        """
        return str( "TravelingSalesman in %d dimensions with %d nodes. %s distance" %
                    ( self.ndim, self.npars, self.disname ) )


from unittest import TestCase
from unittest.mock import Mock, call

from reconbot.notificationprinters.slack import Slack

class SlackTest(TestCase):
    def setUp(self):
        self.eve_mock = Mock()
        self.printer = Slack(self.eve_mock)

        self.timestamp = 1451649600 # 2016-01-01 12:00:00

        self.ccp_alliance = {
            'id': 434243723,
            'name': 'C C P Alliance'
        }

        self.ccp_corporation = {
            'id': 98356193,
            'name': 'C C P Alliance Holding',
            'alliance_id': 434243723
        }

        self.game_masters_corporation = {
            'id': 216121397,
            'name': 'Game Masters',
            'alliance_id': 434243723
        }

        self.ccp_falcon = {
            'id': 92532650,
            'name': 'CCP Falcon',
            'corp': self.ccp_corporation,
            'alliance': self.ccp_alliance
        }

        self.ccp_someone = {
            'id': 92532651,
            'name': 'CCP Someone',
            'corp': self.ccp_corporation
        }

        self.hed_gp = {
            'id': 30001161,
            'name': 'HED-GP',
            'region': 10000014
        }

        self.hed_gp_planet = {
            'id': 40073894,
            'name': 'HED-GP I',
            'system_id': self.hed_gp['id'],
        }

        self.hed_gp_moon = {
            'id': 40073896,
            'name': 'HED-GP II - Moon 1'
        }

        self.amarr_control_tower = {
            'id': 12235,
            'name': 'Amarr Control Tower'
        }

        self.fitting_service = {
            'id': 28155,
            'name': 'Fitting Service'
        }

        self.ihub = {
            'id': 32458,
            'name': 'Infrastructure Hub'
        }

        self.station = {
            'id': 1529,
            'name': 'Caldari Administrative Station'
        }

        self.astrahus = {
            'id': 35832,
            'name': 'Astrahus'
        }

        self.campaign_event_types = {
            'tcu': 1,
            'ihub': 2,
            'station': 3
        }

        self.standup_cloning_center = {
            'id': 35894,
            'name': 'Standup Cloning Center I'
        }

        self.ichooseyou_hub_fortizar = {
            'structure_id': 1023164547009,
            'structure': {
                "typeId": 35833,
                "regionId": 10000002,
                "typeName": "Fortizar",
                "lastSeen": "2017-07-02T11:37:44.359Z",
                "firstSeen": "2017-01-13T18:07:24Z",
                "regionName": "The Forge",
                "name": "Perimeter - IChooseYou Trade Hub",
                "systemId": 30000144,
                "location": {
                    "y": 44793533020.0,
                    "x": 660596273924.0,
                    "z": 2112970671473.0},
                "systemName": "Perimeter",
                "public": True
            }
        }

        self.eve_mock.get_alliance_name_by_id.return_value = self.ccp_alliance['name']
        self.eve_mock.get_corporation_name_by_id.return_value = self.ccp_corporation['name']
        self.eve_mock.get_character_by_id.return_value = self.ccp_falcon
        self.eve_mock.get_system_by_id.return_value = self.hed_gp
        self.eve_mock.get_planet_by_id.return_value = self.hed_gp_planet
        self.eve_mock.get_moon_by_id.return_value = self.hed_gp_moon
        self.eve_mock.get_item_by_id.return_value = self.amarr_control_tower
        self.eve_mock.get_structure_by_id.return_value = self.ichooseyou_hub_fortizar['structure']

    def test_get_alliance(self):
        self.assertEqual(
            self.printer.get_alliance(self.ccp_alliance['id']),
            '<https://zkillboard.com/alliance/434243723/|C C P Alliance>'
        )

        self.eve_mock.get_alliance_name_by_id.assert_called_once_with(
            self.ccp_alliance['id']
        )

    def test_get_corporation_without_alliance(self):
        self.assertEqual(
            self.printer.get_corporation(self.ccp_corporation['id']),
            '<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding>'
        )

        self.eve_mock.get_corporation_name_by_id.assert_called_once_with(
            self.ccp_corporation['id']
        )

    def test_get_corporation_with_alliance(self):
        self.assertEqual(
            self.printer.get_corporation(
                self.ccp_corporation['id'],
                self.ccp_alliance['id']
            ),
            '<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>)'
        )

        self.eve_mock.get_corporation_name_by_id.assert_called_once_with(
            self.ccp_corporation['id']
        )
        self.eve_mock.get_alliance_name_by_id.assert_called_once_with(
            self.ccp_alliance['id']
        )

    def test_get_character(self):
        self.assertEqual(
            self.printer.get_character(self.ccp_falcon['id']),
            '<https://zkillboard.com/character/92532650/|CCP Falcon> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>))'
        )

        self.eve_mock.get_character_by_id.assert_called_once_with(
            self.ccp_falcon['id']
        )
        self.eve_mock.get_corporation_name_by_id.assert_called_once_with(
            self.ccp_corporation['id']
        )
        self.eve_mock.get_alliance_name_by_id.assert_called_once_with(
            self.ccp_alliance['id']
        )

    def test_get_character_without_alliance(self):
        self.eve_mock.get_character_by_id.return_value = self.ccp_someone
        self.assertEqual(
            self.printer.get_character(self.ccp_someone['id']),
            '<https://zkillboard.com/character/92532651/|CCP Someone> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding>)'
        )

    def test_get_system(self):
        self.assertEqual(
            self.printer.get_system(self.hed_gp['id']),
            '<http://evemaps.dotlan.net/system/HED-GP|HED-GP>'
        )

        self.eve_mock.get_system_by_id.assert_called_once_with(
            self.hed_gp['id']
        )

    def test_get_planet(self):
        self.assertEqual(
            self.printer.get_planet(self.hed_gp_planet['id']),
            'HED-GP I in <http://evemaps.dotlan.net/system/HED-GP|HED-GP>'
        )

        self.eve_mock.get_system_by_id.assert_called_once_with(
            self.hed_gp['id']
        )

    def test_get_item(self):
        self.assertEqual(
            self.printer.get_item(self.amarr_control_tower['id']),
            'Amarr Control Tower'
        )

        self.eve_mock.get_item_by_id.assert_called_once_with(
            self.amarr_control_tower['id']
        )

    def test_get_campaign_event_type(self):
        self.assertEqual(
            self.printer.get_campaign_event_type(self.campaign_event_types['tcu']),
            'TCU'
        )

        self.assertEqual(
            self.printer.get_campaign_event_type(self.campaign_event_types['ihub']),
            'IHUB'
        )

        self.assertEqual(
            self.printer.get_campaign_event_type(self.campaign_event_types['station']),
            'Station'
        )

        self.assertEqual(
            self.printer.get_campaign_event_type(9999),
            'Unknown structure type "9999"'
        )

    def test_get_structure_name_by_id(self):
        self.assertEqual(
            self.printer.get_structure_name_by_id(self.ichooseyou_hub_fortizar['structure_id']),
            self.ichooseyou_hub_fortizar['structure']['name']
        )

    def test_transforms_unknown_notification_type(self):
        notification = {
            'notification_type': 9999,
            'notification_timestamp': self.timestamp
        }

        self.assertEqual(
            self.printer.transform(notification),
            '[2016-01-01 12:00:00] Unknown notification type for printing'
        )

    def test_sov_claim_lost(self):
        notification = {
            'notification_type': 41,
            'corpID': self.ccp_corporation['id'],
            'allianceID': self.ccp_alliance['id'],
            'solarSystemID': self.hed_gp['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'SOV lost in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> by <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>)'
        )

    def test_corporation_war_declared(self):
        self.eve_mock.get_corporation_name_by_id.side_effect = lambda ID: self.game_masters_corporation['name'] if ID is self.game_masters_corporation['id'] else self.ccp_corporation['name']
        notification = {
            'notification_type': 27,
            'againstID': self.ccp_corporation['id'],
            'declaredByID': self.game_masters_corporation['id'],
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'War has been declared to <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> by <https://zkillboard.com/corporation/216121397/|Game Masters>'
        )

    def test_sov_claim_acquired(self):
        notification = {
            'notification_type': 43,
            'corpID': self.ccp_corporation['id'],
            'allianceID': self.ccp_alliance['id'],
            'solarSystemID': self.hed_gp['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'SOV acquired in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> by <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>)'
        )

    def test_pos_anchoring_alert(self):
        notification = {
            'notification_type': 45,
            'corpID': self.ccp_corporation['id'],
            'allianceID': self.ccp_alliance['id'],
            'moonID': self.hed_gp_moon['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'New POS anchored in "HED-GP II - Moon 1" by <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>)'
        )

    def test_pos_attack(self):
        notification = {
            'notification_type': 75,
            'moonID': self.hed_gp_moon['id'],
            'aggressorID': self.ccp_falcon['id'],
            'typeID': self.amarr_control_tower['id'],
            'shieldValue': 0.917,
            'armorValue': 0.91,
            'hullValue': 0.903,
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'HED-GP II - Moon 1 POS "Amarr Control Tower" (91.7% shield, 91.0% armor, 90.3% hull) under attack by <https://zkillboard.com/character/92532650/|CCP Falcon> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>))'
        )

    def test_station_conquered(self):
        notification = {
            'notification_type': 79,
            'solarSystemID': self.hed_gp['id'],
            'oldOwnerID': self.ccp_corporation['id'],
            'newOwnerID': self.ccp_corporation['id'],
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Station conquered from <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> by <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> in <http://evemaps.dotlan.net/system/HED-GP|HED-GP>'
        )

    def test_poco_attack(self):
        notification = {
            'notification_type': 93,
            'planetID': self.hed_gp_planet['id'],
            'aggressorID': self.ccp_falcon['id'],
            'shieldLevel': 0.917,
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            '"HED-GP I in <http://evemaps.dotlan.net/system/HED-GP|HED-GP>" POCO (91% shields) has been attacked by <https://zkillboard.com/character/92532650/|CCP Falcon> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>))'
        )

    def test_poco_reinforce(self):
        notification = {
            'notification_type': 94,
            'planetID': self.hed_gp_planet['id'],
            'aggressorID': self.ccp_falcon['id'],
            'reinforceExitTime': 131189759320000000
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            '"HED-GP I in <http://evemaps.dotlan.net/system/HED-GP|HED-GP>" POCO has been reinforced by <https://zkillboard.com/character/92532650/|CCP Falcon> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>)) (comes out of reinforce on "2016-09-21 23:58:52")'
        )

    def test_structure_transfer(self):
        self.eve_mock.get_corporation_name_by_id.side_effect = lambda ID: self.game_masters_corporation['name'] if ID is self.game_masters_corporation['id'] else self.ccp_corporation['name']
        notification = {
            'notification_type': 95,
            'fromCorporationName': self.game_masters_corporation['name'],
            'fromCorporationLinkData': ['showinfo', 2, self.game_masters_corporation['id']],
            'toCorporationName': self.ccp_corporation['name'],
            'toCorporationLinkData': ['showinfo', 2, self.ccp_corporation['id']],
            'structureName': 'HED-GP Freeport Citadel',
            'structureLinkData': ['showinfo', self.astrahus['id'], 1021121988766],
            'solarSystemName': self.hed_gp['name'],
            'solarSystemLinkData': ['showinfo', 5, self.hed_gp['id']],
            'characterName': self.ccp_falcon['name'],
            'characterLinkData': ['showinfo', 1377, self.ccp_falcon['id']],
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            '"HED-GP Freeport Citadel" structure in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has been transferred from <https://zkillboard.com/corporation/216121397/|Game Masters> to <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> by <https://zkillboard.com/character/92532650/|CCP Falcon> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>))'
        )

    def test_entosis_capture_started(self):
        self.eve_mock.get_item_by_id.return_value = self.fitting_service
        notification = {
            'notification_type': 147,
            'solarSystemID': self.hed_gp['id'],
            'structureTypeID': self.fitting_service['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Capturing of "Fitting Service" in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has started'
        )

    def test_entosis_enabled_structure(self):
        self.eve_mock.get_item_by_id.return_value = self.fitting_service
        notification = {
            'notification_type': 148,
            'solarSystemID': self.hed_gp['id'],
            'structureTypeID': self.fitting_service['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Structure "Fitting Service" in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has been enabled'
        )

    def test_entosis_disabled_structure(self):
        self.eve_mock.get_item_by_id.return_value = self.fitting_service
        notification = {
            'notification_type': 149,
            'solarSystemID': self.hed_gp['id'],
            'structureTypeID': self.fitting_service['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Structure "Fitting Service" in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has been disabled'
        )

    def test_sov_structure_reinforced(self):
        notification = {
            'notification_type': 160,
            'solarSystemID': self.hed_gp['id'],
            'campaignEventType': self.campaign_event_types['tcu'],
            'decloakTime': 131189759320000000
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'SOV structure "TCU" in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has been reinforced, nodes will decloak "2016-09-21 23:58:52"'
        )

    def test_sov_structure_command_nodes_decloaked(self):
        notification = {
            'notification_type': 161,
            'solarSystemID': self.hed_gp['id'],
            'campaignEventType': self.campaign_event_types['tcu'],
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Command nodes for "TCU" SOV structure in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> have decloaked'
        )

    def test_sov_structure_destroyed(self):
        self.eve_mock.get_item_by_id.return_value = self.ihub
        notification = {
            'notification_type': 162,
            'solarSystemID': self.hed_gp['id'],
            'structureTypeID': self.ihub['id']
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'SOV structure "Infrastructure Hub" in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has been destroyed'
        )

        self.eve_mock.get_item_by_id.assert_called_once_with(
            self.ihub['id']
        )

    def test_sov_structure_freeported(self):
        self.eve_mock.get_item_by_id.return_value = self.station
        notification = {
            'notification_type': 163,
            'solarSystemID': self.hed_gp['id'],
            'structureTypeID': self.station['id'],
            'freeportexittime': 131189759320000000
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'SOV structure "Caldari Administrative Station" in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> has been freeported, exits freeport on "2016-09-21 23:58:52"'
        )

        self.eve_mock.get_item_by_id.assert_called_once_with(
            self.station['id']
        )

    def test_citadel_low_fuel(self):
        self.eve_mock.get_item_by_id.return_value = self.astrahus
        notification = {
            'notification_type': 181,
            'solarsystemID': self.hed_gp['id'],
            'listOfTypesAndQty': [[149, 4247]],
            'structureID': 1021121988766,
            'structureShowInfoData': ['showinfo', self.astrahus['id'], 1021121988766]
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Citadel (Astrahus, "Perimeter - IChooseYou Trade Hub") low fuel alert in <http://evemaps.dotlan.net/system/HED-GP|HED-GP>'
        )

    def test_citadel_anchored(self):
        self.eve_mock.get_item_by_id.return_value = self.astrahus
        notification = {
            'notification_type': 182,
            'solarsystemID': self.hed_gp['id'],
            'vulnerableTime': 9000000000,
            'timeLeft': 864000385106,
            'ownerCorpName': self.ccp_corporation['name'],
            'ownerCorpLinkData': ['showinfo', 2, self.ccp_corporation['id']],
            'structureID': 1021121988766,
            'structureShowInfoData': ['showinfo', self.astrahus['id'], 1021121988766]
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Citadel (Astrahus, "Perimeter - IChooseYou Trade Hub") anchored in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> by <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding>'
        )

    def test_citadel_attacked(self):
        self.eve_mock.get_item_by_id.return_value = self.astrahus
        notification = {
            'notification_type': 184,
            'solarsystemID': self.hed_gp['id'],
            'structureID': 1021121988766,
            'structureShowInfoData': ['showinfo', self.astrahus['id'], 1021121988766],
            'charID': self.ccp_falcon['id'],
            'allianceName': self.ccp_alliance['name'],
            'shieldPercentage': 5.459048365958682e-13,
            'corpLinkData': ['showinfo', 2, self.ccp_corporation['id']],
            'allianceID': self.ccp_alliance['id'],
            'allianceLinkData': ['showinfo', 16159, self.ccp_alliance['id']],
            'corpName': self.ccp_corporation['name'],
            'hullPercentage': 99.79458190646601,
            'armorPercentage': 0.0
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Citadel (Astrahus, "Perimeter - IChooseYou Trade Hub") attacked (0.0% shield, 0.0% armor, 99.8% hull) in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> by <https://zkillboard.com/character/92532650/|CCP Falcon> (<https://zkillboard.com/corporation/98356193/|C C P Alliance Holding> (<https://zkillboard.com/alliance/434243723/|C C P Alliance>))'
        )

    def test_citadel_onlined(self):
        self.eve_mock.get_item_by_id.return_value = self.astrahus
        notification = {
            'notification_type': 185,
            'solarsystemID': self.hed_gp['id'],
            'structureID': 1021121988766,
            'structureShowInfoData': ['showinfo', self.astrahus['id'], 1021121988766]
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Citadel (Astrahus, "Perimeter - IChooseYou Trade Hub") onlined in <http://evemaps.dotlan.net/system/HED-GP|HED-GP>'
        )

    def test_citadel_destroyed(self):
        self.eve_mock.get_item_by_id.return_value = self.astrahus
        notification = {
            'notification_type': 188,
            'solarsystemID': self.hed_gp['id'],
            'structureID': 1021121988766,
            'ownerCorpLinkData': ['showinfo', 2, self.ccp_corporation['id']],
            'ownerCorpName': self.ccp_corporation['name'],
            'structureShowInfoData': ['showinfo', self.astrahus['id'], 1021911646506]
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Citadel (Astrahus, "Perimeter - IChooseYou Trade Hub") destroyed in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> owned by <https://zkillboard.com/corporation/98356193/|C C P Alliance Holding>'
        )

    def test_citadel_out_of_fuel(self):
        self.eve_mock.get_item_by_id.side_effect = lambda ID: self.astrahus if ID is self.astrahus['id'] else self.standup_cloning_center
        notification = {
            'notification_type': 198,
            'listOfServiceModuleIDs': [self.standup_cloning_center['id']],
            'solarsystemID': self.hed_gp['id'],
            'structureID': 1021121988766,
            'structureShowInfoData': ['showinfo', self.astrahus['id'], 1021121988766]
        }

        self.assertEqual(
            self.printer.get_notification_text(notification),
            'Citadel (Astrahus, "Perimeter - IChooseYou Trade Hub") ran out of fuel in <http://evemaps.dotlan.net/system/HED-GP|HED-GP> with services "Standup Cloning Center I"'
        )
        self.eve_mock.get_item_by_id.assert_any_call(self.astrahus['id'])
        self.eve_mock.get_item_by_id.assert_any_call(self.standup_cloning_center['id'])


# !/usr/bin/python3
import re
#la fonction qui permet de détecter l'OS utilisé
def detect_os(systemAgent):
	if 'Windows' in systemAgent:
		return 'Windows'
	if 'Linux' in systemAgent:
		return 'Linux'
	if 'Mac' in systemAgent:
		return 'Mac'
	else:
		return 'unknown'
#la fonction qui permet de séparer les infos dans un ligne
def parse_line(line):
		ip=line.split(' ')
		get=line.split('"')

		return dict(
			remote_ip=ip[0],
			time=ip[3]+ip[4],
			request=get[1],
			response=ip[8],
			byte=ip[9],
			referrer=ip[10],
			system_agent=get[5],
			OS=detect_os(get[5])
		)

def readF(f):
    dictparline=[]
	#ouvrir et parcour par chaque ligne du fichier
    for line in open(f,'r'):
        #enregistrer les infos de chaque ligne dans une liste
        dictparline.append(parse_line(line))
    return dictparline

print(readF('apache.log'))


# Даны несколько точек на плоскости, некоторые из которых соединены отрезками. Множество точек называется связанным, если из любой его точки можно перейти в любую точку, перемещаясь только по отрезкам (переходить с отрезка на отрезок возможно только в точках исходного множества). Можно за определенную плату добавлять новые отрезки (стоимость добавления равна длине добавляемого отрезка). Требуется за минимальную стоимость сделать данное множество связанным.

def solve(input):
  lines = [s for s in input.splitlines() if s]

  n = int(lines.pop(0))
  graph = createGraph(cities, lines)

  cities, avia_flights, nights_left, start_city, end_city = map(int, lines.pop(0).split())

# ============= main
input = '''
3
1 1
1 2
10 1
1
2 1
'''

solve(input)


import os

class Sound:
    def start_music(self, name, is_game_on=False):
        self.stop_music()
        if os.name == "posix":
            os.system(f"afplay sounds/{name}.wav&")
            if is_game_on:
                os.system("say grid is live!&")
        elif os.name == "nt":
            winsound.PlaySound(bgm, winsound.SND_ASYNC)

    def stop_music(self):
        if os.name == "posix":
            os.system("killall afplay")
        elif os.name == "nt":
            winsound.PlaySound(None, winsound.SND_PURGE)

    def play_sfx(self, sound):
        if os.name == "posix":
            os.system(f"afplay sounds/{sound}.wav&")
        elif os.name == "nt":
            # winsound.PlaySound(sound, winsound.SND_ASYNC)
            # can't play simoutaneous sounds
            pass


import video_maker
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras

# Create initial model
def create_model(function_name, layers, neurons):
    # Define the model architecture
    model = keras.Sequential([
        keras.layers.Dense(neurons, activation="sigmoid", input_shape=(1,)),
    ])

    for _ in range(layers - 1):
        model.add(keras.layers.Dense(neurons, activation="sigmoid"))

    model.add(keras.layers.Dense(1))
    model.save(f"models/{function_name}_model.h5")

    model.compile(optimizer="adam", loss="mean_squared_error")

    return model

# Create train/test data for the model
def create_data(function_name, length):
    # Generate sine data
    if function_name == "sine":
        x = np.linspace(0, length * np.pi, length * 100)
        y = np.sin(x)

    elif function_name == "cosine":
        x = np.linspace(0, length * np.pi, length * 100)
        y = np.cos(x)

    elif function_name == "tangent":
        x = np.linspace(-(length / 2) * np.pi, (length / 2) * np.pi, length * 100)
        y = np.tan(x)

    elif function_name == "cotangent":
        x = np.linspace(-(length / 2) * np.pi, (length / 2) * np.pi, length * 100)
        y = 1 / np.tan(x)

    return x, y

# Train the model. Return a video if desired
def use_model(model, x, y, cycles, function_name, update_label_text, video_check):
    if video_check == 1:
        frame_writer = video_maker.create_video_formatter(function_name)

    # Train the model
    for cycle in range(cycles):
        model.fit(x, y, epochs=100, verbose=1)
        y_pred = model.predict(x)

        fig, ax = plt.subplots()
        ax.plot(x, y, label="Original")
        ax.plot(x, y_pred, label="Predicted")
        ax.set_title(f"{function_name.capitalize()} Wave Prediction")
        ax.legend()

        if function_name == "sine" or function_name == "cosine":
            ax.set_ylim(-1.2, 1.2)

        elif function_name == "tangent" or function_name == "cotangent":
            ax.set_ylim(-5, 5)

        # Save the current plot as an image file
        fig.savefig(f"plot_images/plot_{str(cycle)}.png")
        plt.close(fig)

        if video_check == 1:
            video_maker.add_frame(frame_writer, cycle)

        update_label_text(f"{cycle + 1} / {cycles} Cycles")

    if video_check == 1:
        video_maker.release_video(frame_writer)

    history = model.fit(x, y, epochs=100, verbose=1)
    final_loss = history.history["loss"][-1]

    if final_loss > 999999999:
        return "A lot"

    else:
        return str("{:.8f}".format(final_loss))


import gc
import json
import os
import pickle
from datetime import datetime

import astral
import cv2
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from astral.sun import sun
from object_detection import object_detection
from pytz import timezone
from tqdm import tqdm

image_dir = 'tmp'

image_files = [os.path.join(image_dir, f)
               for f in os.listdir(image_dir) if f.endswith('.jpg')]
image_files_iter = iter(image_files)

output_list = []

image_files_in_output_list = [output['image_file'] for output in output_list]

for image_file in tqdm(image_files_iter):
    if image_file not in image_files_in_output_list:
        detection_result = object_detection(image_file)
        detection_result_json = detection_result.pandas().xyxy[0].to_json()
        print('image_file', image_file)
        print('detection_result_json', detection_result_json)
        output_list.append({
            'image_file': image_file,
            'detection_result': detection_result_json
        })
        # Explicitly delete the detection_result and call the garbage collector
        del detection_result
        gc.collect()

for item in tqdm(output_list):

    detection_results = json.loads(item['detection_result'])
    # print('detection_results', detection_results)
    # Remove heavily overlapping bounding boxes, keeping the one with higher confidence
    i = 0
    while i < len(detection_results['name']):
        j = i + 1
        while j < len(detection_results['name']):
            # Calculate the intersection over union (IoU) of the two bounding boxes
            # print(detection_results)
            if str(i) in detection_results['xmin'] and str(j) in detection_results['xmin']:
                xi1 = max(detection_results['xmin'][str(i)],
                          detection_results['xmin'][str(j)])
                yi1 = max(detection_results['ymin'][str(i)],
                          detection_results['ymin'][str(j)])
                xi2 = min(detection_results['xmax'][str(i)],
                          detection_results['xmax'][str(j)])
                yi2 = min(detection_results['ymax'][str(i)],
                          detection_results['ymax'][str(j)])
                inter_area = max(0, xi2 - xi1 + 1) * max(0, yi2 - yi1 + 1)
                box1_area = (detection_results['xmax'][str(i)] - detection_results['xmin'][str(i)] + 1) * (
                    detection_results['ymax'][str(i)] - detection_results['ymin'][str(i)] + 1)
                box2_area = (detection_results['xmax'][str(j)] - detection_results['xmin'][str(j)] + 1) * (
                    detection_results['ymax'][str(j)] - detection_results['ymin'][str(j)] + 1)
                iou = inter_area / float(box1_area + box2_area - inter_area)

                # If the IoU is greater than 0.5, they are heavily overlapping
                if iou > 0.5:
                    print(
                        f"Processing image {item['image_file']}")
                    print(iou)
                    print("detection_results['confidence'][str(i)]",
                          detection_results['confidence'][str(i)])
                    print("detection_results['confidence'][str(j)]",
                          detection_results['confidence'][str(j)])
                    print(
                        f"Removed bounding box for {detection_results} in image {item['image_file']}")
                    # Remove the bounding box with lower confidence
                    if detection_results['confidence'][str(i)] > detection_results['confidence'][str(j)]:
                        detection_results['name'].pop(str(j))
                        detection_results['xmin'].pop(str(j))
                        detection_results['ymin'].pop(str(j))
                        detection_results['xmax'].pop(str(j))
                        detection_results['ymax'].pop(str(j))
                        detection_results['confidence'].pop(str(j))
                    else:

                        detection_results['name'].pop(str(i))
                        detection_results['xmin'].pop(str(i))
                        detection_results['ymin'].pop(str(i))
                        detection_results['xmax'].pop(str(i))
                        detection_results['ymax'].pop(str(i))
                        detection_results['confidence'].pop(str(i))

                        i -= 1
                    break
            j += 1
        i += 1

with open('output_list.pkl', 'wb') as f:
    pickle.dump(output_list, f)

with open('output_list.pkl', 'rb') as f:
    output_list = pickle.load(f)

location = astral.LocationInfo(
    "Oakland", "USA", "US/Pacific", 37.8044, -122.2712
)

for output in output_list:
    filename = output['image_file'].split('/')[-1]
    camera_name, date, hour, minutes = filename.split('_')[2], filename.split(
        '_')[3], filename.split('_')[6], filename.split('_')[7].split('.')[0]
    seconds = filename.split('_')[7].split('.')[1][0:2]
    year, month, day = date.split('-')
    output['camera_name'] = camera_name
    output['datetime'] = datetime(int(year), int(month), int(
        day), int(hour), int(minutes), int(seconds))
    # Use astral library to get sun information for the specific date and location
    s = sun(location.observer, date=output['datetime'].date(
    ), tzinfo=timezone('US/Pacific'))

    # Classify the lighting based on the sun information
    if s['dawn'].time() <= output['datetime'].time() < s['sunrise'].time():
        output['lighting'] = 'dawn'
    elif s['sunrise'].time() <= output['datetime'].time() < s['sunset'].time():
        output['lighting'] = 'day'
    elif s['sunset'].time() <= output['datetime'].time() < s['dusk'].time():
        output['lighting'] = 'dusk'
    else:
        output['lighting'] = 'night'

for output in output_list:
    print(output['image_file'], output['lighting'])
    # Load the image
    img = cv2.imread(output['image_file'])

    # Load the detection results
    detection_results = json.loads(output['detection_result'])

    # Draw bounding boxes and labels on the image
    for i in range(len(detection_results['name'])):
        xmin = int(detection_results['xmin'][str(i)])
        ymin = int(detection_results['ymin'][str(i)])
        xmax = int(detection_results['xmax'][str(i)])
        ymax = int(detection_results['ymax'][str(i)])
        label = detection_results['name'][str(i)]
        # Convert confidence to percentage
        confidence = int(float(detection_results['confidence'][str(i)]) * 100)
        # Add confidence to label
        label_with_confidence = f"{label} {confidence}%"

        # Draw bounding box
        cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)
        # Calculate label size and position
        (label_width, label_height), baseline = cv2.getTextSize(
            label_with_confidence, cv2.FONT_HERSHEY_SIMPLEX, 1.5, 3)
        label_ymin = max(ymin, label_height + 10)
        # Draw black background rectangle
        cv2.rectangle(img, (xmin, label_ymin - label_height - 10), (xmin +
                      label_width, label_ymin + baseline - 10), (0, 0, 0), cv2.FILLED)
        # Add label with confidence on the black background
        cv2.putText(img, label_with_confidence, (xmin, label_ymin - 7),
                    cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 255, 255), 3)

    # Add 'lighting' label in the upper right hand side
    lighting_label = output['lighting']
    cv2.putText(img, lighting_label, (img.shape[1] - 100, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)

    # Save the image in the 'tmp_labeled' directory
    labeled_image_file = os.path.join(
        'tmp_labeled', output['image_file'].split('/')[-1])
    cv2.imwrite(labeled_image_file, img)

# df = pd.DataFrame(output_list)

# Get simple counts of events based on camera_name from output_list
camera_counts = {}
for output in output_list:
    camera_name = output['camera_name']
    if camera_name not in camera_counts:
        camera_counts[camera_name] = 0
    camera_counts[camera_name] += 1

object_dict = {}
for output in output_list:
    detection_results = json.loads(output['detection_result'])
    for i in range(len(detection_results['name'])):
        object_name = detection_results['name'][str(i)]
        if object_name not in object_dict:
            object_dict[object_name] = []
        object_dict[object_name].append(output)

# Create a dictionary to store confidence intervals
confidence_buckets = {'0-25%': [],
                      '26-50%': [], '51-75%': [], '76-100%': []}

# Iterate over the object dictionary
for object_name, outputs in object_dict.items():
    if object_name in ['car', 'truck']:
        for output in outputs:
            detection_results = json.loads(output['detection_result'])
            for i in range(len(detection_results['name'])):
                if detection_results['name'][str(i)] == object_name:
                    confidence = int(
                        float(detection_results['confidence'][str(i)]) * 100)
                    if confidence <= 25:
                        bucket = '0-25%'
                    elif confidence <= 50:
                        bucket = '26-50%'
                    elif confidence <= 75:
                        bucket = '51-75%'
                    else:
                        bucket = '76-100%'
                    confidence_buckets[bucket].append(
                        (output['lighting'], output['datetime'], output['camera_name'], output['image_file'].split('/')[-1].split('.')[0]))
# Create a dictionary to store the count of each bucket per day
bucket_counts_per_day = {}
for bucket, data in confidence_buckets.items():
    df = pd.DataFrame(
        data, columns=['lighting', 'datetime', 'camera_name', 'image_filename'])
    df['date'] = pd.to_datetime(df['datetime'])
    df['day_of_week'] = df['date'].dt.day_name()
    # Add date in unixtime for sorting later
    df['date_str'] = df['date'].dt.strftime('%Y-%m-%d')
    df.set_index('day_of_week', inplace=True)
    bucket_counts = df.groupby(['day_of_week', 'date_str', 'lighting']).size()
    bucket_counts_per_day[bucket] = bucket_counts

bucket_counts_df = pd.DataFrame(bucket_counts_per_day)
bucket_counts_df = bucket_counts_df.fillna(0)
bucket_counts_df = bucket_counts_df.stack().reset_index()
bucket_counts_df.columns = ['day_of_week', 'date_str',
                            'lighting', 'bucket', 'count']

# Calculate the total count for each day_of_week and lighting
total_counts = bucket_counts_df.groupby(['day_of_week', 'lighting'])[
    'count'].sum().reset_index()
total_counts.columns = ['day_of_week', 'lighting', 'total']

# Merge the total counts back to the original dataframe
bucket_counts_df = pd.merge(bucket_counts_df, total_counts, on=[
                            'day_of_week', 'lighting'])

# Calculate the percentage
bucket_counts_df['percentage'] = bucket_counts_df['count'] / \
    bucket_counts_df['total'] * 100

bucket_counts_df = bucket_counts_df[bucket_counts_df['date_str']
                                    != '2023-11-11']

bucket_counts_df = bucket_counts_df[bucket_counts_df['date_str']
                                    != '2023-11-07']

sns.set(style="whitegrid")
if 'percentage' in bucket_counts_df.columns:
    # Pivot the dataframe to create a 100% stacked bar chart
    pivot_df = bucket_counts_df.pivot_table(
        index=['lighting', 'date_str'], columns='bucket', values='percentage')
    pivot_df = pivot_df.div(pivot_df.sum(axis=1), axis=0).multiply(100)
    # Sort the dataframe by date_str and lighting
    # pivot_df = pivot_df.sort_values(by=['date_str', 'lighting'])
    plot = pivot_df.plot(kind='bar', stacked=True, colormap='RdYlGn')
    # Rotate x-axis labels for better visibility and adjust for auto-fit
    labels = bucket_counts_df['lighting'] + ', ' + bucket_counts_df['date_str']
    sorted_labels = sorted(labels.unique())
    plt.xticks(ticks=range(len(sorted_labels)),
               rotation=45, ha='right', labels=sorted_labels)
    plt.tight_layout()
    # Move the legend outside the plot
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
else:
    print("Error: 'percentage' column not found in the dataframe.")
plt.title('Confidence Distribution of Cars and Trucks by Day and by Sun Phase')
plt.savefig('Confidence_Distribution_per_Day_of_Week_and_Lighting.png',
            bbox_inches='tight')
plt.close()

# create a normalized list of car and truck objects from the output_list
# crop each image to the bounding box of the car or truck
# save the cropped image to a new directory
# create a list of the cropped images
# run the cropped images through the license plate recognition model
# run the cropped images through the car recognition model
# for each recognized plate, run through DMV database
# create a funnel visualization for performance of each step


#!/usr/bin/python3 -B
# -*- coding: utf-8 -*- line endings: unix -*-
__author__ = 'quixadhal'

import os
import sys
import datetime
sys.path.append(os.path.join(os.getcwd(), "Mud"))

# Normally, we always import logging and initialize it BEFORE anything
# else, but in this case, we first need to add to our module search
# path, so we'll trust nothing will explode in os or sys at the top
# level here.

from Mud.log_system import Logger
logger = Logger()

from Mud.cli_args import CLI_Args
from Mud.signals import setup_signals
from Mud.game_data import Game_Data

def changedir(pathname):
    if pathname is not None:
        try:
            os.chdir(pathname)
        except FileNotFoundError as err:
            logger.critical('Invalid directory: %s', err)
            sys.exit(2)
        except PermissionError as err:
            logger.critical('Invalid directory: %s', err)
            sys.exit(2)
    return True

def makepid(pathname):
    if pathname is not None:
        try:
            f = open(pathname, 'w')
            f.write(str(os.getpid()))
            f.close()
        except FileNotFoundError as err:
            logger.critical('Invalid PID file: %s', err)
            sys.exit(2)
        except PermissionError as err:
            logger.critical('Invalid PID file: %s', err)
            sys.exit(2)
    return True

def removefile(pathname):
    if pathname is not None:
        try:
            os.unlink(pathname)
        except FileNotFoundError as err:
            return True
        except PermissionError as err:
            logger.critical('Invalid file: %s', err)
            sys.exit(2)
    return True

if __name__ == '__main__':
    logger.boot('System initializing.')
    start_time = datetime.datetime.utcnow()
    args = CLI_Args()

    changedir(args.directory)
    makepid(args.pidfile)
    removefile(args.logfile)
    logger.start_filelog(args.logfile)

    logger.boot('System booting.')
    logger.info(args)
    logger.info("Player port is %d" % args.port)

    # Here is where we call the outer game loop
    # In wiley's comm.c, that would be run_the_game()

    # set descriptor list to empty
    setup_signals()
    # s = init_socket(port) # Main socket connection
    gameData = Game_Data()
    gameData.import_wileymud()
    # load_db()
    # init_whod(port) # web server who daemon
    # i3_startup(false, 3000, false)
    # game_loop()
    # i3_shutdown()
    # close_sockets(s)
    # close_whod()
    # unload_db()
    # if reboot message about rebooting, return reboot code
    # else message about shutdown, return shutdown code

    # And here we'd be done with that...

    run_length = datetime.datetime.utcnow() - start_time
    logger.info('System was up for %s' % run_length)

    logger.critical('System halting.')
    removefile(args.pidfile)
    logger.stop_filelog()
    logger.critical('System halted.')


import torch
from lstm_autoencoder import CompositeModel
from data import GraspDataset
from torch.utils.data import DataLoader

def train():

    device = torch.device('cuda')

    model = CompositeModel(
        input_size=5,
        hidden_size=256,
        sequence_length=375,
        num_layers=1,
        batch_first=True,
        loss_path='./loss/loss_032019.csv'
    ).to(device)

    train_set = GraspDataset('train')
    valid_set = GraspDataset('valid')

    data_loader_train = DataLoader(
        dataset=train_set,
        batch_size=128,
        shuffle=False,
        num_workers=4,
        drop_last=True
    )

    data_loader_valid = DataLoader(
        dataset=valid_set,
        batch_size=250,
        shuffle=False,
        num_workers=2,
        drop_last=False
    )

    model.train_model(
        num_epochs=1500,
        data_loader_train=data_loader_train,
        data_loader_valid=data_loader_valid,
        checkpoint_path='./checkpoints/checkpoint_032019.pt',
        lr=1e-3,
        weight_decay=0.000001,
        sparsity_weight=0.01,
        device=device
    )

if __name__ == '__main__':
    train()


from selenium import webdriver
import time
from helpers import wait_el, find_el, place_sel, campo_sel, getDriver, wait_landing_xpath
from person_fiverr import Person
import random

# Indicar nombre de la casa de apuestas
HOUSE_NAME = 'Megapuesta'

def register(executable_path, url, person, xpath_url, xpath_end, settings, tipo_user, login_email, browser):

    print(HOUSE_NAME)

    driver = getDriver(browser, executable_path)
    driver.delete_all_cookies()
    driver.get(url)
    driver.maximize_window()
    time.sleep(5)

    #------------------------------------------------------
    #Direct find elements #--
    #------------------------------------------------------

    wait_landing_xpath(xpath_url, 'click', driver, '')

    #wait_el('id', 'onetrust-accept-btn-handler', '	', driver) #>> cookies answer

    time.sleep(3)

    tab_list = driver.window_handles
    driver.switch_to.window(tab_list[-1])

    #wait_el('xpath', '/html/body/op-root/div/op-main-template/div/div[2]/op-register/div/tabset/ul/li[2]/a', 'click_js',
    #        driver) #>> manual answer

    #Nombre
    wait_el('name', 'FirstName', 'send_keys', driver, person.nombre)
    find_el('name', 'MiddleName', 'send_keys', driver, person.segundo_nombre)
    find_el('name', 'LastName', 'send_keys', driver, person.apellido1)
    find_el('name', 'SecondLastName', 'send_keys', driver, person.apellido2)

    #Datos CC
    find_el('name', 'CivilIdentificationCode', 'send_keys', driver, person.cedula)
    place_sel('name', 'DocumentTypeID', driver, person.tipo_documento)

    # Fechas (expedicion de la cedula y nacimiento)
    find_el('name', 'btoIssueOn', 'send_keys', driver, person.fecha_exp_dia+'/'+person.fecha_exp_mes+'/'+person.fecha_exp_ano)
    find_el('name', 'DateOfBirth', 'send_keys', driver, person.fecha_dia +'/'+person.fecha_mes+'/'+person.fecha_ano)

    #Ubicacion expedicion cedula
    place_sel('name', 'DepartmentOfBirthID', driver, person.lugar_exp_dept)
    place_sel('name', 'MunicipalityOfBirthID', driver, person.lugar_exp_mun)

    #siguiente
    find_el('xpath',
    '//button[@id="step1" and @class="btn btn-user-success next"]',
    'click_js',driver, '')

    #e-mail
    wait_el('name', 'Email', 'send_keys', driver, person.email)#
    find_el('name', 'ConfirmEmail', 'send_keys', driver, person.email)

    #password
    find_el('name', 'Password', 'send_keys', driver, person.password)
    find_el('name', 'ConfirmPassword', 'send_keys', driver, person.password)

    #Sexo
    if person.genero == 'Femenino':
        place_sel('name', 'Gender', driver, person.genero)#--

    elif person.genero == 'Masculino':
        place_sel('name', 'Gender', driver, person.genero)#--

    #Datos personal
    place_sel('name', 'CountryISO', driver, person.nacionalidad)
    place_sel('name', 'IssueDepartmentId', driver, person.lugar_nacimiento)
    place_sel('name', 'IssueMunicipalityId', driver, person.ciudad_nacimiento)

    #Siguiente
    find_el('xpath',
    '//button[@id="step2" and @class="btn btn-user-success next"]',
    'click_js',driver, '')

    #Datos adicionales
    wait_el('name', 'Address', 'send_keys', driver, person.calle)
    find_el('name', 'MobileNumber', 'send_keys', driver, person.telefono)

    place_sel('name', 'DepartmentID', driver, person.departamento)
    place_sel('name', 'MunicipalityID', driver, person.municipio)

    #Check
    driver.execute_script('document.getElementsByTagName("span")[44].click()')

    find_el('xpath',
    '//*[@id="step3"]/button[2]',
    'justwait',driver, '')

    print('end')
    time.sleep(15)

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

if __name__ == '__main__':

    # Ubicacion del chromedriver
    executable_path = 'driver/chromedriver.exe'

    # Url de acceso a la casa de apuestas -> Cambiarla para cada script
    url = 'https://www.megapuesta.co/registrarse/' #--

    # Datos de prueba de la persona (fake)
    person = Person('Femenino', 'Araceli', 'Taheri', 'Rochel', 'Cordoba',
                    '134604149', '2', '3', '1974', 'Cl 8 No 1-34',
                    '', '73947', 'Puerto Caicedo', 'Putumayo',
                    '313404725', 'arataro74','grsaidy17@gmail.com',
                    'fO824HEFf', 'colombia', '5', '7', '2013', 'Putumayo',
                    'Puerto Caicedo', '5000', '80000', '200000', 'lola',
                    'cedula de ciudadania','no','tuchín')#--

    # Dejar esto como está
    xpath_url = None
    xpath_end = None
    settings = None
    tipo_user = None
    login_email = None
    browser = 'Chrome'

    # Llamada funcion
    register(executable_path, url, person, xpath_url, xpath_end, settings, tipo_user, login_email, browser)


class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class Linked_List:
    def __init__(self):
        self.head = None

    def Insert_At_End(self, new_data):
        new_node = Node(new_data)
        if self.head is None:
            self.head = new_node
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = new_node

    def Detect_and_Remove_Loop(self):
        slow = fast = self.head
        while slow and fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                self.Remove_loop(slow)
                print("Loop Found")
                return 1
        return 0

    def Remove_loop(self, Loop_node):
        ptr1 = self.head
        while 1:
            ptr2 = Loop_node
            while ptr2.next != Loop_node and ptr2.next != ptr1:
                ptr2 = ptr2.next
            if ptr2.next == ptr1:
                break
            ptr1 = ptr1.next
        ptr2.next = None

    def Display(self):
        temp = self.head
        while temp:
            print(temp.data, "->", end=" ")
            temp = temp.next
        print("None")

if __name__ == "__main__":
    L_list = Linked_List()
    L_list.Insert_At_End(8)
    L_list.Insert_At_End(5)
    L_list.Insert_At_End(10)
    L_list.Insert_At_End(7)
    L_list.Insert_At_End(6)
    L_list.Insert_At_End(11)
    L_list.Insert_At_End(9)
    print("Linked List with Loop: ")
    L_list.Display()
    print("Linked List without Loop: ")
    L_list.head.next.next.next.next.next.next.next = L_list.head.next.next
    L_list.Detect_and_Remove_Loop()
    L_list.Display()


import sys
from unittest import TestCase
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO  # doesn't accept 'str' in Py2

from .. import Options
from ..CmdLine import parse_command_line

class CmdLineParserTest(TestCase):
    def setUp(self):
        backup = {}
        for name, value in vars(Options).items():
            backup[name] = value
        self._options_backup = backup

    def tearDown(self):
        no_value = object()
        for name, orig_value in self._options_backup.items():
            if getattr(Options, name, no_value) != orig_value:
                setattr(Options, name, orig_value)

    def test_short_options(self):
        options, sources = parse_command_line([
            '-V', '-l', '-+', '-t', '-v', '-v', '-v', '-p', '-D', '-a', '-3',
        ])
        self.assertFalse(sources)
        self.assertTrue(options.show_version)
        self.assertTrue(options.use_listing_file)
        self.assertTrue(options.cplus)
        self.assertTrue(options.timestamps)
        self.assertTrue(options.verbose >= 3)
        self.assertTrue(Options.embed_pos_in_docstring)
        self.assertFalse(Options.docstrings)
        self.assertTrue(Options.annotate)
        self.assertEqual(options.language_level, 3)

        options, sources = parse_command_line([
            '-f', '-2', 'source.pyx',
        ])
        self.assertTrue(sources)
        self.assertTrue(len(sources) == 1)
        self.assertFalse(options.timestamps)
        self.assertEqual(options.language_level, 2)

    def test_long_options(self):
        options, sources = parse_command_line([
            '--version', '--create-listing', '--cplus', '--embed', '--timestamps',
            '--verbose', '--verbose', '--verbose',
            '--embed-positions', '--no-docstrings', '--annotate', '--lenient',
        ])
        self.assertFalse(sources)
        self.assertTrue(options.show_version)
        self.assertTrue(options.use_listing_file)
        self.assertTrue(options.cplus)
        self.assertEqual(Options.embed, 'main')
        self.assertTrue(options.timestamps)
        self.assertTrue(options.verbose >= 3)
        self.assertTrue(Options.embed_pos_in_docstring)
        self.assertFalse(Options.docstrings)
        self.assertTrue(Options.annotate)
        self.assertFalse(Options.error_on_unknown_names)
        self.assertFalse(Options.error_on_uninitialized)

        options, sources = parse_command_line([
            '--force', 'source.pyx',
        ])
        self.assertTrue(sources)
        self.assertTrue(len(sources) == 1)
        self.assertFalse(options.timestamps)

    def test_options_with_values(self):
        options, sources = parse_command_line([
            '--embed=huhu',
            '-I/test/include/dir1', '--include-dir=/test/include/dir2',
            '--include-dir', '/test/include/dir3',
            '--working=/work/dir',
            'source.pyx',
            '--output-file=/output/dir',
            '--pre-import=/pre/import',
            '--cleanup=3',
            '--annotate-coverage=cov.xml',
            '--gdb-outdir=/gdb/outdir',
            '--directive=wraparound=false',
        ])
        self.assertEqual(sources, ['source.pyx'])
        self.assertEqual(Options.embed, 'huhu')
        self.assertEqual(options.include_path, ['/test/include/dir1', '/test/include/dir2', '/test/include/dir3'])
        self.assertEqual(options.working_path, '/work/dir')
        self.assertEqual(options.output_file, '/output/dir')
        self.assertEqual(Options.pre_import, '/pre/import')
        self.assertEqual(Options.generate_cleanup_code, 3)
        self.assertTrue(Options.annotate)
        self.assertEqual(Options.annotate_coverage_xml, 'cov.xml')
        self.assertTrue(options.gdb_debug)
        self.assertEqual(options.output_dir, '/gdb/outdir')

    def test_errors(self):
        def error(*args):
            old_stderr = sys.stderr
            stderr = sys.stderr = StringIO()
            try:
                self.assertRaises(SystemExit, parse_command_line, list(args))
            finally:
                sys.stderr = old_stderr
            self.assertTrue(stderr.getvalue())

        error('-1')
        error('-I')
        error('--version=-a')
        error('--version=--annotate=true')
        error('--working')
        error('--verbose=1')
        error('--verbose=1')
        error('--cleanup')


# import Dependendencies
import cv2
import numpy as np
import os

from matplotlib import pyplot as ptl
import time
import mediapipe as mp
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from tensorflow.keras.callbacks import TensorBoard
#from DataCollections import DATA_PATH
from sklearn.model_selection import train_test_split
from tensorflow.keras.utils import to_categorical
#from LoadData import load_data
# Key points using MP Holistics
from tensorflow.keras.models import Sequential
# Holistic model
mp_holistic = mp.solutions.holistic
# Drawing Utilities
mp_drawing = mp.solutions.drawing_utils
# path for exported data, numpy arrays
DATA_PATH = os.path.join('E:\\9th sem\\MS_Thesis\\Awiros\\Project\\data\\MP_DATA')

def mediapipe_detection(image, model):
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # color conversion
    image.flags.writeable = False  # image is no longer writable
    results = model.process(image)  # Make prediction
    image.flags.writeable = True  # image is no longer writable
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)  # color conversion
    return image, results

def draw_landmark(image, results):
    mp_drawing.draw_landmarks(image, results.face_landmarks, mp_holistic.FACE_CONNECTIONS,
                              mp_drawing.DrawingSpec(color=(80, 110, 10), thickness=1, circle_radius=1),
                              mp_drawing.DrawingSpec(color=(80, 256, 121), thickness=1, circle_radius=1))
    mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_holistic.POSE_CONNECTIONS,
                              mp_drawing.DrawingSpec(color=(1, 45, 10), thickness=2, circle_radius=4),
                              mp_drawing.DrawingSpec(color=(70, 26, 21), thickness=2, circle_radius=2)
                              )
    mp_drawing.draw_landmarks(image, results.left_hand_landmarks, mp_holistic.HAND_CONNECTIONS,
                              mp_drawing.DrawingSpec(color=(65, 150, 120), thickness=2, circle_radius=4),
                              mp_drawing.DrawingSpec(color=(82, 96, 11), thickness=2, circle_radius=2)
                              )
    mp_drawing.draw_landmarks(image, results.right_hand_landmarks, mp_holistic.HAND_CONNECTIONS,
                              mp_drawing.DrawingSpec(color=(170, 54, 110), thickness=2, circle_radius=4),
                              mp_drawing.DrawingSpec(color=(40, 56, 51), thickness=2, circle_radius=2)
                              )

def extract_keypoints(results):
    pose = np.array([[res.x, res.y, res.z, res.visibility] for res in
                     results.pose_landmarks.landmark]).flatten() if results.pose_landmarks else np.zeros(132)
    face = np.array([[res.x, res.y, res.z] for res in
                     results.face_landmarks.landmark]).flatten() if results.face_landmarks else np.zeros(468 * 3)
    lh = np.array([[res.x, res.y, res.z] for res in
                   results.left_hand_landmarks.landmark]).flatten() if results.left_hand_landmarks else np.zeros(21 * 3)
    rh = np.array([[res.x, res.y, res.z] for res in
                   results.right_hand_landmarks.landmark]).flatten() if results.right_hand_landmarks else np.zeros(
        21 * 3)
    return np.concatenate([pose, face, lh, rh])

#preprocess Data and create Label and features
actions = np.array(['hello', 'thanks', 'iloveyou'])

no_sequences = 30
sequence_length = 30

label_map = {label: num for num, label in enumerate(actions)}

def load_data():
    sequences, labels = [], []
    for action in actions:
        for sequence in range(no_sequences):
            window = []
            for frame_num in range(sequence_length):
                res = np.load(os.path.join(DATA_PATH, action, str(sequence), "{}.npy".format(frame_num)))
                window.append(res)
            sequences.append(window)
            labels.append(label_map[action])
    return np.array(sequences), labels
X, Y = load_data()

y = to_categorical(Y).astype(int)

sequence =[]
setetence = []
threshold = 0.4
model = Sequential()
model = Sequential()
model.add(LSTM(64, return_sequences=True, activation='relu', input_shape=(30,1662)))
model.add(LSTM(128, return_sequences=True, activation='relu'))
model.add(LSTM(64, return_sequences=False, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(actions.shape[0], activation='softmax'))

model.load_weights('E:\\9th sem\\MS_Thesis\\Awiros\\Project\\models\\action.h5')

cap = cv2.VideoCapture(0)
i=0

colors = [(245, 117, 16), (117, 245, 16), (16, 117, 245)]

def prob_viz(res, actions, input_frame, colors):
    output_frame = input_frame.copy()
    for num, prob in enumerate(res):
        cv2.rectangle(output_frame, (0, 60 + num * 40), (int(prob * 100), 90 + num * 40), colors[num], -1)
        cv2.putText(output_frame, actions[num], (0, 85 + num * 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2,
                    cv2.LINE_AA)

    return output_frame

# 1. New detection variables
sequence = []
sentence = []
predictions = []
threshold = 0.8

cap = cv2.VideoCapture(0)
# Set mediapipe model
with mp_holistic.Holistic(min_detection_confidence=0.5, min_tracking_confidence=0.5) as holistic:
    while cap.isOpened():

        # Read feed
        ret, frame = cap.read()

        # Make detections
        image, results = mediapipe_detection(frame, holistic)
        print(results)

        # Draw landmarks
        draw_landmark(image, results)

        # 2. Prediction logic
        keypoints = extract_keypoints(results)
        sequence.append(keypoints)
        sequence = sequence[-30:]

        if len(sequence) == 30:
            res = model.predict(np.expand_dims(sequence, axis=0))[0]
            print(actions[np.argmax(res)])
            predictions.append(np.argmax(res))

            # 3. Viz logic
            if np.unique(predictions[-10:])[0] == np.argmax(res):
                if res[np.argmax(res)] > threshold:

                    if len(sentence) > 0:
                        if actions[np.argmax(res)] != sentence[-1]:
                            sentence.append(actions[np.argmax(res)])
                    else:
                        sentence.append(actions[np.argmax(res)])

            if len(sentence) > 5:
                sentence = sentence[-5:]

            # Viz probabilities
            image = prob_viz(res, actions, image, colors)

        cv2.rectangle(image, (0, 0), (640, 40), (245, 117, 16), -1)
        cv2.putText(image, ' '.join(sentence), (3, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

        # Show to screen
        cv2.imshow('OpenCV Feed', image)

        # Break gracefully
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
# print(x)


# -*- coding: utf-8 -*-

from inference_engine import InferenceEngine
import sys
import traceback

sys.stdin.reconfigure(encoding='utf-8')
sys.stdout.reconfigure(encoding='utf-8')
print("stdin", sys.stdin.encoding)
print("stdout", sys.stdout.encoding)

engine = InferenceEngine()
print(engine)

running = True

while running:
    try:
        print(engine.fit(input()))
    except Exception as ex:
        running = False
        print(engine.answer)
        print("An error has occured! Here is the error details:")
        try:
            traceback.print_tb(ex.__traceback__, file=sys.stdout)
            print(ex)
        except Exception as another_ex:
            print("Another error has occured::", another_ex)
    finally:
        pass


from django.shortcuts import render, redirect, HttpResponseRedirect
from django.contrib import auth
from django.contrib.auth.forms import AuthenticationForm
from django.core.urlresolvers import reverse
from information.views import teacher_subject_list, speciality_list

# Create your views here.

def login(request):
	form = AuthenticationForm(request, request.POST or None)
	if request.POST:
		if form.is_valid():
			auth.login(request, form.get_user())
			return HttpResponseRedirect(reverse("teacher_subject_list"))
		else:
			return render(request, 'login.html', {'form': form})
	else:
		return render(request, 'login.html', {'form': form})

def logout(request):
	auth.logout(request)
	return HttpResponseRedirect(reverse('speciality_list'))


#
# @lc app=leetcode id=34 lang=python
#
# [34] Find First and Last Position of Element in Sorted Array
#

# @lc code=start
class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        if(len(nums)==0):
            return [-1,-1]

        left = 0
        right = len(nums)-1
        find = False

        while(not find):
            middle = int((left+right)/2)
            if(nums[middle]==target):
                find = True
                break
            if(left==middle or middle==right):
                if(nums[right]==target):
                    middle = right
                    find = True
                break
            if(nums[middle]<target):
                left = middle
            else:
                right = middle

        if(not find):
            return [-1,-1]

        if(middle>=1):
            front = middle-1
            while(nums[front]==target):
                front -=1
                if(front==-1):
                    break
        else:
            front = middle-1

        if(middle<=len(nums)-2):
            back = middle+1
            while(nums[back]==target):
                back +=1
                if(back==len(nums)):
                    break
        else:
            back = middle+1

        return [front+1,back-1]

# @lc code=end


"""This module initializes the app"""

import sys
import logging
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication

from controllers.main_controller import MainWindowController
from views.main_view import MainWindowView
from model.main_model import Model

class App(QApplication):
    """
    A class used to represent applicationa

    Attributes
    ----------
    sys_argv: command lines argument

    Methods
    -------
    close_event(self)
    """

    def __init__(self, sys_argv):
        super().__init__(sys_argv)

        test_mode = False
        if sys_argv[1] == "--test_config":
            test_mode = True
        self.app = QApplication(sys_argv)
        self.model = Model()
        self.controller = MainWindowController(self.model)
        self.main_view = MainWindowView(self.controller, test_mode)

        self.controller.on_start_up()

        self.main_view.show()

        if sys_argv[1] == "--test_config":
            print(f"Got our argument from command line: {sys_argv[1]}")

        self.app.aboutToQuit.connect(self.close_event)

    def close_event(self):
        """Call the function clean from model.py"""
        self.model.clean()

if __name__ == "__main__":
    logging.basicConfig(filename='todolist.log', encoding='utf-8', level=logging.DEBUG)
    app = App(sys.argv)
    app.setWindowIcon(QtGui.QIcon("app_icon.png"))

    SSH_FILE = "/Users/katestepanova/repos/to_do_list_app/style.qss"
    with open(SSH_FILE, "r", encoding='utf-8') as fh:
        _style = fh.read()
        print("Style is loaded")
        app.setStyleSheet(_style)

    sys.exit(app.exec())


from django.views import View
from django.contrib import messages
from django.shortcuts import redirect, render
from littlecms.models import Article, MenuOption
from django.utils.translation import gettext_lazy as _

# Create your views here.
class BaseCmsView(View):

    def get(self, request, menu_option_slug=None):

        if not menu_option_slug:
            menu_option = MenuOption.objects.filter(order=0)
        else:
            menu_option = MenuOption.objects.filter(slug=menu_option_slug)
        if menu_option:
            menu_option = menu_option.first()
            template = 'littlecms/base.html'
            if menu_option.page:
                template = menu_option.page.template if menu_option.page.template else template
            context = {'menu_option': menu_option}
            return render(request, template, context)
        else:
            messages.error(request, _('No se encontró la opción solicitada.'+request.path))
            return redirect('/')

class ArticleDetailView(View):

    def get(self, request, menu_option_slug, article_slug):

        menu_option = MenuOption.objects.filter(slug=menu_option_slug)
        article = Article.objects.filter(slug=article_slug)
        if menu_option and article:
            menu_option = menu_option.first()
            article = article.first()
            context = {'menu_option': menu_option, 'article': article}
            return render(request, 'littlecms/article_detail.html', context)
        else:
            messages.error(request, _('No se encontró la opción solicitada'))
            return render(request, 'littlecms/article_detail.html')