#
# This file is part of the Robotic Observatory Control Kit (rockit)
#
# rockit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# rockit 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with rockit.  If not, see <http://www.gnu.org/licenses/>.

"""Telescope action to observe a sidereally tracked field with autoguiding"""

# pylint: disable=too-many-return-statements
# pylint: disable=too-many-branches

import re
import threading
import time
from astropy import wcs
from astropy.coordinates import EarthLocation, SkyCoord
from astropy.time import Time
import astropy.units as u
import numpy as np
from scipy import conjugate, polyfit
from scipy.fftpack import fft, ifft
from rockit.common import log, validation
from rockit.camera.andor2 import CameraStatus
from rockit.operations import TelescopeAction, TelescopeActionStatus
from .camera_helpers import cameras, cam_status, cam_take_images, cam_stop
from .mount_helpers import mount_slew_radec, mount_offset_radec, mount_stop
from .pipeline_helpers import configure_pipeline
from .schema_helpers import camera_science_schema, pipeline_science_schema

# Amount of time to allow for readout + object detection + wcs solution
# Consider the frame lost if this is exceeded
MAX_PROCESSING_TIME = 25 * u.s

# Amount of time to wait before retrying if an image acquisition generates an error
CAM_ERROR_RETRY_DELAY = 10 * u.s

# Expected time to converge on target field
SETUP_DELAY = 15 * u.s

# Exposure time to use when taking a WCS field image
WCS_EXPOSURE_TIME = 5 * u.s

# Amount of time to wait between camera status checks while observing
CAM_CHECK_STATUS_DELAY = 10 * u.s

class Progress:
    Waiting, Acquiring, Observing = range(3)

class ObserveTimeSeries(TelescopeAction):
    """Telescope action to observe a sidereally tracked field with autoguiding"""
    def __init__(self, log_name, config):
        super().__init__('Observe Time Series', log_name, config)
        self._wait_condition = threading.Condition()

        self._start_date = Time(config['start'])
        self._end_date = Time(config['end'])
        self._guide_camera = config['guide_camera']
        self._progress = Progress.Waiting

        self._wcs_status = WCSStatus.Inactive
        self._wcs = None
        self._wcs_field_center = None

        self._observation_status = ObservationStatus.PositionLost
        self._is_guiding = False
        self._guide_profiles = None

        self._cameras = {}
        for camera_id in cameras:
            self._cameras[camera_id] = CameraWrapper(camera_id, self.config.get(camera_id, None), self.log_name)

    def task_labels(self):
        """Returns list of tasks to be displayed in the schedule table"""
        tasks = []

        if self._progress <= Progress.Waiting:
            if self._start_date:
                tasks.append(f'Wait until {self._start_date.strftime("%H:%M:%S")}')
        elif not self.dome_is_open:
            tasks.append('Wait for dome')

        target_name = self.config["pipeline"]["object"]
        if self._progress <= Progress.Acquiring:
            tasks.append(f'Acquire target field for {target_name}')
            tasks.append(f'Observe until {self._end_date.strftime("%H:%M:%S")}')

        elif self._progress <= Progress.Observing:
            tasks.append(f'Observe target {target_name} until {self._end_date.strftime("%H:%M:%S")}')

        return tasks

    def __acquire_field(self):
        self._progress = Progress.Acquiring

        # Point to the requested location
        acquire_start = Time.now()
        print('ObserveTimeSeries: slewing to target field')
        if not mount_slew_radec(self.log_name, self.config['ra'], self.config['dec'], True):
            return ObservationStatus.Error

        # Take a frame to solve field center
        pipeline_config = {
            'wcs': True,
            'type': 'JUNK',
            'object': 'WCS',
        }

        if not configure_pipeline(self.log_name, pipeline_config, quiet=True):
            return ObservationStatus.Error

        cam_config = {}
        cam_config.update(self.config.get(self._guide_camera, {}))
        cam_config.update({
            'exposure': WCS_EXPOSURE_TIME.to(u.second).value,
            'shutter': True
        })

        # Converge on requested position
        attempt = 1
        target = SkyCoord(self.config['ra'], self.config['dec'], unit=u.degree, frame='icrs')
        while not self.aborted and self.dome_is_open:
            # Wait for telescope position to settle before taking first image
            time.sleep(5)

            self._wcs = None
            self._wcs_status = WCSStatus.WaitingForWCS

            print('ObserveTimeSeries: taking test image')
            while not cam_take_images(self.log_name, self._guide_camera, 1, cam_config, quiet=True):
                # Try stopping the camera, waiting a bit, then try again
                cam_stop(self.log_name, self._guide_camera)
                self.wait_until_time_or_aborted(Time.now() + CAM_ERROR_RETRY_DELAY, self._wait_condition)
                if self.aborted or not self.dome_is_open:
                    break

                attempt += 1
                if attempt == 6:
                    return ObservationStatus.Error

            if self.aborted or not self.dome_is_open:
                break

            # Wait for new frame
            expected_complete = Time.now() + WCS_EXPOSURE_TIME + MAX_PROCESSING_TIME

            while True:
                with self._wait_condition:
                    remaining = (expected_complete - Time.now()).to(u.second).value
                    if remaining < 0 or self._wcs_status != WCSStatus.WaitingForWCS:
                        break

                    self._wait_condition.wait(max(remaining, 1))

            if self.aborted or not self.dome_is_open:
                break

            failed = self._wcs_status == WCSStatus.WCSFailed
            timeout = self._wcs_status == WCSStatus.WaitingForWCS
            self._wcs_status = WCSStatus.Inactive

            if failed or timeout:
                if failed:
                    print('ObserveTimeSeries: WCS failed for attempt', attempt)
                else:
                    print('ObserveTimeSeries: WCS timed out for attempt', attempt)

                attempt += 1
                if attempt == 6:
                    return ObservationStatus.Error

                continue

            # Calculate frame center and offset from expected pointing
            actual = SkyCoord(self._wcs_field_center.ra, self._wcs_field_center.dec, frame='icrs')
            offset_ra, offset_dec = actual.spherical_offsets_to(target)

            print(f'ObserveTimeSeries: offset is {offset_ra.to_value(u.arcsecond):.1f}, ' +
                  f'{offset_dec.to_value(u.arcsecond):.1f}')

            # Close enough!
            if offset_ra < 5 * u.arcsecond and offset_dec < 5 * u.arcsecond:
                dt = (Time.now() - acquire_start).to(u.s).value
                print(f'ObserveTimeSeries: Acquired field in {dt:.1f} seconds')
                return ObservationStatus.OnTarget

            # Offset telescope
            if not mount_offset_radec(self.log_name, offset_ra.to_value(u.deg), offset_dec.to_value(u.deg)):
                return ObservationStatus.Error

        if not self.dome_is_open:
            return ObservationStatus.DomeClosed

        if self.aborted:
            return ObservationStatus.Complete

        return ObservationStatus.Error

    def __wait_for_dome(self):
        while True:
            with self._wait_condition:
                if Time.now() > self._end_date or self.aborted:
                    return ObservationStatus.Complete

                if self.dome_is_open:
                    return ObservationStatus.PositionLost

                self._wait_condition.wait(10)

    def __observe_field(self):
        # Start science observations
        pipeline_config = self.config['pipeline'].copy()
        pipeline_config['guide'] = self._guide_camera.upper()
        pipeline_config['type'] = 'SCIENCE'

        if not configure_pipeline(self.log_name, pipeline_config):
            return ObservationStatus.Error

        # Mark cameras idle so they will be started by camera.update() below
        print('ObserveTimeSeries: starting science observations')
        for camera in self._cameras.values():
            if camera.status == CameraWrapperStatus.Stopped:
                camera.status = CameraWrapperStatus.Idle

        self._is_guiding = True

        # Monitor observation status
        self._progress = Progress.Observing
        return_status = ObservationStatus.Complete
        while True:
            if self.aborted or Time.now() > self._end_date:
                break

            if not self.dome_is_open:
                log.error(self.log_name, 'Aborting because dome is not open')
                return_status = ObservationStatus.DomeClosed
                break

            if not self._is_guiding:
                log.warning(self.log_name, 'Lost autoguiding lock')
                return_status = ObservationStatus.PositionLost
                break

            for camera in self._cameras.values():
                camera.update()
                if camera.status == CameraWrapperStatus.Error:
                    return_status = ObservationStatus.Error
                    break

            self.wait_until_time_or_aborted(Time.now() + CAM_CHECK_STATUS_DELAY, self._wait_condition)

        # Wait for all cameras to stop before returning to the main loop
        print('ObserveTimeSeries: stopping science observations')
        self._is_guiding = False
        for camera in self._cameras.values():
            camera.stop()

        while True:
            if all(c.status in [CameraWrapperStatus.Error, CameraWrapperStatus.Stopped]
                    for c in self._cameras.values()):
                break

            for camera in self._cameras.values():
                camera.update()

            with self._wait_condition:
                self._wait_condition.wait(CAM_CHECK_STATUS_DELAY.to_value(u.s))

        print('ObserveField: cameras have stopped')
        return return_status

    def run_thread(self):
        """Thread that runs the hardware actions"""
        # Configure pipeline immediately so the dashboard can show target name etc
        if not configure_pipeline(self.log_name, self.config['pipeline'], quiet=True):
            self.status = TelescopeActionStatus.Error
            return

        self.wait_until_time_or_aborted(self._start_date, self._wait_condition)
        if Time.now() > self._end_date:
            self.status = TelescopeActionStatus.Complete
            return

        # Outer loop handles transitions between states
        # Each method call blocks, returning only when it is ready to exit or switch to a different state
        while True:
            if self._observation_status == ObservationStatus.Error:
                print('ObserveTimeSeries: status is now Error')
                break

            if self._observation_status == ObservationStatus.Complete:
                print('ObserveTimeSeries: status is now Complete')
                break

            if self._observation_status == ObservationStatus.OnTarget:
                print('ObserveTimeSeries: status is now OnTarget')
                self._observation_status = self.__observe_field()

            if self._observation_status == ObservationStatus.PositionLost:
                print('ObserveTimeSeries: status is now PositionLost')
                self._observation_status = self.__acquire_field()

            if self._observation_status == ObservationStatus.DomeClosed:
                print('ObserveTimeSeries: status is now DomeClosed')
                self._observation_status = self.__wait_for_dome()

        mount_stop(self.log_name)

        if self._observation_status == ObservationStatus.Complete:
            self.status = TelescopeActionStatus.Complete
        else:
            self.status = TelescopeActionStatus.Error

    def abort(self):
        """Notification called when the telescope is stopped by the user"""
        super().abort()

        with self._wait_condition:
            self._wait_condition.notify_all()

    def dome_status_changed(self, dome_is_open):
        """Notification called when the dome is fully open or fully closed"""
        super().dome_status_changed(dome_is_open)

        with self._wait_condition:
            self._wait_condition.notify_all()

    def received_frame(self, headers):
        """Notification called when a frame has been processed by the data pipeline"""
        print('Got frame from', headers.get('CAMID', '').lower())
        camera = self._cameras.get(headers.get('CAMID', '').lower(), None)
        if camera is not None:
            camera.received_frame(headers)

        with self._wait_condition:
            if self._wcs_status == WCSStatus.WaitingForWCS:
                if 'CRVAL1' in headers and 'IMAG-RGN' in headers and 'SITELAT' in headers:
                    r = re.search(r'^\[(\d+):(\d+),(\d+):(\d+)\]$', headers['IMAG-RGN']).groups()
                    cx = (int(r[0]) - 1 + int(r[1])) / 2
                    cy = (int(r[2]) - 1 + int(r[3])) / 2
                    location = EarthLocation(
                        lat=headers['SITELAT'],
                        lon=headers['SITELONG'],
                        height=headers['SITEELEV'])
                    wcs_time = Time(headers['DATE-OBS'], location=location) + 0.5 * headers['EXPTIME'] * u.s
                    self._wcs = wcs.WCS(headers)
                    ra, dec = self._wcs.all_pix2world(cx, cy, 0)
                    self._wcs_field_center = SkyCoord(
                        ra=ra * u.deg,
                        dec=dec * u.deg,
                        frame='icrs',
                        obstime=wcs_time)
                    self._wcs_status = WCSStatus.WCSComplete
                else:
                    self._wcs_status = WCSStatus.WCSFailed
                    self._wcs_field_center = None

                self._wait_condition.notify_all()

    def received_guide_profile(self, headers, profile_x, profile_y):
        """Notification called when a guide profile has been calculated by the data pipeline"""
        camera = headers.get('CAMID', '').lower()
        if camera != self._guide_camera or not self._is_guiding:
            return

        if self._guide_profiles is None:
            print('ObserveTimeSeries: set reference guide profiles')
            self._guide_profiles = profile_x, profile_y
            return

        # Measure image offset
        dx = cross_correlate(profile_x, self._guide_profiles[0])
        dy = cross_correlate(profile_y, self._guide_profiles[1])

        # TODO: Use WCS matrix to convert pixel offsets to sky offsets
        print(f'ObserveTimeSeries: measured guide offsets {dx:.2f} {dy:.2f} px')

        # Stop science observations and reacquire using WCS if we are too far off target
        # TODO: Do this in arcseconds
        if abs(dx) > 100 or abs(dy) > 100:
            self._is_guiding = False
            return

        # TODO: Apply guide offset

    @classmethod
    def validate_config(cls, config_json):
        """Returns an iterator of schema violations for the given json configuration"""
        schema = {
            'type': 'object',
            'additionalProperties': False,
            'required': ['start', 'end', 'ra', 'dec', 'guide_camera', 'pipeline'],
            'properties': {
                'type': {'type': 'string'},
                'start': {
                    'type': 'string',
                    'format': 'date-time'
                },
                'end': {
                    'type': 'string',
                    'format': 'date-time'
                },
                'ra': {
                    'type': 'number',
                    'minimum': 0,
                    'maximum': 360
                },
                'dec': {
                    'type': 'number',
                    'minimum': -90,
                    'maximum': 90
                },
                'guide_camera': {
                    'type': 'string',
                    'enum': list(cameras.keys())
                },
                'pipeline': pipeline_science_schema()
            }
        }

        for camera_id in cameras:
            schema['properties'][camera_id] = camera_science_schema(camera_id)

        return validation.validation_errors(config_json, schema)

def cross_correlate(check, reference):
    corr = ifft(conjugate(fft(reference)) * fft(check))
    peak = np.argmax(corr)

    # Fit sub-pixel offset using a quadratic fit over the 3 pixels centered on the peak
    if peak == len(corr) - 1:
        x = [-1, 0, 1]
        y = [
            corr[-2].real,
            corr[-1].real,
            corr[0].real
        ]
        coeffs = polyfit(x, y, 2)
        return 1 + (coeffs[1] / (2 * coeffs[0]))

    if peak == 0:
        x = [1, 0, -1]
        y = [
            corr[-1].real,
            corr[0].real,
            corr[1].real,
        ]
        coeffs = polyfit(x, y, 2)
        return -coeffs[1] / (2 * coeffs[0])

    x = [peak - 1, peak, peak + 1]
    y = [
        corr[x[0]].real,
        corr[x[1]].real,
        corr[x[2]].real
    ]
    coeffs = polyfit(x, y, 2)
    if peak <= len(corr) / 2:
        return -(-coeffs[1] / (2 * coeffs[0]))
    return len(corr) + (coeffs[1] / (2 * coeffs[0]))

class WCSStatus:
    Inactive, WaitingForWCS, WCSFailed, WCSComplete = range(4)

class ObservationStatus:
    PositionLost, OnTarget, DomeClosed, Complete, Error = range(5)

class CameraWrapperStatus:
    Idle, Active, Error, Stopping, Stopped, Skipped = range(6)

class CameraWrapper:
    """Holds camera-specific flat state"""
    def __init__(self, camera_id, camera_config, log_name):
        self.camera_id = camera_id
        self.status = CameraWrapperStatus.Stopped if camera_config is not None else CameraWrapperStatus.Skipped
        self._log_name = log_name
        self._config = camera_config or {}
        self._start_attempts = 0
        self._last_frame_time = Time.now()

    def stop(self):
        if self.status == CameraWrapperStatus.Idle:
            self.status = CameraWrapperStatus.Stopped
        elif self.status == CameraWrapperStatus.Active:
            self.status = CameraWrapperStatus.Stopping
            cam_stop(self._log_name, self.camera_id)

    # pylint: disable=unused-argument
    def received_frame(self, headers):
        """Callback to process an acquired frame. headers is a dictionary of header keys"""
        self._last_frame_time = Time.now()
    # pylint: enable=unused-argument

    def update(self):
        """Monitor camera status"""
        if self.status in [CameraWrapperStatus.Error, CameraWrapperStatus.Stopped, CameraWrapperStatus.Skipped]:
            return

        # Start exposure sequence on first update
        if self.status == CameraWrapperStatus.Idle:
            if cam_take_images(self._log_name, self.camera_id, 0, self._config):
                self._start_attempts = 0
                self._last_frame_time = Time.now()
                self.status = CameraWrapperStatus.Active
                return

            # Something went wrong - see if we can recover
            self._start_attempts += 1
            log.error(self._log_name, 'Failed to start exposures for camera ' + self.camera_id +
                      f' (attempt {self._start_attempts} of 5)')

            if self._start_attempts >= 5:
                log.error(self._log_name, 'Too many start attempts: aborting')
                self.status = CameraWrapperStatus.Error
                return

            # Try stopping the camera and see if we can recover on the next update loop
            cam_stop(self._log_name, self.camera_id)
            return

        if self.status == CameraWrapperStatus.Stopping:
            if cam_status(self._log_name, self.camera_id).get('state', CameraStatus.Idle) == CameraStatus.Idle:
                self.status = CameraWrapperStatus.Stopped
                return

        # Assume that everything is ok if we are still receiving frames at a regular rate
        if Time.now() < self._last_frame_time + self._config['exposure'] * u.s + MAX_PROCESSING_TIME:
            return

        # Exposure has timed out: lets find out why
        status = cam_status(self._log_name, self.camera_id).get('state', None)

        # Lost communication with camera daemon, this is assumed to be unrecoverable
        if not status:
            log.error(self._log_name, 'Lost communication with camera ' + self.camera_id)
            self.status = CameraWrapperStatus.Error
            return

        # Camera may be idle if the pipeline blocked for too long
        if status is CameraStatus.Idle:
            log.warning(self._log_name, 'Recovering idle camera ' + self.camera_id)
            self.status = CameraWrapperStatus.Idle
            self.update()
            return

        # Try stopping the camera and see if we can recover on the next update loop
        log.warning(self._log_name, f'Camera has timed out in state {CameraStatus.label(status)}, stopping camera')
        cam_stop(self._log_name, self.camera_id)


"""This module contain helper utilities to prepare data for NER."""
from typing import List, Union

import pandas as pd

from ner_ehr.data.variables import (
    AnnotationTuple,
    LongAnnotationTuple,
    TokenTuple,
)

def sort_namedtuples(
    namedtuples: Union[
        List[TokenTuple], List[AnnotationTuple], List[LongAnnotationTuple]
    ],
    by: Union[str, List[str]] = ["doc_id", "start_idx"],
    ascending: bool = True,
):
    """Sort list of TokenTuples/AnnotationTuples/LongAnnotationTuples
    by given condition in given order.

    Args:
        namedtuples: a list of
            tokentuples, ex: [
                                Token(
                                    doc_id="100035",
                                    token='recurrent',
                                    start_idx=10179,
                                    end_idx=10188,),
                                ...
                            ]
            or
            annotatedtuples, ex: [
                                Annotation(
                                    doc_id="100035",
                                    token='recurrent',
                                    start_idx=10179,
                                    end_idx=10188,
                                    entity='B-Reason',),
                                ...
                            ]
            or
            long_annotationtuples, ex: [
                                LongAnnotation(
                                    doc_id="100035",
                                    token='recurrent',
                                    start_idx=10179,
                                    end_idx=10188,
                                    entity='B-Reason',
                                    token_idx=2,
                                    entity_label=2,),
                                ...
                            ]

        by: string or list of string,
            fields within each namedtuple

        ascending: boolean flag, default=False,
            if True, namedtuples are sorted in ascending order on
            given condition other sorted in descending order

        Returns:
            A list of sorted namedtuples
    """

    def check_field(field: str):
        if field not in namedtuples[0]._fields:
            raise AttributeError(
                f"Field `{field}` missing in `{type(namedtuples[0]).__name__}`"
            )

    if isinstance(by, str):
        by = [by]
    for field in by:
        check_field(field=field)

    df = pd.DataFrame(namedtuples).sort_values(by=by, ascending=ascending)
    return list(df.itertuples(name=type(namedtuples[0]).__name__, index=False))

def df_to_namedtuples(
    name: str, df: pd.core.frame.DataFrame
) -> Union[List[TokenTuple], List[AnnotationTuple], List[LongAnnotationTuple]]:
    """Convert given dataframe into list of namedtuples.

    Args:
        name: string name of every namedtuple formed from rows of dataframe.

    Returns:
        A list of namedtuples
    """
    return list(df.itertuples(name=name, index=False))

def generate_token_seqs(
    annotatedtuples: Union[List[AnnotationTuple], List[LongAnnotationTuple]],
    seq_length: int = 256,
) -> Union[List[List[AnnotationTuple]], List[List[LongAnnotationTuple]]]:
    """Generate sequences of AnnotatedTuples of with maximum length
        as given `seq_length`.

    Note: this function ensures that sequences of tokens generated preserve
        continuation of `IOB` tagging within every sequence,
        i.e. `B-` and `I-` tags of an entity in continuation
        are kept in same sequence.
        Doing so, a sequence can be shorter than given `seq_length`,
        i.e. not all sequences are of given `seq_length`.

        Also, this function is not implemented to generated sequences
            of `seq_length=1`

    Args:
        namedtuples: a list of
            annotatedtuples, ex: [
                                    Annotation(
                                        doc_id="100035",
                                        token='recurrent',
                                        start_idx=10179,
                                        end_idx=10188,
                                        entity='B-Reason',),
                                    ...
                                    ]
            or
            long_annotationtuples, ex: [
                                    LongAnnotation(
                                        doc_id="100035",
                                        token='recurrent',
                                        start_idx=10179,
                                        end_idx=10188,
                                        entity='B-Reason',
                                        token_idx=2,
                                        entity_label=2,),
                                    ...
                                    ]

        seq_length: maximum length of sequences, default=256

    Returns:
        A list of list of AnnotatedTuples
    """

    if seq_length == 1:
        raise ValueError("Not implemented for seq_length=1")

    seqs: Union[
        List[List[AnnotationTuple]], List[List[LongAnnotationTuple]]
    ] = []
    total_tokens: int = len(annotatedtuples)

    def find_end(start: int):
        """Find end index for a sequence with respect to start idx."""
        end = start + seq_length
        if end > total_tokens:
            end = total_tokens
        return end

    start: int = 0
    end: int = find_end(start)

    while end > start and end <= total_tokens:
        if (
            not annotatedtuples[start].entity.startswith("I-")
            and annotatedtuples[end - 1].entity.startswith("I-")
            and (
                end == total_tokens
                or not annotatedtuples[end].entity.startswith("I-")
            )
        ):
            # perfect sequence found
            # TODO: Add examples of perfect sequences
            pass
        else:
            # finding best possible sequence
            is_inside_tag_found: bool = False
            # check if inside tag and not retracking to previous sub-seqs
            while end > start and annotatedtuples[end - 1].entity.startswith(
                "I-"
            ):
                end -= 1
                is_inside_tag_found = True

            if is_inside_tag_found:
                end -= 1

        if end <= start:
            # skipping current sequence
            #   try from next start idx
            start += 1
            end = find_end(start)
            continue

        seqs.append(annotatedtuples[start:end])
        start = end
        end = find_end(start)
    return seqs


from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from .resources import project

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def app_is_running():
    return {"message": "The app is running"}

app.include_router(project.router)


"""
Dispatch routines.
"""

from collections import OrderedDict  # NOQA
from andes.utils.func import list_flatten  # NOQA
from ams.routines.routine import RoutineData, RoutineModel  # NOQA

all_routines = OrderedDict([
    ('dcpf', ['DCPF']),
    ('pflow', ['PFlow']),
    ('cpf', ['CPF']),
    ('acopf', ['ACOPF']),
    ('dcopf', ['DCOPF']),
    ('ed', ['ED']),
    ('rted', ['RTED', 'RTED2']),
    ('uc', ['UC']),
    ('dopf', ['LDOPF', 'LDOPF2']),
])

class_names = list_flatten(list(all_routines.values()))
routine_cli = OrderedDict([(item.lower(), item) for item in class_names])


import json                                         # to print list/dict in textbox
import tkinter as tk                                # root GUI module
import tkinter.scrolledtext as scrolledtext         # module for scrollable text widget
import tkinter.ttk as ttk                           # themed GUI module
from tkinter.filedialog import askopenfile          # module to read file

import requests                                     # module to get all contents of a website
from bs4 import BeautifulSoup                       # module to get only text from a website
from PIL import Image, ImageTk                      # module to open and load a image
from ttkthemes import ThemedStyle                   # module to use in-built GUI themes

# class to get all frames together
class MyApp(tk.Tk):

    def __init__(self, *args, **kwargs, ):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        menu = tk.Menu(container)

        ex = tk.Menu(menu, tearoff=0)
        menu.add_cascade(menu=ex, label="Menu")
        ex.add_command(label="Exit",
                    command=self.destroy)

        # code to make theme choosable
        style = ThemedStyle(self)

        def theme(thm,inde):
            style.set_theme(thm.entrycget(inde,"label"))

        th = tk.Menu(menu,tearoff=0)
        menu.add_cascade(menu=th, label="Theme")

        th.add_command(label="aquativo",command=lambda:theme(th,0))
        th.add_command(label="black",command=lambda:theme(th,1))
        th.add_command(label="blue",command=lambda:theme(th,2))
        th.add_command(label="clearlooks",command=lambda:theme(th,3))
        th.add_command(label="radiance",command=lambda:theme(th,4))
        th.add_command(label="winxpblue",command=lambda:theme(th,5))
        th.add_command(label="keramik",command=lambda:theme(th,6))
        th.add_command(label="kroc",command=lambda:theme(th,7))
        th.add_command(label="plastik",command=lambda:theme(th,8))

        tk.Tk.config(self, menu=menu)

        for F in (Startpage, PageOne, PageTwo):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(Startpage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

# Home page
class Startpage(ttk.Frame):

    def __init__(self, parent, controller):
        ttk.Frame.__init__(self, parent)

        label = ttk.Label(self, text="Home",font=("Simplifica",22))         # page heading
        label.pack(pady=5, padx=5)

        ttk.Label(self,text="").pack()

        button1 = ttk.Button(self, text="Detect",
                        command=lambda: controller.show_frame(PageOne))     # got to detect page
        button1.pack()

        ttk.Label(self,text="").pack()

        button2 = ttk.Button(self, text="About",
                        command=lambda: controller.show_frame(PageTwo))     # got to about page
        button2.pack()

        ttk.Label(self,text="").pack()

        img=ImageTk.PhotoImage(Image.open("wall.jpg").resize((1200,700)))   # set the home page image
        img.image = img
        ttk.Label(self,image=img).pack()

#   *****   PAGES   *****
# Detect page
class PageOne(ttk.Frame):

    def __init__(self, parent, controller):
        ttk.Frame.__init__(self, parent)
        label = ttk.Label(self, text="Detect",font=("Simplifica",22))       # page heading
        label.pack(pady=5, padx=5)

        ttk.Label(self,text="\n").pack()

        ttk.Label(self,text="Enter a webpage",font=(18)).pack()
        text = tk.Entry(self,font=(26),width=70,bg="lightgray")             # textbox to enter a website
        text.pack()

        ttk.Label(self,text="").pack()

        # load the file containing fixed keywords
        j=[]
        f = open("keywords.txt", "r")
        for line in f:
            j.append(line.strip())
        f.close()
        d = dict.fromkeys(j,0)

        # code to scan the website given in textbox
        def scan():
            count=0
            url = text.get()
            text.delete(0,"end")
            result = requests.get(url.strip())
            soup = BeautifulSoup(result.content, 'lxml')
            for i in soup.get_text().split():
                if(i.lower()in j):
                    count+=1
                    if i.lower() in d:
                        d[i.lower()] +=1
            l3.config(state=tk.NORMAL)
            l3.delete('1.0',"end")
            di = dict(sorted(d.items(),reverse=True, key=lambda item: item[1]))
            lis = [(k,v) for k,v in di.items() if v >= 1]
            l3.insert(tk.END,url.strip()+" = "+str(count)+"\n\nKeywords matched:  \n"+json.dumps(lis))
            l3.config(state=tk.DISABLED)

        b2=ttk.Button(self,text="Scan",command= scan)
        b2.pack()

        ttk.Label(self,text="").pack()

        # code to open and scan the list of websites given in a text file
        def open_n_scan():
            files = askopenfile(mode ='r', filetypes =[("Text File", "*.txt")])
            l3.config(state=tk.NORMAL)
            l3.delete('1.0',"end")
            for url in files:
                count=0
                result = requests.get(url.strip())
                soup = BeautifulSoup(result.content, 'lxml')
                for i in soup.get_text().split():
                    if(i.lower()in j):
                        count+=1
                l3.insert(tk.END,url.strip()+" = "+str(count)+"\n")
            l3.config(state=tk.DISABLED)

        ttk.Label(self,text="Select your text file containing urls",font=(18)).pack()

        b1=ttk.Button(self,text="Open and Scan",command= open_n_scan)
        b1.pack()

        ttk.Label(self,text="").pack()

        l3=scrolledtext.ScrolledText(self,font=(18),height=10,width=70,bg="lightgray",state=tk.DISABLED)       # multiline textbox
        l3.pack()

        ttk.Label(self,text="").pack()

        button1 = ttk.Button(self, text="Back to Home",
                        command=lambda: controller.show_frame(Startpage))                           # go to home page
        button1.pack()

        ttk.Label(self,text="").pack()

        button2 = ttk.Button(self, text="About",
                        command=lambda: controller.show_frame(PageTwo))                             # got to about page
        button2.pack()

# About page
class PageTwo(ttk.Frame):

    def __init__(self, parent, controller):
        ttk.Frame.__init__(self, parent)
        label = ttk.Label(self, text="About",font=("Simplifica",22))                    # page heading
        label.pack(pady=5, padx=5)

        ttk.Label(self,text="").pack()

        button1 = ttk.Button(self, text="Back to Home",
                        command=lambda: controller.show_frame(Startpage))               # got to home page
        button1.pack()

        ttk.Label(self,text="").pack()

        button2 = ttk.Button(self, text="Detect",
                        command=lambda: controller.show_frame(PageOne))                 # got to detect page
        button2.pack()

        ttk.Label(self,text="").pack()

        tk.Message(self,relief="sunken",bd=4,font=(20),width=1100,text="Terrorism is, in the broadest sense, the use of intentional violence for political or religious purposes. It is used in this regard primarily to refer to violence during peacetime or in the context of war against non-combatants (mostly civilians and neutral military personnel). The terms terrorist and terrorism originated during the French Revolution of the late 18th century but gained mainstream popularity in the 1970s during the conflicts of Northern Ireland, the Basque Country and Palestine. The increased use of suicide attacks from the 1980s onwards was typified by the September 11 attacks in New York City and Washington, D.C. in 2001.").pack()
                                                                                # Info on terrorism
        ttk.Label(self,text="").pack()

        tk.Message(self,relief="sunken",bd=4,font=(20),width=1100,text="Cyberterrorism is the use of the Internet to conduct violent acts that result in, or threaten, loss of life or significant bodily harm, in order to achieve political or ideological gains through threat or intimidation. It is also sometimes considered an act of Internet terrorism where terrorist activities, including acts of deliberate, large-scale disruption of computer networks, especially of personal computers attached to the Internet by means of tools such as computer viruses, computer worms, phishing, and other malicious software and hardware methods and programming scripts. Cyberterrorism is a controversial term.").pack()
                                                                                # Info on cyberterrorism
        ttk.Label(self,text="").pack()

        tk.Message(self,relief="sunken",bd=4,font=(20),width=1100,text="We use web mining algorithms to mine textual information on web pages and detect their relevancy to terrorism. This system will check web pages whether a webpage is promoting terrorism. Data mining is a technique used to mine out patterns of useful data from large data sets and make the most use of obtained results. Web mining also consists of text mining methodologies that allow us to scan and extract useful content from unstructured data.").pack()
                                                                                # About
        ttk.Label(self,text="").pack()

        ttk.Label(self,text="© Virat Bamaniya and Milan Solanki",font=(20)).pack()                        # copyright

app = MyApp()

# set default app theme
style = ThemedStyle(app)
style.set_theme("black")

# set app icon
icon = ImageTk.PhotoImage(Image.open("icon.jpg"))
app.iconphoto(False,icon)

app.resizable(0,0)
app.title("Detect Terrorism")                                                           # app title
app.state('zoomed')                                                                     # maximized app by default
app.mainloop()


import cv2
import matplotlib.pyplot as plt
import numpy as np
#cap = cv2.VideoCapture(0)
imgpath = "Downloads\\Compressed\\misc\\misc\\4.1.08.tiff"
img = cv2.imread(imgpath)
#ret,img = cap.read(0)
#hist, bins = np.histogram(R.ravel(), 256, [0,255])
#red = cv2.calcHist([img], [0], None, [256],[0,255])
#green = cv2.calcHist([img],[1], None, [256],[0,255])
#blue = cv2.calcHist([img], [2], None, [256],[0,255])
R,G, B = cv2.split(img)
output_1 = cv2.equalizeHist(R)
output_2 = cv2.equalizeHist(G)
output_3 = cv2.equalizeHist(B)
output = cv2.merge((output_1, output_2, output_3))
clahe = cv2.createCLAHE()

output2_1 = clahe.apply(R)
output2_2 = clahe.apply(G)
output2_3 = clahe.apply(B)
output2 = cv2.merge((output2_1, output2_2, output2_3))

cv2.imshow('frame2', img)
cv2.imshow('frame', output)
cv2.imshow('frame1', output2)

cv2.waitKey(0)
#cap.release()
cv2.destroyAllWindows()


import wx

# PanelsSwitcher is a type of BoxSizer which allows
# switching between panels
class PanelsSwitcher(wx.BoxSizer):
    # The constructor a parent window
    # and a list of panels for switch between them
    def __init__(self, parent):
        # Initialize the base class
        wx.BoxSizer.__init__(self)
        # Attach this sizer to the parent window
        parent.SetSizer(self)
        # Save the parent windows
        self.parent = parent
        self.panels = {}

    def add_panel(self, panel, panel_name):
        # CATCH EVENTUAL panel double insertion
        self.panels[panel_name] = panel
        self.Add(panel, 1, wx.EXPAND)
        panel.Hide()

   # Show one panel and hide the rest
    def show(self, panel_name):
        # Check the required panel is in the list, throw error otherwise
        panel_name_list = list(self.panels.keys())
        if panel_name not in panel_name_list:
            wx.MessageBox("Still nothing to show!", 'Error', wx.OK | wx.ICON_ERROR)

            raise MissingPanel("Required panel not known by the switcher")

        # For each panel in the list of panels, hide it
        for panel in panel_name_list:
            self.panels[panel].Hide()

        # Then show the given panel
        self.panels[panel_name].Show()

        # Rearrange the window
        self.parent.Layout()

class MissingPanel(KeyError):
    pass


#!/usr/bin/env python3
#
# from checkhttp import *
# httpcheck = CheckHTTP('example.com')

from modules.logging import *
from urllib.parse import urlparse
import subprocess
import json
import os

def HTTPParse(DOMAIN):
	try:
		target = urlparse(DOMAIN)
		if target.scheme == 'http' and target.port == 80:
			target = target.scheme + '://' + target.hostname
		elif target.scheme == 'https' and target.port == 443:
			arget = target.scheme + '://' + target.hostname
		else:
			target = target.scheme + '://' + target.netloc
		return target
	except:
		return None

def CheckHTTP(DOMAIN):
	try:
		HTTPX_BIN = os.getenv('HTTPX_BIN')
		target = subprocess.Popen(["echo", "{DOMAIN}".format(DOMAIN=DOMAIN)], stdout=subprocess.PIPE)
		get_http_list = subprocess.run(['{}'.format(HTTPX_BIN), '-timeout', '5', '-retries', '3', '-status-code', '-tech-detect', '-json', '-silent'], stdin=target.stdout, capture_output=True, text=True)
		result = []
		for http_list in get_http_list.stdout.split('\n'):
			if 'url' in http_list:
				data = json.loads(http_list)
				try:
					tech = data['tech']
				except Exception:
					tech = None
					pass
				try:
					content_type = data['content_type']
				except:
					content_type = None
					pass
				data_parsed = {'url': HTTPParse(data['url']), 'status_code': data['status_code'], 'host': data['host'], 'port': data['port'], 'content_type': content_type, 'technologies': tech}
				result.append(data_parsed)
		if result == []:
			return False
		return result[0]
	except Exception:
		logger.error(traceback.format_exc())
		return False


import pygame
from utils import cycle_sprite, update, place_items

pygame.init()

#VALUES
MAX_HEIGHT = 500
MAX_WIDTH = 500
BACKGROUND_COLOR = (255, 100, 255)

SPRITE_WIDTH = 40
SPRITE_HEIGHT = 60

x = (MAX_WIDTH / 2) - (SPRITE_WIDTH / 2)
y = (MAX_HEIGHT / 2) - (SPRITE_HEIGHT / 2)

PLAYER = pygame.image.load("maria.png")
PLAYER_RECT = PLAYER.get_rect()

SPEED = 10

SCORE = 0

#make the window, set bg color
win = pygame.display.set_mode((MAX_WIDTH, MAX_HEIGHT))
win.fill(BACKGROUND_COLOR)

run = True

player_cycle = 0

#put the prizes and enemies on the screen

enemy_list = []
enemy_token_list = []

prize_list = []
prize_token_list = []

while run:
  pygame.time.delay(50)

  pygame.display.set_caption("SCORE: " + str(SCORE))

  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      run = False

  keys = pygame.key.get_pressed()

  if keys[pygame.K_LEFT] and (x-SPEED >= 0):
    x -= SPEED
    player_cycle = update(player_cycle)
  if keys[pygame.K_RIGHT] and (x+SPEED <= MAX_WIDTH-SPRITE_WIDTH):
    x += SPEED
    player_cycle = update(player_cycle)
  if keys[pygame.K_UP] and (y-SPEED >= 0):
    y -= SPEED
    player_cycle = update(player_cycle)
  if keys[pygame.K_DOWN] and (y+SPEED <= MAX_HEIGHT-SPRITE_HEIGHT):
    y += SPEED
    player_cycle = update(player_cycle)

  win.fill(BACKGROUND_COLOR)

  pygame.display.update()

pygame.quit()


from flask import Blueprint, render_template, session, abort
from flask_login import current_user
from monolith.database import (
    db,
    Restaurant,
    Positive,
)
from monolith.forms import ReservationForm
from monolith.services import (
    UserService,
    RestaurantServices,
)
from monolith.utils import DispatcherMessage
from monolith.app_constant import CALCULATE_RATING_RESTAURANTS

home = Blueprint("home", __name__)

@home.route("/")
def index():
    DispatcherMessage.send_message(CALCULATE_RATING_RESTAURANTS, [])
    restaurants = db.session.query(Restaurant).all()
    if current_user is None:
        _test = "anonymous_test"
    else:
        _test = "logged_test"
    if "ROLE" in session:
        if session["ROLE"] == "HEALTH":
            n_positive = db.session.query(Positive).filter_by(marked=True).count()
            n_healed = (
                db.session.query(Positive)
                .filter_by(marked=False)
                .distinct(Positive.user_id)
                .count()
            )
            return render_template(
                "index_health.html",
                _test=_test,
                n_positive=n_positive,
                n_healed=n_healed,
            )
        elif session["ROLE"] == "OPERATOR":
            if "RESTAURANT_ID" in session:
                restaurant_id = session["RESTAURANT_ID"]
                model = RestaurantServices.get_all_restaurants_info(restaurant_id)
                if model is None:
                    abort(501)
                weekDaysLabel = [
                    "Monday",
                    "Tuesday",
                    "Wednesday",
                    "Thursday",
                    "Friday",
                    "Saturday",
                    "Sunday",
                ]
                return render_template(
                    "restaurantsheet.html",
                    id=restaurant_id,
                    name=model.name,
                    lat=model.lat,
                    lon=model.lon,
                    phone=model.phone,
                    covid_measures=model.covid_measures,
                    hours=model.opening_hours,
                    cuisine=model.cusine,
                    weekDaysLabel=weekDaysLabel,
                    photos=model.photos,
                    reviews=RestaurantServices.get_three_reviews(restaurant_id),
                    dishes=model.dishes,
                    _test=_test,
                )
            else:
                return render_template("norestaurant.html", _test=_test)
        elif session["ROLE"] == "CUSTOMER":
            form = ReservationForm()
            is_positive = UserService.is_positive(current_user.id)
            return render_template(
                "index_customer.html",
                _test=_test,
                restaurants=restaurants,
                form=form,
                is_positive=is_positive,
            )

    return render_template("index.html", _test=_test, restaurants=restaurants)


from django import forms
from django.forms import ModelForm
from django.forms import widgets
from django.forms.models import ModelChoiceField
from django.forms.widgets import Widget
from . models import TipoMoneda, Contacto

class ContactoForm(forms.ModelForm):

    class Meta:
        model= Contacto
        fields = ['numero_identificaion', 'nombre_completo', 'telefono', 'direccion', 'email' , 'pais','contraseña','moneda']
        labels ={
            'numero_identificaion': ' Ingrese su Numero de Identificacion:',
            'nombre_completo': 'Ingrese su Nombre completo:',
            'telefono': 'Ingrese su Telefono:',
            'direccion': 'Ingrese su Direccion:',
            'email': 'Ingrese su Email:',
            'pais': 'Ingrese su Pais:',
            'contraseña': 'Ingrese su Contraseña',
            'moneda': 'Ingrese su Moneda',
        }
        widgets={
            'numero_identificaion': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Numero de Identificacion',
                    'id': 'numero_identificaion',
                    'name': 'numero_identificaion',

                }
            ),
            'nombre_completo': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Nombre Completo',
                    'id': 'nombre_completo',
                    'name': 'nombre_completo',
                }
            ),
            'telefono': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Telefono',
                    'id': 'telefono',
                    'name': 'telefono',
                }
            ),

            'direccion': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Direccion',
                    'id': 'direccion',
                    'name': 'direccion',
                }
            ),
            'email': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Email',
                    'id': 'email',
                    'name': 'email',
                    'type': 'email',
                }
            ),
            'pais': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Pais',
                    'id': 'pais',
                    'name': 'pais',
                }
            ),
            'contraseña': forms.TextInput(
                attrs={
                    'class': 'form-control',
                    'placeholder': 'Contraseña',
                    'id': 'pais',
                    'name': 'contraseña',
                    'type': 'password'
                }
            ),
            'moneda': forms.Select(
                attrs={
                    'class': 'form-control',
                    'id': 'moneda',
                    'name': 'moneda'
                }
            ),

        }


import bindings
from compile import FullyQualifiedCommand, KeyCombo
import yaml

allcommands = []
commandsmap = {}

def register_command(combo, cmd):
    combo = str(combo)
    if combo in commandsmap:
        commandsmap[combo].append(cmd.to_dict())
    else:
        commandsmap[combo] = [cmd.to_dict()]

for context_group in bindings.keyconfig_data:
    context = context_group[0]
    types = context_group[1]
    specs = context_group[2]
    for item in specs["items"]:
        command = item[0]
        keycombo = KeyCombo.from_dict(item[1])
        options = item[2]
        fqcommand = FullyQualifiedCommand(
            context, types["space_type"], types["region_type"], command
        )
        allcommands.append(fqcommand)
        register_command(keycombo, fqcommand)

print(yaml.dump(commandsmap))


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

# In[1]:

import pandas as pd
import numpy as np

# In[4]:

data=pd.read_csv("vgsales.csv")
data

# In[6]:

#DATA CLEANING
#Mengecek Missing Value
data.isnull().sum()

# In[10]:

# melakukan isian missing value,
from scipy.stats import mode

data['Year'] = data['Year'].fillna(data['Year'].mode()[0])
data['Publisher'] = data['Publisher'].fillna(data['Publisher'].mode()[0])

# In[12]:

#mengecek data missing value
data.isnull().sum()

# In[14]:

data.info()

# In[17]:

data['Year']=data['Year'].astype('int64')
data.info()

# In[18]:

data.to_csv("vgsales_clean.csv")

# In[42]:

#import package
import pandas as pd
import numpy as np
import matplotlib as plt
from pylab import *
import seaborn as sns
from matplotlib import *
import sys
from pylab import pl
f = figure.Figure(figsize=(17,10))

# In[43]:

#TOTAL PENJUALAN DAN JUMLAH GAME DI SELURUH DUNIA (BAR CHART)
plt.figure(figsize=(17,10))

plt.subplot(2,2,1)
sns.barplot(x='Year', y='Global_Sales', data=data.groupby(data['Year']).sum().Global_Sales.reset_index(), palette='Spectral')
plt.ylabel('Global_sales')
plt.xlabel('Tahun')
plt.xticks(rotation=90)
plt.title('Total Penjualan Game di Seluruh Dunia')

plt.subplot(2,2,2)
sns.barplot(x=data['Year'].value_counts().index, y=data['Year'].value_counts())
plt.ylabel('Jumlah Game')
plt.xlabel('Tahun')
plt.xticks(rotation=90)
plt.title('Total Jumlah Game yang Dirilis setiap Tahun')

# Karna data sebelumnya belum tampil, naka

# In[51]:

EU= data.pivot_table('EU_Sales', columns='Name',index='Year', aggfunc='sum').sum(axis=1)
NA= data.pivot_table('NA_Sales', columns='Name',index='Year', aggfunc='sum').sum(axis=1)
JP= data.pivot_table('JP_Sales', columns='Name',index='Year', aggfunc='sum').sum(axis=1)
Other= data.pivot_table('Other_Sales', columns='Name',index='Year', aggfunc='sum').sum(axis=1)
years= Other.index.astype(int)

plt.figure(figsize=(10,6))
ax = sns.pointplot(x=years, y=EU, color='mediumslateblue', scale=0.7)
ax = sns.pointplot(x=years, y=NA, color='cornflowerblue', scale=0.7)
ax = sns.pointplot(x=years, y=JP, color='orchid', scale=0.7)
ax = sns.pointplot(x=years, y=Other, color='thistle', scale=0.7)
ax.set_xticklabels(labels=years, rotation=90)
ax.set_xlabel(xlabel='Tahun', fontsize=14)
ax.set_ylabel(ylabel='Penjualan', fontsize=14)
ax.set_title(label='Penjualan Game di Berbagai Negara', fontsize=15)
ax.legend(handles=ax.lines[::len(years)+1], labels=['European Unio','Nort America', 'Japan','Other'])
plt.show()

# In[55]:

#Persentase Genre Game (Pie Chart)
plt.figure(figsize=(8,8))
color=['#0a5f38','#048243','#0cb577','#12e193','#05ffa6','#7bfdc7','#b8ffeb','#13eac9','#24bca8','#029386','#014d4e']
exp=[0.1,0,0,0,0,0,0,0,0,0,0,0]
plt.pie(data['Genre'].value_counts(), labels=data['Genre'].value_counts().index, autopct='%1.1f%%',explode=exp, colors=color);
plt.title('Genre');

# In[61]:

df= data.groupby(['Publisher']).sum()['Global_Sales']
df=pd.DataFrame(df.sort_values(ascending=False))[0:10]
publisher=df.index
df.columns=['Global Sales']

plt.figure(figsize=(10,6))
ax= sns.barplot(y=publisher, x='Global Sales', data=df, palette='Purples_r')
ax.set_xlabel(xlabel='Global Sales', fontsize=14)
ax.set_ylabel(ylabel='Publisher', fontsize=14)
ax.set_title(label='Top 10 Total Penjualan Publisher', fontsize=15)
ax.set_yticklabels(labels= publishers)
plt.show()

# In[ ]:


from django.shortcuts import render
from rest_framework.views import APIView
from .serializers import *
from rest_framework.response import Response
from administrator.models import *
from .permissions import *

# Create your views here.

# urlpatterns = [
#     path('admission_form/', Admission_view.as_view(), name = 'admission-form'),
#     path('application_form/', Application_view.as_view(), name = 'application-form'),
#     path('payment_form/<str:name
# >/', PaymentView.as_view(), name = 'payment_update'),
#     path('course/', CourseView.as_view(), name = 'courses'),

# ]

class Admission_view(APIView):

    def post(self, request):

        serializer = Admission_Forms_detailSerializer(data = request.data)
        serializer.is_valid(raise_exception = True)
        serializer.save()

        return Response(serializer.data)

    def get(self, request):
        # create permission file
        queryset = Admission_Forms_detail.objects.all()
        serializer = Admission_Forms_detailSerializer(queryset, many=True)

        for applicant in queryset:
            if applicant.status == 'Pending Approval' and int(applicant.grade) <= 15:
                applicant.status = 'Approved'
                applicant.save()

        return Response(serializer.data)

class Application_view(APIView):

    def post(self, request):

        serializer = Application_form_detailSerializer(data = request.data)
        serializer.is_valid(raise_exception = True)
        serializer.save()

        return Response(serializer.data)

    def get(self, request):
        # create permission file
        permission_classes = (Admin_priviledge)
        queryset = Application_Form_detail.objects.all()
        serializer = Application_form_detailSerializer(queryset, many=True)

        for applicant in queryset:
            if applicant.duration_of_work == 'Full time':
                applicant.status = 'Approved'
                applicant.save()

        return Response(serializer.data)

class PaymentView(APIView):

    def get(self, request, name):
        permission_classes = (Student_priviledge, Admin_priviledge)
        queryset = Student_Payment_Details.objects.filter(name = name)
        serializer = Student_Payment_DetailsSerializer(queryset, many = True)

        return Response(serializer.data)

    def patch(self, request, name):
        permission_classes = (Admin_priviledge)
        queryset = Student_Payment_Details.objects.get(name = name)
        serializer = Student_Payment_DetailsSerializer(instance = queryset, data = request.data, partial=True)

        serializer.is_valid()
        serializer.save()

        return Response(serializer.data)

class CourseView(APIView):

    def post(self, request):

        permission_classes = (Admin_priviledge)
        serializer = CourseSerializer(data = request.data)
        serializers.is_valid(raise_exception = True)
        serializer.save()

        return Response(serilizer.data)

class RegisterationView(APIView):

    def post(self, request):
        serializer = UserDataSerializer(data = request.data)
        serializer.is_valid(raise_exception = True)
        serializer.save()

        return Response(serializer.data)

class StudentRegisterationView(APIView):
    # check this functionaltity
    def post(self, request):

        student = 0
        for students in Admission_Forms_detail.objects.all():

            if students.admission_number == int(request.data.get('admission_number')) and students.status == 'Approved':
                student = int(request.data.get('admission_number'))

        if student == int(request.data.get('admission_number')):
            pass
        else:
            print(type(student))
            print(student)
            print(int(request.data.get('admission_number')))
            print(type(int(request.data.get('admission_number'))))

            return Response({'Your admission was not approved':'Contact the school authorities or apply next time. Thank you'})

        serializer = StudentRegisterationSerializer(data = request.data)
        serializer.is_valid(raise_exception = True)
        serializer.save()

        return Response(serializer.data)

class TeacherRegisterationView(APIView):

    def post(Self, request):

        teacher = 0
        for teachers in Application_Form_detail.objects.all():

            if teachers.application_number == int(request.data.get('application_number')) and teachers.status == 'Approved':
                teacher = int(request.data.get('application_number'))

        if teacher == int(request.data.get('application_number')):
            pass
        else:

            return Response({'Your application was not approved':'Contact the school authorities or apply next time. Thank you'})

        serializer = TeacherRegisterationSerializer(data = request.data)
        serializer.is_valid(raise_exception = True)
        serializer.save()

        return Response(serializer.data)


from typing import List
class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        product = 1
        res = [1] * len(nums)
        for i in range(1, len(nums)):
            product *= nums[i-1]
            res[i] *= product

        product = 1
        for j in range(len(nums)-2, -1, -1):
            product *= nums[j+1]
            res[j] *= product
        return res


import cv2 as cv
import numpy as np

img = cv.imread('Resources/gray_img.png')
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thrash = cv.threshold(gray_img, 240, 255, cv.CHAIN_APPROX_NONE)
contours, hierarchy = cv.findContours(thrash, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)

for contour in contours:
    cv.drawContours(img, contour, 0, (0, 0, 0), 5)
    approx = cv.approxPolyDP(contour, 0.01*cv.arcLength(contour, True), True)
    x, y, w, h = cv.boundingRect(approx)

    if len(approx) == 3:
        cv.putText(img, "Triangle", (x, y), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))

    elif len(approx) == 4:
        aspectRatio = float(w)/h
        if aspectRatio >= 0.95 and aspectRatio < 1.05:
            cv.putText(img, "Square", (x, y), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
        else:
            cv.putText(img, "Rectangle", (x, y), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))

    elif len(approx) == 5:
        cv.putText(img, "Pentagon", (x, y), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))

    else:
        cv.putText(img, "Circle", (x, y), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))

cv.waitKey(0)


from google.cloud import firestore

db = firestore.Client()

class Cinema(object):
    def __init__(self):
        pass

    def post_book_cinema(self, date, time, seat):
        ref = db.collection(u'cinema').document(f'{date}T{time}')
        if ref.get().exists:
            ref.update({
                        "bookedSeats": firestore.ArrayUnion([seat])
            })
        else:
            ref.set({
                        "bookedSeats": firestore.ArrayUnion([seat])
            })

    def get_book_cinema(self, date, time):
        ref = db.collection(u'cinema').document(f'{date}T{time}').get()
        if ref.exists:
            r = ref.to_dict()
            return r['bookedSeats']
        return []

    def get_book_date(self, date):
        retVal = []
        for time in ["19:30", "21:00", "22:30"]:
            ref = db.collection(u'cinema').document(f'{date}T{time}').get()
            if ref.exists:
                r = ref.to_dict()
                r['time'] = time
                retVal.append(r)
        return retVal


from schemas import UserModel
from sqlalchemy.orm import Session

from db.models import User
from libgravatar import Gravatar

async def get_user_by_email(email: str, db: Session) -> User:
    """
    Gets user by email address.

    :param email: Email address.
    :type email: str
    :param db: Database session.
    :type db: Session
    :return: User.
    :rtype: User
    """
    return db.query(User).filter(User.email == email).first()

async def create_user(body: UserModel, db: Session) -> User:
    """
    Creates new user.

    :param body: Data for contact.
    :type body: UserModel
    :param db: Database session.
    :type db: Session
    :return: Created user.
    :rtype: User
    """
    avatar = None
    try:
        g = Gravatar(body.email)
        avatar = g.get_image()
    except Exception as e:
        print(e)

    new_user = User(**body.model_dump(), avatar=avatar)
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    return new_user

async def update_token(user: User, token: str | None, db: Session) -> None:
    """
    Updates refresh token for specific user.

    :param user: User for which token will update.
    :type user: User
    :param token: Refresh token.
    :type token: str | None
    :param db: Database session.
    :type db: Session
    :return: None.
    :rtype: None
    """
    user.refresh_token = token
    db.commit()

async def confirmed_email(email: str, db: Session) -> None:
    """
    Confirms email for specific user.

    :param email: Email address.
    :type email: str
    :param db: Database session.
    :type db: Session
    :return: None.
    :rtype: None
    """
    user = await get_user_by_email(email, db)
    user.confirmed = True
    db.commit()

async def update_avatar(email: str, url: str, db: Session) -> User:
    """
    Updates avatar for specific user.

    :param email: Email address.
    :type email: str
    :param url: Cloudinary URL address.
    :type url: str
    :param db: Database session.
    :type db: Session
    :return: Updated user.
    :rtype: User
    """
    user = await get_user_by_email(email, db)
    user.avatar = url
    db.commit()
    return user


import requests
from bs4 import BeautifulSoup

### 코드를 작성하세요 ###
page = requests.get("https://workey.codeit.kr/orangebottle/index")
soupedPage = BeautifulSoup(page.text, "html.parser")
branchList = soupedPage.select(".branch")
branch_infos = []
for info in branchList:
    branch_info = info.select("p span")
    branch_name = branch_info[0].get_text()
    address = branch_info[2].get_text()
    phone_number = branch_info[3].get_text()
    # address = info.select(".address")
    # phone_number = info.select(".phoneNum")
    # print(branch_name)
    branch_infos.append([branch_name, address, phone_number])

# 출력 코드
print(branch_infos)


# -*- coding: utf-8 -*-
"""
Define some generic socket functions for network modules
"""

# Import python libs
import os
import re
import logging
import subprocess
import socket
import platform

from hubblestack.utils.versions import LooseVersion
import hubblestack.utils.path
import hubblestack.utils.platform
from hubblestack.utils._compat import ipaddress

# Attempt to import wmi
try:
    import wmi
    import hubblestack.utils.winapi
except ImportError:
    pass

log = logging.getLogger(__name__)

try:
    import ctypes
    import ctypes.util
    libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c"))
    res_init = libc.__res_init
except (ImportError, OSError, AttributeError, TypeError):
    pass

def natural_ipv4_netmask(ip, fmt='prefixlen'):
    """
    Returns the "natural" mask of an IPv4 address
    """
    bits = _ipv4_to_bits(ip)

    if bits.startswith('11'):
        mask = '24'
    elif bits.startswith('1'):
        mask = '16'
    else:
        mask = '8'

    if fmt == 'netmask':
        return cidr_to_ipv4_netmask(mask)
    else:
        return '/' + mask

def _ipv4_to_bits(ipaddr):
    """
    Accepts an IPv4 dotted quad and returns a string representing its binary
    counterpart
    """
    return ''.join([bin(int(x))[2:].rjust(8, '0') for x in ipaddr.split('.')])

def cidr_to_ipv4_netmask(cidr_bits):
    """
    Returns an IPv4 netmask
    """
    try:
        cidr_bits = int(cidr_bits)
        if not 1 <= cidr_bits <= 32:
            return ''
    except ValueError:
        return ''

    netmask = ''
    for idx in range(4):
        if idx:
            netmask += '.'
        if cidr_bits >= 8:
            netmask += '255'
            cidr_bits -= 8
        else:
            netmask += '{0:d}'.format(256 - (2 ** (8 - cidr_bits)))
            cidr_bits = 0
    return netmask

def interfaces():
    """
    Return a dictionary of information about all the interfaces on the minion
    """
    if hubblestack.utils.platform.is_windows():
        return win_interfaces()
    elif hubblestack.utils.platform.is_netbsd():
        return netbsd_interfaces()
    else:
        return linux_interfaces()

def win_interfaces():
    """
    Obtain interface information for Windows systems
    """
    with hubblestack.utils.winapi.Com():
        c = wmi.WMI()
        ifaces = {}
        for iface in c.Win32_NetworkAdapterConfiguration(IPEnabled=1):
            ifaces[iface.Description] = dict()
            if iface.MACAddress:
                ifaces[iface.Description]['hwaddr'] = iface.MACAddress
            if iface.IPEnabled:
                ifaces[iface.Description]['up'] = True
                for ip in iface.IPAddress:
                    if '.' in ip:
                        if 'inet' not in ifaces[iface.Description]:
                            ifaces[iface.Description]['inet'] = []
                        item = {'address': ip,
                                'label': iface.Description}
                        if iface.DefaultIPGateway:
                            broadcast = next((i for i in iface.DefaultIPGateway if '.' in i), '')
                            if broadcast:
                                item['broadcast'] = broadcast
                        if iface.IPSubnet:
                            netmask = next((i for i in iface.IPSubnet if '.' in i), '')
                            if netmask:
                                item['netmask'] = netmask
                        ifaces[iface.Description]['inet'].append(item)
                    if ':' in ip:
                        if 'inet6' not in ifaces[iface.Description]:
                            ifaces[iface.Description]['inet6'] = []
                        item = {'address': ip}
                        if iface.DefaultIPGateway:
                            broadcast = next((i for i in iface.DefaultIPGateway if ':' in i), '')
                            if broadcast:
                                item['broadcast'] = broadcast
                        if iface.IPSubnet:
                            netmask = next((i for i in iface.IPSubnet if ':' in i), '')
                            if netmask:
                                item['netmask'] = netmask
                        ifaces[iface.Description]['inet6'].append(item)
            else:
                ifaces[iface.Description]['up'] = False
    return ifaces

def linux_interfaces():
    """
    Obtain interface information for *NIX/BSD variants
    """
    ifaces = dict()
    ip_path = hubblestack.utils.path.which('ip')
    ifconfig_path = None if ip_path else hubblestack.utils.path.which('ifconfig')
    if ip_path:
        cmd1 = subprocess.Popen(
            '{0} link show'.format(ip_path),
            shell=True,
            close_fds=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT).communicate()[0]
        cmd2 = subprocess.Popen(
            '{0} addr show'.format(ip_path),
            shell=True,
            close_fds=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT).communicate()[0]
        ifaces = _interfaces_ip("{0}\n{1}".format(
            hubblestack.utils.stringutils.to_str(cmd1),
            hubblestack.utils.stringutils.to_str(cmd2)))
    elif ifconfig_path:
        cmd = subprocess.Popen(
            '{0} -a'.format(ifconfig_path),
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT).communicate()[0]
        ifaces = _interfaces_ifconfig(hubblestack.utils.stringutils.to_str(cmd))
    return ifaces

def _interfaces_ip(out):
    """
    Uses ip to return a dictionary of interfaces with various information about
    each (up/down state, ip address, netmask, and hwaddr)
    """
    ret = dict()

    def parse_network(value, cols):
        """
        Return a tuple of ip, netmask, broadcast
        based on the current set of cols
        """
        brd = None
        scope = None
        if '/' in value:  # we have a CIDR in this address
            ip, cidr = value.split('/')  # pylint: disable=C0103
        else:
            ip = value  # pylint: disable=C0103
            cidr = 32

        if type_ == 'inet':
            mask = cidr_to_ipv4_netmask(int(cidr))
            if 'brd' in cols:
                brd = cols[cols.index('brd') + 1]
        elif type_ == 'inet6':
            mask = cidr
            if 'scope' in cols:
                scope = cols[cols.index('scope') + 1]
        return (ip, mask, brd, scope)

    groups = re.compile('\r?\n\\d').split(out)
    for group in groups:
        iface = None
        data = dict()

        for line in group.splitlines():
            if ' ' not in line:
                continue
            match = re.match(r'^\d*:\s+([\w.\-]+)(?:@)?([\w.\-]+)?:\s+<(.+)>', line)
            if match:
                iface, parent, attrs = match.groups()
                if 'UP' in attrs.split(','):
                    data['up'] = True
                else:
                    data['up'] = False
                if parent:
                    data['parent'] = parent
                continue

            cols = line.split()
            if len(cols) >= 2:
                type_, value = tuple(cols[0:2])
                iflabel = cols[-1:][0]
                if type_ in ('inet', 'inet6'):
                    if 'secondary' not in cols:
                        ipaddr, netmask, broadcast, scope = parse_network(value, cols)
                        if type_ == 'inet':
                            if 'inet' not in data:
                                data['inet'] = list()
                            addr_obj = dict()
                            addr_obj['address'] = ipaddr
                            addr_obj['netmask'] = netmask
                            addr_obj['broadcast'] = broadcast
                            addr_obj['label'] = iflabel
                            data['inet'].append(addr_obj)
                        elif type_ == 'inet6':
                            if 'inet6' not in data:
                                data['inet6'] = list()
                            addr_obj = dict()
                            addr_obj['address'] = ipaddr
                            addr_obj['prefixlen'] = netmask
                            addr_obj['scope'] = scope
                            data['inet6'].append(addr_obj)
                    else:
                        if 'secondary' not in data:
                            data['secondary'] = list()
                        ip_, mask, brd, scp = parse_network(value, cols)
                        data['secondary'].append({
                            'type': type_,
                            'address': ip_,
                            'netmask': mask,
                            'broadcast': brd,
                            'label': iflabel,
                        })
                        del ip_, mask, brd, scp
                elif type_.startswith('link'):
                    data['hwaddr'] = value
        if iface:
            ret[iface] = data
            del iface, data
    return ret

def _interfaces_ifconfig(out):
    """
    Uses ifconfig to return a dictionary of interfaces with various information
    about each (up/down state, ip address, netmask, and hwaddr)
    """
    ret = dict()

    piface = re.compile(r'^([^\s:]+)')
    pmac = re.compile('.*?(?:HWaddr|ether|address:|lladdr) ([0-9a-fA-F:]+)')
    if hubblestack.utils.platform.is_sunos():
        pip = re.compile(r'.*?(?:inet\s+)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*)')
        pip6 = re.compile('.*?(?:inet6 )([0-9a-fA-F:]+)')
        pmask6 = re.compile(r'.*?(?:inet6 [0-9a-fA-F:]+/(\d+)).*')
    else:
        pip = re.compile(r'.*?(?:inet addr:|inet [^\d]*)(.*?)\s')
        pip6 = re.compile('.*?(?:inet6 addr: (.*?)/|inet6 )([0-9a-fA-F:]+)')
        pmask6 = re.compile(
            r'.*?(?:inet6 addr: [0-9a-fA-F:]+/(\d+)|prefixlen (\d+))(?: Scope:([a-zA-Z]+)| scopeid (0x[0-9a-fA-F]))?')
    pmask = re.compile(r'.*?(?:Mask:|netmask )(?:((?:0x)?[0-9a-fA-F]{8})|([\d\.]+))')
    pupdown = re.compile('UP')
    pbcast = re.compile(r'.*?(?:Bcast:|broadcast )([\d\.]+)')

    groups = re.compile('\r?\n(?=\\S)').split(out)
    for group in groups:
        data = dict()
        iface = ''
        updown = False
        for line in group.splitlines():
            miface = piface.match(line)
            mmac = pmac.match(line)
            mip = pip.match(line)
            mip6 = pip6.match(line)
            mupdown = pupdown.search(line)
            if miface:
                iface = miface.group(1)
            if mmac:
                data['hwaddr'] = mmac.group(1)
                if hubblestack.utils.platform.is_sunos():
                    expand_mac = []
                    for chunk in data['hwaddr'].split(':'):
                        expand_mac.append('0{0}'.format(chunk) if len(chunk) < 2 else '{0}'.format(chunk))
                    data['hwaddr'] = ':'.join(expand_mac)
            if mip:
                if 'inet' not in data:
                    data['inet'] = list()
                addr_obj = dict()
                addr_obj['address'] = mip.group(1)
                mmask = pmask.match(line)
                if mmask:
                    if mmask.group(1):
                        mmask = _number_of_set_bits_to_ipv4_netmask(
                            int(mmask.group(1), 16))
                    else:
                        mmask = mmask.group(2)
                    addr_obj['netmask'] = mmask
                mbcast = pbcast.match(line)
                if mbcast:
                    addr_obj['broadcast'] = mbcast.group(1)
                data['inet'].append(addr_obj)
            if mupdown:
                updown = True
            if mip6:
                if 'inet6' not in data:
                    data['inet6'] = list()
                addr_obj = dict()
                addr_obj['address'] = mip6.group(1) or mip6.group(2)
                mmask6 = pmask6.match(line)
                if mmask6:
                    addr_obj['prefixlen'] = mmask6.group(1) or mmask6.group(2)
                    if not hubblestack.utils.platform.is_sunos():
                        ipv6scope = mmask6.group(3) or mmask6.group(4)
                        addr_obj['scope'] = ipv6scope.lower() if ipv6scope is not None else ipv6scope
                # SunOS sometimes has ::/0 as inet6 addr when using addrconf
                if not hubblestack.utils.platform.is_sunos() \
                        or addr_obj['address'] != '::' \
                        and addr_obj['prefixlen'] != 0:
                    data['inet6'].append(addr_obj)
        data['up'] = updown
        if iface in ret:
            # SunOS optimization, where interfaces occur twice in 'ifconfig -a'
            # output with the same name: for ipv4 and then for ipv6 addr family.
            # Every instance has it's own 'UP' status and we assume that ipv4
            # status determines global interface status.
            #
            # merge items with higher priority for older values
            # after that merge the inet and inet6 sub items for both
            ret[iface] = dict(list(data.items()) + list(ret[iface].items()))
            if 'inet' in data:
                ret[iface]['inet'].extend(x for x in data['inet'] if x not in ret[iface]['inet'])
            if 'inet6' in data:
                ret[iface]['inet6'].extend(x for x in data['inet6'] if x not in ret[iface]['inet6'])
        else:
            ret[iface] = data
        del data
    return ret

def _number_of_set_bits_to_ipv4_netmask(set_bits):  # pylint: disable=C0103
    """
    Returns an IPv4 netmask from the integer representation of that mask.

    Ex. 0xffffff00 -> '255.255.255.0'
    """
    return cidr_to_ipv4_netmask(_number_of_set_bits(set_bits))

def _number_of_set_bits(x):
    """
    Returns the number of bits that are set in a 32bit int
    """
    # Taken from http://stackoverflow.com/a/4912729. Many thanks!
    x -= (x >> 1) & 0x55555555
    x = ((x >> 2) & 0x33333333) + (x & 0x33333333)
    x = ((x >> 4) + x) & 0x0f0f0f0f
    x += x >> 8
    x += x >> 16
    return x & 0x0000003f

def netbsd_interfaces():
    """
    Obtain interface information for NetBSD >= 8 where the ifconfig
    output diverged from other BSD variants (Netmask is now part of the
    address)
    """
    # NetBSD versions prior to 8.0 can still use linux_interfaces()
    if LooseVersion(os.uname()[2]) < LooseVersion('8.0'):
        return linux_interfaces()

    ifconfig_path = hubblestack.utils.path.which('ifconfig')
    cmd = subprocess.Popen(
        '{0} -a'.format(ifconfig_path),
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT).communicate()[0]
    return _netbsd_interfaces_ifconfig(hubblestack.utils.stringutils.to_str(cmd))

def _netbsd_interfaces_ifconfig(out):
    """
    Uses ifconfig to return a dictionary of interfaces with various information
    about each (up/down state, ip address, netmask, and hwaddr)
    """
    ret = dict()

    piface = re.compile(r'^([^\s:]+)')
    pmac = re.compile('.*?address: ([0-9a-f:]+)')

    pip = re.compile(r'.*?inet [^\d]*(.*?)/([\d]*)\s')
    pip6 = re.compile(r'.*?inet6 ([0-9a-f:]+)%([a-zA-Z0-9]*)/([\d]*)\s')

    pupdown = re.compile('UP')
    pbcast = re.compile(r'.*?broadcast ([\d\.]+)')

    groups = re.compile('\r?\n(?=\\S)').split(out)
    for group in groups:
        data = dict()
        iface = ''
        updown = False
        for line in group.splitlines():
            miface = piface.match(line)
            mmac = pmac.match(line)
            mip = pip.match(line)
            mip6 = pip6.match(line)
            mupdown = pupdown.search(line)
            if miface:
                iface = miface.group(1)
            if mmac:
                data['hwaddr'] = mmac.group(1)
            if mip:
                if 'inet' not in data:
                    data['inet'] = list()
                addr_obj = dict()
                addr_obj['address'] = mip.group(1)
                mmask = mip.group(2)
                if mip.group(2):
                    addr_obj['netmask'] = cidr_to_ipv4_netmask(mip.group(2))
                mbcast = pbcast.match(line)
                if mbcast:
                    addr_obj['broadcast'] = mbcast.group(1)
                data['inet'].append(addr_obj)
            if mupdown:
                updown = True
            if mip6:
                if 'inet6' not in data:
                    data['inet6'] = list()
                addr_obj = dict()
                addr_obj['address'] = mip6.group(1)
                mmask6 = mip6.group(3)
                addr_obj['scope'] = mip6.group(2)
                addr_obj['prefixlen'] = mip6.group(3)
                data['inet6'].append(addr_obj)
        data['up'] = updown
        ret[iface] = data
        del data
    return ret

def get_fqhostname():
    """
    Returns the fully qualified hostname
    """
    l = [socket.getfqdn()]

    # try socket.getaddrinfo
    try:
        addrinfo = socket.getaddrinfo(
            socket.gethostname(), 0, socket.AF_UNSPEC, socket.SOCK_STREAM,
            socket.SOL_TCP, socket.AI_CANONNAME
        )
        for info in addrinfo:
            # info struct [family, socktype, proto, canonname, sockaddr]
            if len(info) >= 4:
                l.append(info[3])
    except socket.gaierror:
        pass

    return l and l[0] or None

def ip_addrs(interface=None, include_loopback=False, interface_data=None):
    """
    Returns a list of IPv4 addresses assigned to the host. 127.0.0.1 is
    ignored, unless 'include_loopback=True' is indicated. If 'interface' is
    provided, then only IP addresses from that interface will be returned.
    """
    return _ip_addrs(interface, include_loopback, interface_data, 'inet')

def _ip_addrs(interface=None, include_loopback=False, interface_data=None, proto='inet'):
    """
    Return the full list of IP adresses matching the criteria

    proto = inet|inet6
    """
    ret = set()

    ifaces = interface_data \
        if isinstance(interface_data, dict) \
        else interfaces()
    if interface is None:
        target_ifaces = ifaces
    else:
        target_ifaces = dict([(k, v) for k, v in iter(ifaces.items())
                              if k == interface])
        if not target_ifaces:
            log.error('Interface %s not found.', interface)
    for ip_info in target_ifaces.values():
        addrs = ip_info.get(proto, [])
        addrs.extend([addr for addr in ip_info.get('secondary', []) if addr.get('type') == proto])

        for addr in addrs:
            addr = ipaddress.ip_address(addr.get('address'))
            if not addr.is_loopback or include_loopback:
                ret.add(addr)
    return [str(addr) for addr in sorted(ret)]

def ip_addrs6(interface=None, include_loopback=False, interface_data=None):
    """
    Returns a list of IPv6 addresses assigned to the host. ::1 is ignored,
    unless 'include_loopback=True' is indicated. If 'interface' is provided,
    then only IP addresses from that interface will be returned.
    """
    return _ip_addrs(interface, include_loopback, interface_data, 'inet6')

def is_ipv6(ip):
    """
    Returns a bool telling if the value passed to it was a valid IPv6 address
    """
    try:
        return ipaddress.ip_address(ip).version == 6
    except ValueError:
        return False

def is_ipv4(ip):
    """
    Returns a bool telling if the value passed to it was a valid IPv4 address
    """
    try:
        return ipaddress.ip_address(ip).version == 4
    except ValueError:
        return False

def refresh_dns():
    """
    issue #21397: force glibc to re-read resolv.conf
    """
    try:
        res_init()
    except NameError:
        # Exception raised loading the library, thus res_init is not defined
        pass

def in_subnet(cidr, addr=None):
    """
    Returns True if host or (any of) addrs is within specified subnet, otherwise False
    """
    try:
        cidr = ipaddress.ip_network(cidr)
    except ValueError:
        log.error("Invalid CIDR '%s'", cidr)
        return False

    if addr is None:
        addr = ip_addrs()
        addr.extend(ip_addrs6())
    elif not isinstance(addr, (list, tuple)):
        addr = (addr,)

    return any(ipaddress.ip_address(item) in cidr for item in addr)

def _generate_minion_id():
    '''
    Get list of possible host names and convention names.

    :return:
    '''
    # There are three types of hostnames:
    # 1. Network names. How host is accessed from the network.
    # 2. Host aliases. They might be not available in all the network or only locally (/etc/hosts)
    # 3. Convention names, an internal nodename.

    class DistinctList(list):
        '''
        List, which allows one to append only distinct objects.
        Needs to work on Python 2.6, because of collections.OrderedDict only since 2.7 version.
        Override 'filter()' for custom filtering.
        '''
        localhost_matchers = [r'localhost.*', r'ip6-.*', r'127[.]\d', r'0\.0\.0\.0',
                              r'::1.*', r'ipv6-.*', r'fe00::.*', r'fe02::.*', r'1.0.0.*.ip6.arpa']

        def append(self, p_object):
            if p_object and p_object not in self and not self.filter(p_object):
                super(self.__class__, self).append(p_object)
            return self

        def extend(self, iterable):
            for obj in iterable:
                self.append(obj)
            return self

        def filter(self, element):
            'Returns True if element needs to be filtered'
            for rgx in self.localhost_matchers:
                if re.match(rgx, element):
                    return True

        def first(self):
            return self and self[0] or None

    hostname = socket.gethostname()

    hosts = DistinctList().append(
        hubblestack.utils.stringutils.to_unicode(socket.getfqdn(hubblestack.utils.stringutils.to_bytes(hostname)))
    ).append(platform.node()).append(hostname)
    if not hosts:
        try:
            for a_nfo in socket.getaddrinfo(hosts.first() or 'localhost', None, socket.AF_INET,
                                            socket.SOCK_RAW, socket.IPPROTO_IP, socket.AI_CANONNAME):
                if len(a_nfo) > 3:
                    hosts.append(a_nfo[3])
        except socket.gaierror:
            log.warning('Cannot resolve address {addr} info via socket: {message}'.format(
                addr=hosts.first() or 'localhost (N/A)', message=socket.gaierror)
            )
    # Universal method for everywhere (Linux, Slowlaris, Windows etc)
    for f_name in ('/etc/hostname', '/etc/nodename', '/etc/hosts',
                   r'{win}\system32\drivers\etc\hosts'.format(win=os.getenv('WINDIR'))):
        try:
            with hubblestack.utils.files.fopen(f_name) as f_hdl:
                for line in f_hdl:
                    line = hubblestack.utils.stringutils.to_unicode(line)
                    hst = line.strip().split('#')[0].strip().split()
                    if hst:
                        if hst[0][:4] in ('127.', '::1') or len(hst) == 1:
                            hosts.extend(hst)
        except IOError:
            pass

    # include public and private ipaddresses
    return hosts.extend([addr for addr in ip_addrs()
                         if not ipaddress.ip_address(addr).is_loopback])

def generate_minion_id():
    '''
    Return only first element of the hostname from all possible list.

    :return:
    '''
    try:
        ret = hubblestack.utils.stringutils.to_unicode(_generate_minion_id().first())
    except TypeError:
        ret = None
    return ret or 'localhost'


# /*******************************************************************************
#  Author		: Gil Gerard Austria, Justin Bernstein, Hayden Daly
#  Date			: 2019-06-09
#  Version      : Sprint.02.Proj.06
#  Description	: Parses Dictionary Data to Output All Errors in Individuals and Families Using Functions Imported from UserStories
#                 Creates/Appends to Txt file ( {fileName}_output.txt )
#                 Returns Table with Individual Data
#  Github       : https://github.com/haydendaly/GEDCOM-Parser
#  Pledge		:"I pledge my honor that I have abided by the Stevens Honor System"	- Gil Gerard Austria, Justin Bernstein, Hayden Daly
#  *******************************************************************************/

# Built-in Python Modules
import sys
import json

# Non-Built-In Python Modules that Need to be Installed
from prettytable import PrettyTable

# Import userstories
from userstories import hdUserStories, jbUserStories, gaUserStories

# Errors:
#   us01 -
#   us02 -
#   us03 -
#   us04 -
#   us05 -
#   us06 -
#   us21 -
#   us42 - (Implemented Directly in All Functions that Output Errors (in userstories))
def displayErrors(fileName, GEDCOM_dict):

    us01 = jbUserStories.us01(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write('[us_01] - Error: Date Occurs After Current Date\n')
        output.write(us01['invalidIndiDates']+'\n\n')
        output.write(us01['invalidFamDates']+'\n\n')
    print('\n[us01] Error: Date Occurs After Current Date')
    print( us01 )

    us02 = jbUserStories.us02(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us02] - Error: Birth Occurs After Marriage Date\n")
        output.write(us02.get_string(title="[us02] - Error: Birth Occurs After Marriage Date")+'\n\n')
    print('\n[us02] Error: Date Occurs After Current Date')
    print( us02 )

    us03 = jbUserStories.us03(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us03] - Error: Birth Occurs After Death Date\n")
        output.write(us02.get_string(title="[us03] - Error: Birth Occurs After Death Date")+'\n\n')
    print('\n[us03] Error: Birth date Occurs After Death Date')
    print( us03 )

    us04 = jbUserStories.us04(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us04] - Error: Divorce Occurs Before Marriage Date\n")
        output.write(us04.get_string(title="[us04] - Error: Divorce Occurs Before Marriage Date")+'\n\n')
    print('\n[us04] Error: Marriage Occurs After Divorce Date')
    print( us04 )

    us05 = jbUserStories.us05(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us05] - Error: Death Occurs Before Marriage Date\n")
        output.write(us05.get_string(title="[us05] - Error: Death Occurs Before Marriage Date")+'\n\n')
    print('\n[us05] Error: Marriage Occurs After Death Date')
    print( us05 )

    us06 = hdUserStories.us06(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us06] - Error: Divorce Before Death\n")
        output.write(us06.get_string(title="[us06] - Error: Divorce Before Death")+'\n\n')
    print('\n[us06] Error: Divorce Before Death')
    print( us06 )

    us09 = jbUserStories.us09(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us09] - Error: Birth Occurs After Parents Death Date\n")
        output.write(us09.get_string(title="[us09] - Error: Birth Occurs After Parents Death Date")+'\n\n')
    print('\n[us09] Error: Birth Occurs After Parents Death Date')
    print( us09 )

    us21 = hdUserStories.us21(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us21] - Error: Incorrect Gender for Role\n")
        output.write(us21.get_string(title="[us21] - Error: Incorrect Gender for Role")+'\n\n')
    print('\n[us21] Error: Incorrect Gender for Role')
    print( us21 )

    us08 = jbUserStories.us08(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us08] - Error: Birth Occurs Before Marriage or After Parents Divorce Date\n")
        output.write(us09.get_string(title="[us08] - Error: Birth Occurs Before Marriage or After Parents Divorce Date")+'\n\n')
    print('\n[us08] Error: Birth Occurs Before Marriage or After Parents Divorce Date')
    print( us08 )

    us12 = jbUserStories.us12(GEDCOM_dict)
    with open(fileName[:-4] + '_output.txt', 'a+') as output:
        output.write("[us12] - Error: Birth Occurs 60 or 80 years after the birth or mother and father respectively\n")
        output.write(us12.get_string(title="[us12] - Error: Birth Occurs 60 or 80 years after the birth or mother and father respectively")+'\n\n')
    print('\n[us12] Error: Birth Occurs 60 or 80 years after the birth or mother and father respectively')
    print( us12 )

    return

def main(fileName, GEDCOM_dict):

    # Case when the Program is Run Directly from Command Line and on an Valid Input File (Sanitized GEDCOM File from 1_sanitizedGEDCOM.py)
    if ( fileName.endswith('_dict.json') ):
        # READ FROM JSON DATA
        with open( fileName ) as GEDCOM_JSON:
            GEDCOM_dict = json.loads( GEDCOM_JSON.read() )

        displayErrors( fileName, GEDCOM_dict )

        return
    # Case when the Program is run from 0_main.py
    else:
        if ( len(GEDCOM_dict) != 0 ):
            displayErrors( fileName, GEDCOM_dict )

            return
        else:
            raise 'Empty Input, no GEDCOM Dictionary Data to Display'

    return

if __name__ == '__main__':
    main(sys.argv[1], {})


import random

from django.core import serializers
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse

from Carts.cart import get_single_item
from Carts.models import *
from Products.models import *
from Stats import stats

# Create your views here.

def _generate_cart_id():
    cart_id = ''
    characters = 'ABCDEFGHIJKLMNOPQRQSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()'
    cart_id_length = 50
    for y in range(cart_id_length):
        cart_id += characters[random.randint(0, len(characters) - 1)]
    return cart_id

def view(request):
    try:
        the_id = request.session['cart_id']
    except KeyError:
        the_id = None

    # the_id = 6
    if the_id:
        try:
            cart = Carts.objects.get(session_id=the_id)
            request.session['total_items'] = cart.cartitems_set.count()
            empty = False
            context = {'cart': cart, }
        except Carts.DoesNotExist:
            if request.session['total_items']:
                del request.session['total_items']
            empty = True
            context = {'empty': empty}
    else:
        empty = True
        context = {'empty': empty}

    # Others queryset
    search_recs = stats.recommended_from_search(request)
    recently_viewed = stats.get_recently_viewed(request)
    view_recs = stats.recommended_from_views(request)
    context['search_recs'] = search_recs
    context['recently_viewed'] = recently_viewed
    context['view_recs'] = view_recs

    template = 'carts/carts.html'
    return render(request, template, context)

def add_to_cart(request, slug):
    try:
        the_id = request.session['cart_id']
    except:
        cart = Carts()
        session_id = str(_generate_cart_id())
        cart.session_id = session_id
        cart.save()
        request.session['cart_id'] = cart.session_id
        the_id = cart.session_id
    try:
        cart = Carts.objects.get(session_id=the_id)
    except:
        del request.session['cart_id']
        return HttpResponseRedirect(reverse('cart_view'))

    try:
        product = Product.objects.get(slug=slug)
    except Product.DoesNotExist:
        print('The product is not register')
    except:
        pass

    cart_item, created = CartItems.objects.get_or_create(cart=cart, product=product)
    try:
        qty = request.GET.get('qty')
    except KeyError:
        print('No QTY attribute founded in request session')
    except:
        pass

    if qty == None:
        qty = 0

    if created:
        if int(qty) == 0:
            qty = 1
        cart_item.quantity = int(qty)
        cart_item.save()
    else:
        if int(qty) == 0:
            cart_item.delete()
        else:
            cart_item.quantity += int(qty)
            cart_item.save()

    new_total = 0.00
    for items in cart.cartitems_set.all():
        line_total = float(items.product.sale_price) * items.quantity
        items.line_total = line_total
        new_total += line_total
        items.save()

    request.session['total_items'] = cart.cartitems_set.count()
    cart.total = new_total
    cart.save()

    # Others queryset
    search_recs = stats.recommended_from_search(request)
    recently_viewed = stats.get_recently_viewed(request)
    view_recs = stats.recommended_from_views(request)

    template = 'carts/carts.html'
    context = locals()
    return render(request, template, context)

def remove_from_cart(request, slug):
    try:
        product = Product.objects.get(slug=slug)
        item = CartItems.objects.get(product=product)
    except:
        return HttpResponseRedirect(reverse('cart_view'))
    item.delete()
    return HttpResponseRedirect(reverse('cart_view'))

def update_cart(request):
    post_data = request.POST.copy()
    item_id = post_data['item_id']
    quantity = request.GET.get('qty')
    cart_item = get_single_item(request, item_id)
    if cart_item:
        if int(quantity) > 0:
            cart_item.quantity = int(quantity)
            cart_item.save()
            return HttpResponseRedirect(reverse('cart_view'))
        else:
            product_slug = cart_item.product.slug
            remove_from_cart(request, product_slug)
    else:
        return HttpResponseRedirect(reverse('cart_view'))

def clear_cart(request):
    pass

def base(request):
    return render(request, 'base.html', locals())