import time
import math
#import audioio
import json
from secrets import secrets
import board
from adafruit_pyportal import PyPortal
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.label import Label
from digitalio import DigitalInOut, Direction, Pull
import analogio
import displayio
#import logging
#import adafruit_logging as logging

class logging:
    """A place holder for the missing adafruit_logging class"""
    name="";

    ERROR=0;
    WARN=1;
    DEBUG=2;
    INFO=3;
    level=INFO;

    def getLogger(name):
        ret=logging();
        ret.name=name;
        return ret;

    def setLevel(self, lvl):
        self.level=lvl;

    def info(self, *args):
        if(self.INFO <= self.level):
            print(args);

    def debug(self, *args):
        if(self.DEBUG <= self.level):
            print(args);

    def warn(self, *args):
        if(self.WARN <= self.level):
            print(args);

    def error(self, *args):
        if(self.ERROR <= self.level):
            print(args);

# Set up where we'll be fetching data from
DATA_SOURCE = 'http://api.openweathermap.org/data/2.5/weather?id='+secrets['city_id']
DATA_SOURCE += '&appid='+secrets['openweather_token']
# You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22'
DATA_LOCATION = []

####################
# setup hardware

pyportal = PyPortal(url=DATA_SOURCE,
                    json_path=DATA_LOCATION,
                    status_neopixel=board.NEOPIXEL)

light = analogio.AnalogIn(board.LIGHT)

snooze_button = DigitalInOut(board.D3)
snooze_button.direction = Direction.INPUT
snooze_button.pull = Pull.UP

####################
# variables

# alarm support

alarm_background = 'red_alert.bmp'
alarm_file = 'alarm.wav'
alarm_enabled = True
alarm_armed = True
alarm_interval = 12.0
alarm_hour = 7
alarm_minute = 45
snooze_time = None
snooze_interval = 600.0

# mugsy support
mugsy_background = 'mugsy_background.bmp'

# weather support

icon_file = None
icon_sprite = None
celcius = secrets['celcius']

# display/data refresh timers

refresh_time = None
update_time = None
weather_refresh = None

# The most recently fetched time
current_time = None

# track whether we're in low light mode

low_light = False

####################
# Load the fonts

time_font = bitmap_font.load_font('/fonts/Anton-Regular-104.bdf')
time_font.load_glyphs(b'0123456789:') # pre-load glyphs for fast printing

alarm_font = bitmap_font.load_font('/fonts/Helvetica-Bold-36.bdf')
alarm_font.load_glyphs(b'0123456789:')

temperature_font = bitmap_font.load_font('/fonts/Arial-16.bdf')
temperature_font.load_glyphs(b'0123456789CF')

####################
# Set up logging

logger = logging.getLogger('alarm_clock')
logger.setLevel(logging.ERROR)            # change as desired

####################
# Functions

def create_text_areas(configs):
    """Given a list of area specifications, create and return test areas."""
    text_areas = []
    for cfg in configs:
        textarea = Label(cfg['font'], text=' '*cfg['size'])
        textarea.x = cfg['x']
        textarea.y = cfg['y']
        textarea.color = cfg['color']
        text_areas.append(textarea)
    return text_areas

def clear_splash():
    for _ in range(len(pyportal.splash) - 1):
        pyportal.splash.pop()

def touch_in_button(t, b):
    in_horizontal = b['left'] <= t[0] <= b['right']
    in_vertical = b['top'] <= t[1] <= b['bottom']
    return in_horizontal and in_vertical

def button_meridian(b):
    meridian = b['right'] - b['left'];
    meridian=meridian/2;
    meridian=meridian+b['left'];
    return meridian;

def button_equator(b):
    equator = b['bottom'] - b['top'];
    equator=equator/2;
    equator=equator+b['top'];
    return equator;

touched = False

####################
# states

class State(object):
    """State abstract base class"""

    def __init__(self):
        pass

    @property
    def name(self):
        """Return the name of teh state"""
        return ''

    def tick(self, now):
        """Handle a tick: one pass through the main loop"""
        pass

    #pylint:disable=unused-argument
    def touch(self, t, touched):
        """Handle a touch event.
        :param (x, y, z) - t: the touch location/strength"""
        return bool(t)

    def enter(self):
        """Just after the state is entered."""
        pass

    def exit(self):
        """Just before the state exits."""
        clear_splash()

class Time_State(State):
    """This state manages the primary time display screen/mode"""

    def __init__(self):
        super().__init__()
        self.background_day = 'main_background_day.bmp'
        self.background_night = 'main_background_night.bmp'
        self.refresh_time = None
        self.update_time = None
        self.weather_refresh = None
        text_area_configs = [dict(x=88, y=170, size=5, color=0xFFFFFF, font=time_font),
                             dict(x=210, y=50, size=5, color=0xFF0000, font=alarm_font),
                             dict(x=88, y=90, size=6, color=0xFFFFFF, font=temperature_font)]
        self.text_areas = create_text_areas(text_area_configs)
        self.weather_icon = displayio.Group()
        self.weather_icon.x = 88
        self.weather_icon.y = 20
        self.icon_file = None

        self.snooze_icon = displayio.Group()
        self.snooze_icon.x = 260
        self.snooze_icon.y = 70
        self.snooze_file = None

        # each button has it's edges as well as the state to transition to when touched
        self.buttons = [dict(left=0, top=50, right=80, bottom=120, next_state='settings'),
                        dict(left=0, top=155, right=80, bottom=220, next_state='mugsy')]

    @property
    def name(self):
        return 'time'

    def adjust_backlight_based_on_light(self, force=False):
        """Check light level. Adjust the backlight and background image if it's dark."""
        global low_light
        if light.value <= 1000 and (force or not low_light):
            pyportal.set_backlight(0.01)
            pyportal.set_background(self.background_night)
            low_light = True
        elif force or (light.value >= 2000 and low_light):
            pyportal.set_backlight(1.00)
            pyportal.set_background(self.background_day)
            low_light = False

    def tick(self, now):
        #print("time.tick");
        global alarm_armed, snooze_time, update_time, current_time

        # is the snooze button pushed? Cancel the snooze if so.
        if not snooze_button.value:
            if snooze_time:
                self.snooze_icon.pop()
            snooze_time = None
            alarm_armed = False

        # is snooze active and the snooze time has passed? Transition to alram is so.
        if snooze_time and ((now - snooze_time) >= snooze_interval):
            change_to_state('alarm')
            return

        # check light level and adjust background & backlight
        #self.adjust_backlight_based_on_light()

        # only query the online time once per hour (and on first run)
        if (not self.refresh_time) or ((now - self.refresh_time) > 3600):
            logger.debug('Fetching time')
            try:
                pyportal.get_local_time(location=secrets['timezone'])
                self.refresh_time = now
            except RuntimeError as e:
                self.refresh_time = now - 3000   # delay 10 minutes before retrying
                logger.error('Some error occured, retrying! - %s', str(e))

        # only query the weather every 10 minutes (and on first run)
        if (not self.weather_refresh) or (now - self.weather_refresh) > 600:
            logger.debug('Fetching weather')
            try:
                value = pyportal.fetch()
                weather = json.loads(value)

                # set the icon/background
                weather_icon_name = weather['weather'][0]['icon']
                try:
                    self.weather_icon.pop()
                except IndexError:
                    pass
                filename = "/icons/"+weather_icon_name+".bmp"
                if filename:
                    if self.icon_file:
                        self.icon_file.close()
                    self.icon_file = open(filename, "rb")
                    icon = displayio.OnDiskBitmap(self.icon_file)
                    try:
                        icon_sprite = displayio.TileGrid(icon,
                                                         pixel_shader=displayio.ColorConverter(),
                                                         x=0, y=0)
                    except TypeError:
                        icon_sprite = displayio.TileGrid(icon,
                                                         pixel_shader=displayio.ColorConverter(),
                                                         position=(0, 0))

                    self.weather_icon.append(icon_sprite)

                temperature = weather['main']['temp'] - 273.15 # its...in kelvin
                if celcius:
                    temperature_text = '%3d C' % round(temperature)
                else:
                    temperature_text = '%3d F' % round(((temperature * 9 / 5) + 32))
                self.text_areas[2].text = temperature_text
                self.weather_refresh = now
                board.DISPLAY.refresh_soon()
                board.DISPLAY.wait_for_frame()

            except RuntimeError as e:
                self.weather_refresh = now - 540   # delay a minute before retrying
                logger.error("Some error occured, retrying! - %s", str(e))

        if (not update_time) or ((now - update_time) > 30):
            # Update the time
            update_time = now
            #time_string=datetime.strftime("%I:%M%p", time.localtime());
            suffix="a";
            current_time = time.localtime();
            hr=current_time.tm_hour;
            mn=current_time.tm_min;
            if(hr>12):
                hr=hr-12;
                suffix="p";

            #time_string = '%02d:%02d' % (current_time.tm_hour,current_time.tm_min)
            time_string = '%02d:%02d' % (hr,mn);
            self.text_areas[0].text = time_string
            board.DISPLAY.refresh_soon()
            board.DISPLAY.wait_for_frame()

            # Check if alarm should sound
        if current_time is not None and not snooze_time:
            minutes_now = current_time.tm_hour * 60 + current_time.tm_min
            minutes_alarm = alarm_hour * 60 + alarm_minute
            #print("now: ", minutes_now);
            #print("alarm: ", minutes_alarm);
            if minutes_now == minutes_alarm:
                #print("alarm should fire if armed");
                if alarm_armed:
                    #print("alarm firing");
                    change_to_state('alarm')
            else:
                alarm_armed = alarm_enabled

    def touch(self, t, touched):
        #print("time.touch(): ", t, touched);
        if t and not touched:             # only process the initial touch
            for button_index in range(len(self.buttons)):
                b = self.buttons[button_index]
                if touch_in_button(t, b):
                    change_to_state(b['next_state'])
                    break
        return bool(t)

    def enter(self):
        print("time.enter()");
        self.adjust_backlight_based_on_light(force=True)
        for ta in self.text_areas:
            pyportal.splash.append(ta)
        pyportal.splash.append(self.weather_icon)
        if snooze_time:
            if self.snooze_file:
                self.snooze_file.close()
            self.snooze_file = open('/icons/zzz.bmp', "rb")
            icon = displayio.OnDiskBitmap(self.snooze_file)
            try:
                icon_sprite = displayio.TileGrid(icon,
                                                 pixel_shader=displayio.ColorConverter(),
                                                 x=0, y=0)
            except TypeError:
                icon_sprite = displayio.TileGrid(icon,
                                                 pixel_shader=displayio.ColorConverter(),
                                                 position=(0, 0))
            self.snooze_icon.append(icon_sprite)
            pyportal.splash.append(self.snooze_icon)
        if alarm_enabled:
            self.text_areas[1].text = '%2d:%02d' % (alarm_hour, alarm_minute)
        else:
            self.text_areas[1].text = '     '
        board.DISPLAY.refresh_soon()
        board.DISPLAY.wait_for_frame()

    def exit(self):
        super().exit()
        for _ in range(len(self.snooze_icon)):
            self.snooze_icon.pop()

class Mugsy_State(Time_State):
    """This state tells Mugsey 'Make me a coffee' """

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

    @property
    def name(self):
        return 'mugsy'

    def tick(self, now):
        # Once the job is done, go back to the main screen
        print("mugsy.tick: change state to time");
        change_to_state('time')

    def enter(self):
        global low_light
        print("mugsy.enter: set backlight and draw mugsy background");
        low_light = False
        pyportal.set_backlight(1.00)
        pyportal.set_background(mugsy_background)
        board.DISPLAY.refresh_soon()
        board.DISPLAY.wait_for_frame()

class Alarm_State(State):
    """This state shows/sounds the alarm.
    Touching anywhere on the screen cancells the alarm.
    Pressing the snooze button turns of the alarm, starting it again in 10 minutes."""

    def __init__(self):
        super().__init__()
        self.sound_alarm_time = None
        #self.audio = audioio.AudioOut(board.SPEAKER)
        #self.sine_wave_sample = audioio.RawSample(sine_wave)

    @property
    def name(self):
        return 'alarm'

    def tick(self, now):
        global snooze_time
        #print("alarm.tick()");
        # is the snooze button pushed
        if not snooze_button.value:
            snooze_time = now
            change_to_state('time')
            return
        #return;
        # is it time to sound the alarm?
        #if self.sound_alarm_time and (now - self.sound_alarm_time) > alarm_interval:
        if True:
            #print("alarm: playing audio");
            self.sound_alarm_time = now

            #self.audio.play(sine_wave_sample, loop=True);
            if(not pyportal.audio.playing):
                logger.info("alarm: playing audio");
                pyportal.play_file(alarm_file, False)

    def touch(self, t, touched):
        global snooze_time
        #print("alarm.touch()", t, touched);
        if t and not touched:
            #self.audio.stop();
            snooze_time = None
            change_to_state('time')
        return bool(t)

    def enter(self):
        global low_light
        #print("entered alarm state");
        self.sound_alarm_time = time.monotonic() - alarm_interval
        pyportal.set_backlight(1.00)
        pyportal.set_background(alarm_background)
        low_light = False
        board.DISPLAY.refresh_soon()
        board.DISPLAY.wait_for_frame()
        #print("alarm.enter() end of method");

    def exit(self):
        global alarm_armed, pyportal
        super().exit()
        pyportal.audio.stop()
        alarm_armed = bool(snooze_time)

class Setting_State(State):
    """This state lets the user enable/disable the alarm and set its time.
    Swiping up/down adjusts the hours & miniutes separately."""

    def __init__(self):
        super().__init__()
        self.previous_touch = None
        self.background = 'settings_background.bmp'
        text_area_configs = [dict(x=88, y=120, size=5, color=0xFFFFFF, font=time_font)]

        self.text_areas = create_text_areas(text_area_configs)
        self.buttons = [dict(left=0, top=30, right=80, bottom=93),    # on
                        dict(left=0, top=98, right=80, bottom=152),   # return
                        dict(left=0, top=155, right=80, bottom=220),  # off
                        dict(left=100, top=0, right=200, bottom = 240), # hours
                        dict(left=220, top=0, right=320, bottom = 240)]   # minutes

    @property
    def name(self):
        return 'settings'

    def touch(self, t, touched):
        global alarm_hour, alarm_minute, alarm_enabled, alarm_armed
        if t:
            if touch_in_button(t, self.buttons[0]):   # on
                logger.debug('ON touched')
                alarm_enabled = True
                alarm_armed=True
                self.text_areas[0].text = '%02d:%02d' % (alarm_hour, alarm_minute)
            elif touch_in_button(t, self.buttons[1]):   # return
                logger.debug('RETURN touched')
                change_to_state('time')
            elif touch_in_button(t, self.buttons[2]): # off
                logger.debug('OFF touched')
                alarm_enabled = False
                self.text_areas[0].text = '     '
            elif alarm_enabled:
                if not self.previous_touch:
                    self.previous_touch = t
                else:
                    if touch_in_button(t, self.buttons[3]):   # HOURS
                        logger.debug('HOURS touched')
                        if t[1] < 120: # top half
                            alarm_hour = (alarm_hour + 1) % 24;
                        else:
                            alarm_hour = (alarm_hour - 1) % 24;

                        logger.debug("Alarm hour now: %d", alarm_hour);
                        self.text_areas[0].text = '%02d:%02d' % (alarm_hour, alarm_minute)
                    elif touch_in_button(t, self.buttons[4]): # MINUTES

                        logger.debug('MINUTES touched')
                        increment=0;

                        if t[1] < button_equator(self.buttons[4]):   # top half
                            increment=1;
                        else:
                            increment=-1;

                        if t[0] < button_meridian(self.buttons[4]): # left half
                            # toggle 10's digit
                            increment=increment*10;

                        alarm_minute = (alarm_minute + increment) % 60;

                        logger.debug('Alarm minute now: %d', alarm_minute)
                        self.text_areas[0].text = '%02d:%02d' % (alarm_hour, alarm_minute)

                    self.previous_touch = t
            board.DISPLAY.refresh_soon()
            board.DISPLAY.wait_for_frame()
        else:
            self.previous_touch = None
        return bool(t)

    def enter(self):
        global snooze_time
        snooze_time = None

        pyportal.set_background(self.background)
        for ta in self.text_areas:
            pyportal.splash.append(ta)
        if alarm_enabled:
            self.text_areas[0].text = '%02d:%02d' % (alarm_hour, alarm_minute) # set time textarea
        else:
            self.text_areas[0].text = '     '

    def exit(self):
        super().exit();
        logger.debug("armed: ", alarm_armed);

####################
# State management

states = {'time': Time_State(),
          'mugsy': Mugsy_State(),
          'alarm': Alarm_State(),
          'settings': Setting_State()}

current_state = None

def change_to_state(state_name):
    global current_state
    if current_state:
        logger.debug('Exiting %s', current_state.name)
        current_state.exit()
    current_state = states[state_name]
    logger.debug('Entering %s', current_state.name)
    current_state.enter()

class SmartTouch:
    """A smart object to collect touch point information"""
    # consider: track maxZ observed and set minZ to 25% of maxZ

    minZ=15000; # default minimum touch pressure
    proximity=20; # default minimum proximity in pixels (square; used for both x and y)

    consecutiveSamps=4; # default number of consecutive valid samples for a touch point to be captured
    currentSamples=[0,0,0,0,0,0,0,0]; # dynamic list size? oh python you confound me. using static for now
    currentIndex=0;

    dbgLvl=0;

    def __init__(self):
        self.zeroize();

    def debug(self, *args):
        self.debugLvl(2, args);

    def debugLvl(self, lvl, *args):
        if(lvl <= self.dbgLvl):
            print(args);

    def zeroize(self):
        self.debug("      * zeroizing...");
        zeroSample=(0,0,0);
        i=0;
        while(i<self.consecutiveSamps):
            self.currentSamples[i]=zeroSample;
            i=i+1;

        self.currentIndex=0;

    def push(self, tp):
        if(tp):
            if(self.currentIndex>=self.consecutiveSamps):
                return True; # exit early if we've already collected enough data

            # valid tp tuple; test minZ
            if(tp[2]>=self.minZ):
                self.debugLvl(1, "RX TP: ", tp);
                #print("TP satisfies minZ");

                if(self.test(tp)):
                    self.debugLvl(1, "   > TP is valid (within proximity)");
                    # if this touchpoint is WITHIN PROXIMITY LIMITS, extend the data set
                    self.currentSamples[self.currentIndex]=tp;
                    self.currentIndex=self.currentIndex+1;
                else:
                    self.debugLvl(0, "   < TP is invalid (outside proximity)", tp);
                    # if this touchpoint is OUTSIDE PROXIMITY LIMITS, zeroize and wait for the next touch
                    self.zeroize();
            else:
                # doesn't satisfy minZ, so IGNORE IT (don't zeroize!)
                self.debugLvl(1, "RX'd TP below minZ: ", tp);

            #self.debugLvl(1, "   currentIndex: ", self.currentIndex);
            #self.debugLvl(1, "   currentSamples:\r\n", self.currentSamples);
            return(self.currentIndex >= self.consecutiveSamps);
        else:
            return False; # return value indicates when we are done

    def test(self, tp):
        # test against minZ in the push() function so we can differentiate between
        # fails due to minZ and fails due to x/y proximity
        #if(tp[2] < self.minZ):
        #    return False;
        #else:
        #    print("TP satisfies minZ");

        if(self.currentIndex==0):
            self.debug("   TP is first sample; always passes test");
            return True; # always accept the first sample
        else:
            self.debug("   testing against average x/y locale");

        pprox=self.proximity;
        nprox=(-1)*self.proximity;

        avgSamp=self.getAvgPosition();
        self.debug("        avgSamp x,y: ", avgSamp[0], avgSamp[1]);
        xDif=avgSamp[0]-tp[0];
        yDif=avgSamp[1]-tp[1];
        self.debug("        xDif, yDif: ", xDif, yDif);

        if(xDif > pprox):
            return False;
        if(xDif < nprox):
            return False;
        if(yDif > pprox):
            return False;
        if(yDif < nprox):
            return False;

        # we've filtered for minZ, x-proximity, and y-proximity
        # so if we reach this line the touchpoint is VALID and the test PASSES
        return True;

    def getAvgPosition(self):
        avgX=0;
        avgY=0;
        i=0;
        while(i<self.currentIndex):
            tmpSamp=self.currentSamples[i];
            avgX=avgX+tmpSamp[0];
            avgY=avgY+tmpSamp[1];
            i=i+1;

        avgX=avgX/(self.currentIndex);
        avgY=avgY/(self.currentIndex);

        #avgX=math.floor(avgX);
        #avgY=math.floor(avgY);

        return (avgX, avgY, self.minZ); # return a touchpoint tuple with > minZ pressure value

    def consume(self):
        ret = self.getAvgPosition();
        self.zeroize();
        self.debugLvl(1, "avgSamp: ", ret);
        return ret;

####################
# And... go

clear_splash()
change_to_state("time")

#pyportal.touchscreen.samples=8;

smarttouch = SmartTouch();
validTouchPoint=False;

#change_to_state("alarm");
tpValid=False;

while True:
    try:
        tp=pyportal.touchscreen.touch_point;
        tpValid=True;
    except:
        logger.error("touchscreen input failure");
        tp=None;
        tpValid=False;

    if(tpValid):
        if(not tp):
            touched=False;

        if(smarttouch.push(tp)):
            # we have captured a smart point
            stp=smarttouch.consume();
            #print("consuming the average touchpoint");
            touched = current_state.touch(stp, touched);
            #smarttouch=SmartTouch(); # create a new smarttouch container
    else:
        time.sleep(1);

    current_state.tick(time.monotonic());

print("System exit!");


from collections import OrderedDict, defaultdict
from dataclasses import dataclass
import os
import json
from typing import Dict, Iterable, List, Optional, Set, Tuple

import dacite

from helm.benchmark.adaptation.adapters.adapter_factory import (
    ADAPT_MULTIPLE_CHOICE_SEPARATE_METHODS,
    ADAPT_MULTIPLE_CHOICE_SEPARATE_CALIBRATED,
)
from helm.benchmark.adaptation.adapter_spec import AdapterSpec
from helm.benchmark.adaptation.request_state import RequestState
from helm.benchmark.adaptation.scenario_state import ScenarioState
from helm.benchmark.augmentations.dialect_perturbation import DialectPerturbation
from helm.benchmark.augmentations.extra_space_perturbation import ExtraSpacePerturbation
from helm.benchmark.augmentations.filler_words_perturbation import FillerWordsPerturbation
from helm.benchmark.augmentations.gender_perturbation import GenderPerturbation
from helm.benchmark.augmentations.misspelling_perturbation import MisspellingPerturbation
from helm.benchmark.augmentations.person_name_perturbation import PersonNamePerturbation
from helm.benchmark.augmentations.perturbation_description import PerturbationDescription
from helm.benchmark.augmentations.space_perturbation import SpacePerturbation
from helm.benchmark.augmentations.synonym_perturbation import SynonymPerturbation
from helm.benchmark.augmentations.typos_perturbation import TyposPerturbation
from helm.benchmark.metrics.metric import PerInstanceStats
from helm.benchmark.presentation.schema import Schema
from helm.benchmark.runner import RunSpec
from helm.benchmark.scenarios.scenario import Instance
from helm.common.general import asdict_without_nones, write
from helm.common.hierarchical_logger import htrack
from helm.common.request import Request

# TODO(#1251): Add proper class registration
_PERTURBATION_NAME_TO_DESCRIPTION = {
    DialectPerturbation.name: DialectPerturbation.Description,
    ExtraSpacePerturbation.name: ExtraSpacePerturbation.Description,
    FillerWordsPerturbation.name: FillerWordsPerturbation.Description,
    GenderPerturbation.name: GenderPerturbation.Description,
    MisspellingPerturbation.name: MisspellingPerturbation.Description,
    PersonNamePerturbation.name: PersonNamePerturbation.Description,
    SpacePerturbation.name: SpacePerturbation.Description,
    SynonymPerturbation.name: SynonymPerturbation.Description,
    TyposPerturbation.name: TyposPerturbation.Description,
}

def _deserialize_perturbation_description(raw_perturbation_description: Dict) -> PerturbationDescription:
    """Convert a raw dictionary to a PerturbationDescription.
    This uses the name field to look up the correct PerturbationDescription subclass to output.
    """
    factory = _PERTURBATION_NAME_TO_DESCRIPTION.get(raw_perturbation_description["name"], PerturbationDescription)
    return factory(**raw_perturbation_description)

_DACITE_CONFIG = dacite.Config(type_hooks={PerturbationDescription: _deserialize_perturbation_description})

@dataclass(frozen=True)
class DisplayPrediction:
    """
    Captures a unit of evaluation for displaying in the web frontend.
    """

    # (instance_id, perturbation, train_trial_index) is a unique key for this prediction.
    instance_id: str
    """ID of the Instance"""

    perturbation: Optional[PerturbationDescription]
    """Description of the Perturbation that was applied"""

    train_trial_index: int
    """Which replication"""

    predicted_text: str
    """Prediction text"""

    truncated_predicted_text: Optional[str]
    """The truncated prediction text, if truncation is required by the Adapter method."""

    mapped_output: Optional[str]
    """The mapped output, if an output mapping exists and the prediction can be mapped"""

    reference_index: Optional[int]
    """Which reference of the instance we're evaluating (if any)"""

    stats: Dict[str, float]
    """Statistics computed from the predicted output"""

@dataclass(frozen=True)
class DisplayRequest:
    """
    Captures a unit of evaluation for displaying in the web frontend.
    """

    # (instance_id, perturbation, train_trial_index) is a unique key for this prediction.
    instance_id: str
    """ID of the Instance"""

    perturbation: Optional[PerturbationDescription]
    """Description of the Perturbation that was applied"""

    train_trial_index: int
    """Which replication"""

    request: Request
    """The actual Request to display in the web frontend.

    There can be multiple requests per trial. The displayed request should be the
    most relevant request e.g. the request for the chosen cohice for multiple choice questions."""

def _read_scenario_state(run_path: str) -> ScenarioState:
    scenario_state_path: str = os.path.join(run_path, "scenario_state.json")
    if not os.path.exists(scenario_state_path):
        raise ValueError(f"Could not load ScenarioState from {scenario_state_path}")
    with open(scenario_state_path) as f:
        raw_scenario_state = json.load(f)
        return dacite.from_dict(ScenarioState, raw_scenario_state, config=_DACITE_CONFIG)

def _read_per_instance_stats(run_path: str) -> List[PerInstanceStats]:
    per_instance_stats_path: str = os.path.join(run_path, "per_instance_stats.json")
    if not os.path.exists(per_instance_stats_path):
        raise ValueError(f"Could not load PerInstanceStats from {per_instance_stats_path}")
    with open(per_instance_stats_path) as f:
        raw_per_instance_stats = json.load(f)
        return [dacite.from_dict(PerInstanceStats, r, config=_DACITE_CONFIG) for r in raw_per_instance_stats]

def _truncate_predicted_text(
    predicted_text: str, request_state: RequestState, adapter_spec: AdapterSpec
) -> Optional[str]:
    method = adapter_spec.method
    prefix = ""
    if method in ADAPT_MULTIPLE_CHOICE_SEPARATE_METHODS:
        prefix = request_state.instance.input.text
    elif method == "language_modeling":
        if request_state.result is not None and request_state.result.completions:
            tokens = request_state.result.completions[0].tokens
            if tokens:
                first_token = tokens[0]
                if not first_token.top_logprobs:
                    prefix = first_token.text
    if prefix:
        predicted_text = predicted_text
        prefix = prefix
        if predicted_text.startswith(prefix):
            return predicted_text[len(prefix) :]
    return None

def _get_metric_names_for_group(run_group_name: str, schema: Schema) -> Set[str]:
    metric_groups_by_name = {metric_group.name: metric_group for metric_group in schema.metric_groups}
    run_groups_by_name = {run_group.name: run_group for run_group in schema.run_groups}

    result: Set[str] = set()
    run_group = run_groups_by_name.get(run_group_name)
    if run_group is None:
        return result

    for metric_group_name in run_group.metric_groups:
        metric_group = metric_groups_by_name.get(metric_group_name)
        if metric_group is None:
            continue
        for metric_name_matcher in metric_group.metrics:
            if metric_name_matcher.perturbation_name:
                continue
            result.add(metric_name_matcher.substitute(run_group.environment).name)
    return result

def _get_metric_names_for_groups(run_group_names: Iterable[str], schema: Schema) -> Set[str]:
    result: Set[str] = set()
    for run_group_name in run_group_names:
        result.update(_get_metric_names_for_group(run_group_name, schema))
    return result

@htrack(None)
def write_run_display_json(run_path: str, run_spec: RunSpec, schema: Schema):
    """Write run JSON files that are used by the web frontend.

    The derived JSON files that are used by the web frontend are much more compact than
    the source JSON files. This speeds up web frontend loading significantly.

    Reads:

    - ScenarioState from `scenario_state.json`
    - List[PerInstanceStats] from `per_instance_stats.json`

    Writes:

    - List[Instance] to `instances.json`
    - List[DisplayPrediction] to `display_predictions.json`
    - List[DisplayRequest] to `display_requests.json`
    """
    scenario_state = _read_scenario_state(run_path)
    per_instance_stats = _read_per_instance_stats(run_path)

    metric_names = _get_metric_names_for_groups(run_spec.groups, schema)

    if run_spec.adapter_spec.method in ADAPT_MULTIPLE_CHOICE_SEPARATE_METHODS:
        metric_names.add("predicted_index")

    stats_by_trial: Dict[Tuple[str, Optional[PerturbationDescription], int], Dict[str, float]] = defaultdict(dict)
    for original_stats in per_instance_stats:
        stats_dict: Dict[str, float] = {
            original_stat.name.name: original_stat.mean
            for original_stat in original_stats.stats
            if original_stat.name.name in metric_names and original_stat.mean is not None
        }

        key = (
            original_stats.instance_id,
            original_stats.perturbation,
            original_stats.train_trial_index,
        )
        stats_by_trial[key].update(stats_dict)

    instance_id_to_instance: Dict[Tuple[str, Optional[PerturbationDescription]], Instance] = OrderedDict()
    predictions: List[DisplayPrediction] = []
    requests: List[DisplayRequest] = []

    for request_state in scenario_state.request_states:
        assert request_state.instance.id is not None
        if request_state.result is None:
            continue

        # For the multiple_choice_separate_calibrated adapter method,
        # only keep the original prediction and discard the calibration prediction.
        if (
            run_spec.adapter_spec.method == ADAPT_MULTIPLE_CHOICE_SEPARATE_CALIBRATED
            and request_state.request_mode == "calibration"
        ):
            continue

        stats_key = (
            request_state.instance.id,
            request_state.instance.perturbation,
            request_state.train_trial_index,
        )
        trial_stats: Dict[str, float] = stats_by_trial[stats_key]
        # For the multiple_choice_separate_* adapter methods,
        # only keep the prediction for the chosen reference and discard the rest.
        if (
            run_spec.adapter_spec.method in ADAPT_MULTIPLE_CHOICE_SEPARATE_METHODS
            and "predicted_index" in trial_stats
            and trial_stats["predicted_index"] != request_state.reference_index
        ):
            continue

        predicted_text = (
            request_state.result.completions[0].text
            if request_state.result is not None and request_state.result.completions
            else ""
        )
        mapped_output = (
            request_state.output_mapping.get(predicted_text.strip()) if request_state.output_mapping else None
        )
        instance_id_to_instance[
            (request_state.instance.id, request_state.instance.perturbation)
        ] = request_state.instance
        predictions.append(
            DisplayPrediction(
                instance_id=request_state.instance.id,
                perturbation=request_state.instance.perturbation,
                train_trial_index=request_state.train_trial_index,
                predicted_text=predicted_text,
                truncated_predicted_text=_truncate_predicted_text(predicted_text, request_state, run_spec.adapter_spec),
                mapped_output=mapped_output,
                reference_index=request_state.reference_index,
                stats=trial_stats,
            )
        )
        requests.append(
            DisplayRequest(
                instance_id=request_state.instance.id,
                perturbation=request_state.instance.perturbation,
                train_trial_index=request_state.train_trial_index,
                request=request_state.request,
            )
        )

    write(
        os.path.join(run_path, "instances.json"),
        json.dumps(list(map(asdict_without_nones, instance_id_to_instance.values())), indent=2),
    )
    write(
        os.path.join(run_path, "display_predictions.json"),
        json.dumps(list(map(asdict_without_nones, predictions)), indent=2),
    )
    write(
        os.path.join(run_path, "display_requests.json"),
        json.dumps(list(map(asdict_without_nones, requests)), indent=2),
    )


import csv as csv
import networkx as net
import matplotlib.pyplot as plt
import itertools
import numpy as np
import pandas as pd
from sklearn.metrics import pairwise_distances
from scipy.spatial.distance import cosine
import SimRank as sim

def graph_generator(file_name):
    file = open(file_name, 'r')
    graphreader = csv.reader(file, delimiter = '\t')
    G = net.DiGraph()
    for row in graphreader:
        G.add_node(row[0])
    nodes = list(G.nodes())
    print(nodes)
    G.add_edge(nodes[5],nodes[6])
    G.add_edge(nodes[5],nodes[7])
    G.add_edge(nodes[5],nodes[8])
    G.add_edge(nodes[6],nodes[4])
    G.add_edge(nodes[7],nodes[4])
    G.add_edge(nodes[8],nodes[4])
    G.add_edge(nodes[4],nodes[0])
    G.add_edge(nodes[4],nodes[1])
    G.add_edge(nodes[4],nodes[2])
    G.add_edge(nodes[4],nodes[3])
    G.add_edge(nodes[0],nodes[6])
    G.add_edge(nodes[1],nodes[7])
    G.add_edge(nodes[2],nodes[8])
    G.add_edge(nodes[3],nodes[5])

    return G

graph = graph_generator('graph_simrank.csv')

pairwise_matrix = net.to_numpy_matrix(graph)

sim = net.simrank_similarity_numpy(graph)

df = pd.DataFrame(data=sim, index=graph.nodes)
df.columns = graph.nodes

pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)

#print(df)

pairwise_matrix = net.to_numpy_matrix(graph)

#print(pairwise_matrix)

#cosine_similarity = pairwise_distances(pairwise_matrix, metric="cosine")  #cosine similarity
#print("cosine similarity of student and AAU:" , cosine_similarity[4][5])
#print("cosine similarity of Professor A and AAU:" , cosine_similarity[6][5])

#   graph visualization

fig,ax= plt.subplots()
pos=net.kamada_kawai_layout(graph)
net.draw(graph,pos,with_labels = True)
net.draw_networkx_labels(graph,pos,font_color = 'white')
net.draw_networkx_edges(graph, pos, arrowstyle='->',
                              arrowsize=10, edge_color='green',
                                 width=2)

ax.set_facecolor('black')
fig.set_facecolor('black')
plt.show()


"""
Binary Search Tree (BST) is another tree datastructure like binary tree.
The main difference is the Node or sub-tree to the left is lesser then its parent node,
and the right sub-tree is greater.

Due to this property searching and insertion is easy.
"""

class Node:

    def __init__(self, val) -> None:
        self.left = None
        self.value = val
        self.right = None

# Search function to find a element in BST
def search(root, value):

    """
        this function returns true if ask node is present and false if it is absent,
        else it returns None
    """

    if root == None:
        return

    if root.value == value:
        return True

    if root.value > value:
        return search(root.left,value)
    else:
        return search(root.right,value)

    return False

# Insert function to insert a new node in BST
def insert(root, value):

    if root == None:
        return Node(value)

    if root.value == value:
        return root

    else:
        if root.value < value:
            root = insert(root.right, value)
        else:
            root = insert(root.left, value)

    return root

# Function to print the BST nodes in inorder
def inorder(root):
    if root:
        inorder(root.left)
        print(root.value,end = " ")
        inorder(root.right)

if __name__ == "__main__":

    """
    Making a simple BST

        10
        /\
       5  15

    """

    root = Node(10)
    root.right = Node(15)
    root.left = Node(5)

    inorder(root)
    print()
    insert(root, 3)
    insert(root, 6)
    insert(root, 2)

    inorder(root)
    print()
    print(search(root, 500))

"""
# Output

    5 10 15
    5 10 15
    None
"""


# QuickPassTasks 15

from nltk.tokenize import RegexpTokenizer

# path = 'sky.txt'
path = input()
tokenizer = RegexpTokenizer("[а-я]+(?:-[a-z]+)*")
para = ''
with open(path, encoding="utf8") as f:
    file = f.readlines()

for line in file:
    line = line.lower().rstrip('\n')
    para += line + ' '

text_without_trash = tokenizer.tokenize(para)
d = {}
for w in text_without_trash:
    if w not in d:
        d[w] = 0
    d[w] += 1
d = sorted(d.items(), key = lambda x : -x[1])
i = min(10, len(d))
for j in range(i):
    print(d[j][0], d[j][1])


#!/usr/bin/env python
import rospy
from random import *
from ros_tutorials.msg import new_msg

if __name__ == "__main__":
    rospy.init_node("publisher_node_v2", anonymous=True)
    pub = rospy.Publisher('tick_tock', new_msg, queue_size=5)
    rate = rospy.Rate(2)

    while not rospy.is_shutdown():
        msg = new_msg()
        msg.intarray = [int(random()*20), int(random()*30), int(random()*40)]
        msg.floatarray = [random(), random(), random()]
        pub.publish(msg)
        rate.sleep()


# OPENCORE - ADD
from shared.database.common import *

class NotificationUser(Base):
    """

    """

    __tablename__ = 'notification_user'

    notification_id = Column(Integer, ForeignKey('notification.id'), primary_key=True)
    notification = relationship("Notification", foreign_keys=[notification_id])

    user_id = Column(Integer, ForeignKey('userbase.id'), primary_key=True)
    user = relationship("User",  foreign_keys=[user_id])

    is_read = Column(Boolean, default=False)

    time_created = Column(DateTime, default=None, nullable=True)

    @staticmethod
    def new(session=None,
            add_to_session=False,
            flush_session=False,
            notification_id=None,
            user_id=None,
            is_read=False):

        notification = NotificationUser(
            notification_id=notification_id,
            user_id=user_id,
            is_read=is_read)
        if add_to_session:
            session.add(notification)
        if flush_session:
            session.flush()
        return notification

    @staticmethod
    def get_by_id(session, notification_id=None, user_id=None):
        return session.query(NotificationUser).filter(
            NotificationUser.notification_id == notification_id,
            NotificationUser.user_id == user_id
        ).first()


import os

from django.contrib import messages
from django.http import request
from django.shortcuts import render, redirect
from .forms import *
from .models import *

# Create your views here.

def DashboardView(request):
    dams = ManageDam.objects.all()
    return render(request, 'home.html', {"dams": dams})

def DamView(request):
    if request.method == "POST":
        form = DamForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/damentry")
    else:
        form = DamForm()
    return render(request, "fishfarm/damindex.html", {"form": form})

def ShowViewDam(request):
    dams = ManageDam.objects.all()
    return render(request, "fishfarm/damshow.html", {"dams": dams})

def EditViewDam(request, id):
    dam = ManageDam.objects.get(id=id)
    return render(request, "fishfarm/damedit.html", {"dam": dam})

def UpdateViewDam(request, id):
    dam = ManageDam.objects.get(id=id)
    form = DamForm(request.POST, instance=dam)
    if form.is_valid():
        form.save()
        return redirect("/damentry")
    return render(request, "fishfarm/damedit.html", {"dam": dam})

def DestroyViewDam(request, id):
    dam = ManageDam.objects.get(id=id)
    dam.delete()
    return redirect("/damentry")

# staff
def StaffAdd(request):
    if request.method=="POST":
        form=ManageStaff()
        form.staffid=request.POST.get('staffid')
        form.staffname=request.POST.get('staffname')
        form.staffEmail=request.POST.get('staffEmail')

        if len(request.FILES)!=0:
            form.staffImage=request.FILES['staffImage']

        form.save()
        messages.success(request,"data added")
        return redirect('/staffshow')

    return render(request,'fishfarm/staffadd.html')

def StaffView(request):
    staffs = ManageStaff.objects.all()
    return render(request, "fishfarm/staffshow.html", {"staffs": staffs})

def EditViewStaff(request, pk):
    staff = ManageStaff.objects.get(id=pk)

    if request.method == "POST":
        if len(request.FILES) != 0:
            if len(staff.staffImage) > 0:
                os.remove(staff.staffImage.path)
                staff.staffImage = request.FILES['staffImage']
                staff.staffid = request.POST.get('staffid')
                staff.staffname = request.POST.get('staffname')
                staff.staffEmail = request.POST.get('staffEmail')
                staff.save()
        messages.success(request,"Staff section updated successfully")
        return redirect('/staffshow')
    else:
        return render(request, "fishfarm/staffedit.html", {"staff": staff})

'''
def UpdateViewStaff(request, id):
    staff = ManageStaff.objects.get(id=id)
    form = StaffForm(request.POST, instance=staff)
    if form.is_valid():
        form.save()
        return redirect("/staffshow")
    return render(request, "fishfarm/staffedit.html", {"staff": staff})
    '''

def DestroyViewStaff(request, pk):
    staff = ManageStaff.objects.get(id=pk)
    if len(staff.staffImage) > 0:
        os.remove(staff.staffImage.path)
    staff.delete()
    messages.success(request,"Staff deleted")
    return redirect("/staffshow")

# Fish
def FishAdd(request):
    if request.method == "POST":
        form = FishForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/fishshow")
    else:
        form = FishForm()
    return render(request, "fishfarm/fishadd.html", {"form": form})

def ViewFish(request):
    fishs = ManageFish.objects.all()
    return render(request, "fishfarm/fishshow.html", {"fishs": fishs})

def EditViewFish(request, id):
    fish = ManageFish.objects.get(id=id)
    return render(request, "fishfarm/fishedit.html", {"fish": fish})

def UpdateViewFish(request, id):
    fish = ManageFish.objects.get(id=id)
    form = FishForm(request.POST, instance=fish)
    if form.is_valid():
        form.save()
        return redirect("/fishshow")
    return render(request, "fishfarm/fishedit.html", {"fish": fish})

def DestroyViewFish(request, id):
    dam = ManageFish.objects.get(id=id)
    dam.delete()
    return redirect("/fishshow")

# Department
def DepartmentAdd(request):
    if request.method == "POST":
        form = DepartmentForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/departmentshow")
    else:
        form = DepartmentForm()
    return render(request, "fishfarm/departmentadd.html", {"form": form})

def ViewDepartment(request):
    departments = ManageDepartment.objects.all()
    return render(request, "fishfarm/departmentshow.html", {"departments": departments})

def EditViewDepartment(request, id):
    department = ManageDepartment.objects.get(id=id)
    return render(request, "fishfarm/departmentedit.html", {"department": department})

def UpdateViewDepartment(request, id):
    department = ManageDepartment.objects.get(id=id)
    form = DepartmentForm(request.POST, instance=department)
    if form.is_valid():
        form.save()
        return redirect("/departmentshow")
    return render(request, "fishfarm/departmentedit.html", {"department": department})

def DestroyViewDepartment(request, id):
    department = ManageDepartment.objects.get(id=id)
    department.delete()
    return redirect("/departmentshow")

# Sales

def SalesAdd(request):
    if request.method == "POST":
        form = SalesForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/salesshow")
    else:
        form = SalesForm()
    return render(request, "fishfarm/salesadd.html", {"form": form})

def ViewSales(request):
    sales = ManageSales.objects.all()
    return render(request, "fishfarm/salesshow.html", {"sales": sales})

def EditViewSales(request, id):
    sale = ManageSales.objects.get(id=id)
    return render(request, "fishfarm/salesedit.html", {"sale": sale})

def UpdateViewSales(request, id):
    sale = ManageSales.objects.get(id=id)
    form = SalesForm(request.POST, instance=sale)
    if form.is_valid():
        form.save()
        return redirect("/salesshow")
    return render(request, "fishfarm/salesedit.html", {"sale": sale})

def DestroyViewSales(request, id):
    sale = ManageSales.objects.get(id=id)
    sale.delete()
    return redirect("/salesshow")

# Credit

def CreditAdd(request):
    if request.method == "POST":
        form = CreditForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/creditshow")
    else:
        form = CreditForm()
    return render(request, "fishfarm/creditadd.html", {"form": form})

def ViewCredit(request):
    credits = ManageCredit.objects.all()
    return render(request, "fishfarm/creditshow.html", {"credits": credits})

def EditViewCredit(request, id):
    credit = ManageCredit.objects.get(id=id)
    return render(request, "fishfarm/creditedit.html", {"credit": credit})

def UpdateViewCredit(request, id):
    credit = ManageCredit.objects.get(id=id)
    form = CreditForm(request.POST, instance=credit)
    if form.is_valid():
        form.save()
        return redirect("/creditshow")
    return render(request, "fishfarm/creditedit.html", {"credit": credit})

def DestroyViewCredit(request, id):
    credit = ManageCredit.objects.get(id=id)
    credit.delete()
    return redirect("/creditshow")


#!/usr/bin/env python3
import cgi
import cgitb
import json
import numpy as np
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Model
from tensorflow.keras.applications.inception_v3 import InceptionV3, preprocess_input
from pickle import load
from tensorflow.keras.preprocessing.image import load_img, img_to_array
import requests
from io import BytesIO
from flask import Flask, request, jsonify
from flask_cors import CORS
import os
import keras
import keras.utils as image
from keras.preprocessing.text import tokenizer_from_json
from keras.utils import pad_sequences
import matplotlib.pyplot as plt
import tensorflow as tf
import string
import requests
from PIL import Image
from io import BytesIO
import ssl
ssl._create_default_https_context = ssl._create_unverified_context

# Enable detailed error messages
cgitb.enable()

# Load the trained model to classify sign
base_model = InceptionV3(
    weights='inception_v3_weights_tf_dim_ordering_tf_kernels.h5')
vgg_model = Model(base_model.input, base_model.layers[-2].output)

def preprocess_img_from_url(url):
    # Inception V3 expects images in 299x299 size
    response = requests.get(url, verify=False)
    img = load_img(BytesIO(response.content), target_size=(299, 299))
    x = img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    return x

def encode(image):
    image = preprocess_img_from_url(image)
    vec = vgg_model.predict(image)
    vec = np.reshape(vec, (vec.shape[1]))
    return vec

def greedy_search(pic, wordtoix, max_length):
    # Your implementation for greedy search goes here
    start = 'startseq'
    for i in range(max_length):
        seq = [wordtoix[word] for word in start.split() if word in wordtoix]
        seq = pad_sequences([seq], maxlen=max_length)
        yhat = model.predict([pic, seq])
        yhat = np.argmax(yhat)
        word = ixtoword[yhat]
        start += ' ' + word
        if word == 'endseq':
            break
    final = start.split()
    final = final[1:-1]
    final = ' '.join(final)
    return final

# Load the model (new-model-1.h5) for generating captions
model = load_model('new-model-1.h5')

# Load wordtoix and ixtoword from pickle files
with open('wordtoix.pkl', 'rb') as f:
    wordtoix = load(f)

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

############## Semantic model ################

def feature_extractions(directory, image_url):
    model = tf.keras.applications.vgg16.VGG16()
    model = keras.models.Model(inputs=model.input, outputs=model.layers[-2].output)
    url= image_url
    image_response = requests.get(url)
    img = Image.open(BytesIO(image_response.content))
    img = img.resize((224, 224))  # Resize the image to match the VGG16 input size

    arr = keras.utils.img_to_array(img, dtype=np.float32)
    arr = arr.reshape((1, arr.shape[0], arr.shape[1], arr.shape[2]))
    arr = keras.applications.vgg16.preprocess_input(arr)

    features = model.predict(arr, verbose=0)
    return features
def sample_caption(model, tokenizer, max_length, vocab_size, feature):
    caption = "<startseq>"
    while 1:
        encoded = tokenizer.texts_to_sequences([caption])[0]
        padded = pad_sequences([encoded], maxlen=max_length, padding='pre')[0]
        padded = padded.reshape((1, max_length))
        pred_Y = model.predict([feature, padded])[0,-1,:]
        next_word = tokenizer.index_word[pred_Y.argmax()]
        caption = caption + ' ' + next_word
        if next_word == '<endseq>' or len(caption.split()) >= max_length:
            break
    caption = caption.replace('<startseq> ', '')
    caption = caption.replace(' <endseq>', '')
    return(caption)

def funSemantic(image_url):
    with open('./semantic/File1.json', 'r') as f:
        tokenizer_json = json.load(f)
    tokenizer = tokenizer_from_json(tokenizer_json)
    model = keras.models.load_model("./semantic/File2.h5")
    vocab_size = tokenizer.num_words
    max_length = 37
    img = image_url
    features = feature_extractions("./semantic", img)
    filename = "img1.jpg"  # This should be the filename or identifier of the image
    # plt.figure()
    caption = sample_caption(model, tokenizer, max_length, vocab_size, features)
    img = tf.keras.utils.load_img("./semantic/" + filename)
    return(caption)

############## End Semantic model ################

# Create a Flask app
app = Flask(__name__)
CORS(app, supports_credentials=True)

# Define your Flask route to process the image

@app.route('/', methods=['POST'])
def process_image_route():
    data = request.get_json()
    image_url = data["image_url"]
    enc = encode(image_url)
    image = enc.reshape(1, 2048)

    # Define max_length (adjust this value based on your sequence length)
    max_length = 74

    # Example usage for generating captions using greedy search
    pred = greedy_search(image, wordtoix, max_length)

    semantic_caption = funSemantic(image_url)

    # Create a dictionary to store the caption
    result = {"caption": pred,"semantic": semantic_caption}
    # Return the JSON response
    return jsonify(result)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)


from django.contrib import admin
from django.contrib.auth.models import Group
from .models import *
# Register your models here.
admin.site.site_header = "Trading Robot Admin v1.0"
admin.site.register(StockExchange)
admin.site.unregister(Group)

class StockSymbolTableAdmin(admin.ModelAdmin):
    list_display = ('stock_name', 'stock_symbols', 'get_stock_exchanges')
    fields = (
        'stock_name',
        'stock_symbols',
        'stock_exchange',
        )

admin.site.register(StockSymbolTable, StockSymbolTableAdmin)

class PlaceOrderAdmin(admin.ModelAdmin):
    list_display = ('order_id','date_time','exchange_symbol')

admin.site.register(PlaceOrder, PlaceOrderAdmin)


import sys
import csv
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder

def remove_duplicates(values):
    output = []
    seen = set()
    for value in values:
        # If value has not been encountered yet,
        # ... add it to both list and set.
        if value not in seen:
            output.append(value)
            seen.add(value)
    return output

#features = ['origin', 'destination', 'oil_price', 'quarter', 'year', 'flight_fare']
features = ['origin', 'destination', 'oil_price', 'flight_fare']

features2 = ['origin', 'destination', 'oil_price']
#featuresToDrop = ['origin', 'destination','distance', 'quarter', 'origin_population', 'destination_population' ,'passengers', 'flights' ,'seats', 'flight_fare']
target = ['flight_fare']
dataset = 'DS1.csv'
theData = pd.read_csv(dataset, usecols=features)

df = pd.DataFrame(theData)
#df_ = pd.DataFrame(mydata)

origin_df = df['origin']
origin_arr = np.array(np.array(origin_df))
print(origin_arr)
print(type(origin_arr))
# integer encode
label_encoder = LabelEncoder()
integer_encoded = label_encoder.fit_transform(origin_arr)
#print(integer_encoded)
# binary encode
onehot_encoder = OneHotEncoder(sparse=False)
integer_encoded = integer_encoded.reshape(len(integer_encoded), 1)
onehot_encoded = onehot_encoder.fit_transform(integer_encoded)
print(onehot_encoded)
print(type(onehot_encoded))

with open('origin.csv', 'a') as outcsv:
    writer = csv.writer(outcsv)
    writer.writerow(["Origin", "Origin_Encoded"])

with open('destination.csv', 'a') as outcsv:
    writer = csv.writer(outcsv)
    writer.writerow(["Destination", "Destination_Encoded"])

origin_encoded_list = []
for origin_abbr, origin_encoded in zip(origin_arr,onehot_encoded):
    #print("{} --> {}".format(origin_abbr,origin_encoded))
    #origin_encoded_list.append([origin_abbr,origin_encoded])
    #origin_encoded = origin_encoded.replace('\n','')
    with open('origin.csv', 'a') as file:
        writer = csv.writer(file, delimiter = ",")
        writer.writerow([origin_abbr,origin_encoded])

#===================================

destination_df = df['destination']
destination_arr = np.array(remove_duplicates(np.array(destination_df)))
print(destination_arr)
print(type(destination_arr))
# integer encode
label_encoder = LabelEncoder()
integer_encoded = label_encoder.fit_transform(destination_arr)
#print(integer_encoded)
# binary encode
onehot_encoder = OneHotEncoder(sparse=False)
integer_encoded = integer_encoded.reshape(len(integer_encoded), 1)
onehot_encoded = onehot_encoder.fit_transform(integer_encoded)
print(onehot_encoded)
print(type(onehot_encoded))

origin_encoded_list = []
for origin_abbr, origin_encoded in zip(destination_arr,onehot_encoded):
    #print("{} --> {}".format(origin_abbr,origin_encoded))
    #origin_encoded_list.append([origin_abbr,origin_encoded])
    with open('destination.csv', 'a') as file:
        writer = csv.writer(file, delimiter = ",")
        writer.writerow([origin_abbr,origin_encoded])

#print(origin_encoded_list)
#print(df)


# F(n) = F(n-1) + F(n-2)

class Solution:
    def nthFibonacci (ob, n):
        dp = [0] * (n+1)
        dp[0] = 0
        dp[1] = 1
        mod = 1000000007
        for i in range(2,n+1):
            dp[i] = (dp[i-1] % mod + dp[i-2] % mod) % mod

        return dp[n]


import cv2
import numpy as np

cap = cv2.VideoCapture(0) # 0 bizim default kameramız.

#şablonu yani tamplate aranacak resimi okuduk
template = cv2.imread("python.png",0)

# şablonun boyutlarını aldık
h , w = template.shape

while True:

    ret , frame = cap.read()

    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

    #TM_CCOEFF_NORMED template matching algoritması kullanarak şablon işlemeyi yaptık
    res = cv2.matchTemplate(gray,template,cv2.TM_CCOEFF_NORMED)
    threshold = 0.8
    loc = np.where( res >= threshold)

    for pt in zip(*loc[::-1]):
        cv2.rectangle(frame,pt,(pt[0] + w , pt[1] + h) , (0,0,255),2)

    cv2.imshow("Webcam",frame)

    if cv2.waitKey(1) & 0xFF == ord("q") :
        break

cap.release()
cv2.destroyAllWindows()


from math import *

N = 5
senox = 0
x = 1.2
n = 0

print("Este programa calcula o seno de 1.2 usando a série de Taylor \n")
print("Para n = 5 \n")

for n in range(n,N + 1):             #loop para o somatório, variando n de 0 até 5, em passos de 1

   fat = 1
   num = (-1)**n                     #numerador
   den = (2*n + 1)                   #deniminador

   for d in range(den,0,-1):         #loop para o fatorial do denominador, variando dele mesmo, para cada n, até 1, em passos de -1

       fat = fat*d                   #calculo do fatorial

   senox = senox + (num*x**den)/fat  #somatorio da série

print("O seno de 1.2 é aproximadamente igual a %.8f \n" %(senox))
print(sin(1.2))                      #valor de sin(1.2) da bibliotéca math


'''Defines the command line interface for ALPALFA.'''

import argparse
from .alpafa import Lexicon
from .parse import parse_file, ParserError

def set_args():
    '''Sets command line parameters, and runs ALPAFA.'''

    parser = argparse.ArgumentParser(prog='alpafa',
                                     description='Applies the algorithm from AAFP to a correctly \
                                     formatted input file.')
    parser.add_argument('input_file', help='correctly formatted UTF-8 input file')
    parser.add_argument('output_file', help='name of file to output')

    parser.add_argument('--no_uf', dest='uf', action='store_false',
                        help='do not implement unvalued features')
    parser.add_argument('--no_cselect', dest='cselect', action='store_false',
                        help='do not implement c-selection')
    parser.add_argument('--log', dest='log', action='store_true',
                        help='include a log of algorithm operations')
    parser.add_argument('--categories', dest='cats', action='store_true',
                        help='list all categories before heads')
    parser.add_argument('--dependents', dest='dependents', action='store_true',
                        help='list all dependent features below their relevant categories (implies \
                        --categories)')

    args = parser.parse_args()
    if args.dependents:
        args.cats = True

    return (args.input_file, args.output_file, args.uf, args.cselect, args.log, args.cats,
           args.dependents)

def run_alpafa(input_file, output_file, uf, cselect, log, cats, dependents):
    '''Parse an input file, and apply ALPAFA to its contents, printing the output to a specified
    file.
    '''

    try:
        prominence, heads = parse_file(input_file)
    except FileNotFoundError as e:
        print('alpafa: input failure: ' + str(e)[10:])
        return
    except ParserError as e:
        print('alpafa: parsing failure: {}'.format(e))
        return
    lex = Lexicon(prominence, heads, uf, cselect)
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(lex.display(log, cats, dependents))
    print(lex.stats())

def main():
    run_alpafa(*set_args())


# comando para converter arquivos UI criados pelo UI Designer para um arquivo .py:
# pyside2-uic arquivo.ui -o ui_arquivo.py (ui_arquivo.py - esse ui é somente uma referência
# de nome pra indicar a origem  do arquivo, dizendo que esse arquivo .py foi convertido de um arquivo .ui)

from PySide2.QtCore import QCoreApplication
from PySide2.QtGui import QIcon, QIntValidator
from PySide2.QtCore import QThread
from PySide2.QtWidgets import QApplication, QMainWindow, QSystemTrayIcon, QMenu, QAction, QDialog, QFileDialog, QMessageBox
from ui_janela_principal import Ui_MainWindow
from ui_janela_log import Ui_janela_log
from datetime import datetime
import socket, time, pygame, subprocess, sys, os, tempfile, atexit
from version_uptate import verifica_atualizacao
import rede

# Pega o diretório atual da execução do arquivo atual e joga o path dele na variável diretorio_atual
diretorio_atual = os.path.dirname(os.path.abspath(__file__))

# Cria um arquivo na inicialização do programa, para que, se tentar abrir novamente outra instância da mesma aplicação
# a pessoa não consiga. No fim do programa, quando o programa é fechado, o arquivo é excluido
lock_file = diretorio_atual + "/my_app.lock"

# Verificando a existência do arquivo acima
try:
    lock_fd = os.open(lock_file, os.O_CREAT | os.O_EXCL | os.O_RDWR)
# Tratando o erro e dando exit do sistema se o arquivo existir
except Exception as e:
    print(f"Erro ao abrir o arquivo de bloqueio: {str(e)}")
    sys.exit(1)

# Função chamada pelo método atexit.register, e é executado na saída do programa, quando é fechado. Ele exclui o arquivo
# criado acima (my_app.lock).
def encerrar_programa():
    os.close(lock_fd)
    os.unlink(lock_file)

# O método abaixo teve que ser importado, e permite que no fim do programa seja executado o que estiver entre parenteses
atexit.register(encerrar_programa)

# Variáveis que rodam a função obter_endereco_ip_por_nome_interface do arquivo rede.py, que retorna dois valores, o
# primeiro é o endereço de ip da interface ativa e o segundo é o nome da interface ativa, armazenando em variáveis.
endereco_interface_ativa, nome_interface_ativa = rede.obter_endereco_ip_por_nome_interface()
print(endereco_interface_ativa, nome_interface_ativa)

# ____________________________________ Sessão da classe da  threads ____________________________________
# Classe que trabalha com Thread, que é a execução de funções sem travar o programa. Se quiser que uma função seja
# executada sem travar o sistema, deve-se criar uma isntância dessa classe para rodar a função.
class NossaThread(QThread):
    def __init__(self):
        QThread.__init__(self)
        self.func = None

    def __del__(self):
        self.wait()

    def set_function(self, func, param=None, param2=None):
        self.func = func
        self.param = param
        self.param2 = param2

    def run(self):
        if self.param == None:
            # print("Sem parâmetro!")
            if self.func:
                self.func()
        elif self.param != None and self.param2 == None:
            if self.func:
                # print("Com parâmetro!")
                self.func(self.param)
        else:
            if self.param != None and self.param2 != None:
                self.func(self.param, self.param2)

# ____________________________________ Sessão da janela principal ____________________________________
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.setWindowTitle("Cadê minha internet?")
        self.setWindowIcon(QIcon(diretorio_atual + "\images\icon.png"))
        self.setFixedSize(782, 637)
        self.busca_informacoes_rede()
        self.definindo_sons()
        self.chamada_da_NossaThread()
        self.chamada_da_NossaThread3()

        # Criação da lista para o log
        self.lista_log_conexao = []
        self.lista_log_ping = []

        self.ln_quantidade_ping.setValidator(QIntValidator())
        self.ln_quantidade_ping.textChanged.connect(self.teste_valor_quantidade_ping)

        # Botão pingar
        self.btn_pingar.clicked.connect(self.test_site_ip_valido_ping)

        # Botão abrir pagina de logs
        self.btn_abrir_janela_logs_conexao.clicked.connect(self.mostrar_janela_log_conexao)
        self.btn_abrir_janela_logs_ping.clicked.connect(self.mostrar_janela_log_ping)

        # Botão DNS do google
        self.btn_dns_google.clicked.connect(self.alterar_dns_google)
        self.btn_dns_auto.clicked.connect(self.alterar_dns_dhcp)

        # ____________________________________ Sessão do tray do windows ____________________________________
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon(diretorio_atual + "\images\icon.png"))
        self.tray_icon.setToolTip("Cadê minha internet?")

        self.tray_menu = QMenu()
        self.show_action = QAction("Abrir", self)
        self.quit_action = QAction("Sair", self)

        self.show_action.triggered.connect(self.show_or_restore_window)
        self.quit_action.triggered.connect(self.quit_application)

        self.tray_menu.addAction(self.show_action)
        self.tray_menu.addAction(self.quit_action)

        self.tray_icon.setContextMenu(self.tray_menu)
        self.tray_icon.activated.connect(self.tray_activated)
        self.tray_icon.show()

    def show_or_restore_window(self):
        if self.isMinimized() or not self.isVisible():
            self.showNormal()
            self.activateWindow()
        else:
            self.hide()

    def quit_application(self):
        QApplication.quit()

    def closeEvent(self, event):
        event.ignore()
        self.hide()
        self.tray_icon.show()

    def tray_activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.show_or_restore_window()

    def show_window(self):
        self.show()
    # Aqui termina a série de comandos do Tray

    # ____________________________________ Sessão de threads ____________________________________
    # Função para a chamada do bloco que iniciará uma instância da classe NossaThread, responsável por executar uma
    # função em looping e ainda sim mostrar a tela incial do programa (mainWindow)
    def chamada_da_NossaThread(self):
        ##########################################################
        self.bloco = NossaThread()                               #
        self.bloco.set_function(self.check_internet_connection)  #
        self.bloco.start()                                       #
        ##########################################################

    # Função para a chamada do bloco que iniciará uma instância da classe NossaThread, responsável por executar uma
    # função que capta o ping e o exibe na label)
    def chamada_da_NossaThread2(self):
        #############################################################################################
        self.bloco2 = NossaThread()                                                                 #
        self.bloco2.set_function(self.test_verbose_ping, self.hostname, self.quantidade_de_ping)    #
        self.bloco2.start()                                                                         #
        #############################################################################################

    # Função para a chamada do bloco que iniciará uma instância da classe NossaThread, responsável por executar uma
    # função que capta o ping pela primeira vez ao iniciar o programa
    def chamada_da_NossaThread3(self):
        #############################################################################################
        self.hostname = "www.google.com.br"                                                         #
        self.quantidade_de_ping = 4                                                                 #
        self.bloco3 = NossaThread()                                                                 #
        self.bloco3.set_function(self.test_verbose_ping, self.hostname, self.quantidade_de_ping)    #
        self.bloco3.start()                                                                         #
        #############################################################################################

    # ____________________________________ Sessão de funções principais ____________________________________
    # Função que coleta informações sobre a rede do usuário e mostra na mainWindow
    def busca_informacoes_rede(self):
        # Executa o comando ipconfig /all no Windows

        result = subprocess.run(["ipconfig", "/all"], capture_output=True, text=True)

        # Se não obter erro no retorno, cria a lista output_lines, onde cada posição vai receber uma linha do retorno
        if result.returncode == 0:
            output_lines = result.stdout.split('\n')

            # Cria as variáves para capturar as linhas referentes às posições dos DNS no retorno que está na lista
            linha_dns1 = output_lines[25]
            linha_dns2 = output_lines[26]

            # Cria mais duas listas, e separa a linha tudo que vier depois dos ":" fica na posição 1 da nova lista.
            parts1 = linha_dns1.split(':', 1)
            parts2 = linha_dns2.split(':', 1)

            # Verifica se o tamanho da primeira lista (parts1) tem duas posições
            if len(parts1) >= 2:
                dns1 = parts1[1].strip()
                dns2 = parts2[0].strip()

                if dns1 == "8.8.8.8" and dns2 == "8.8.4.4":
                    self.btn_dns_google.setDisabled(True)

            # Seta os labels da mainWindows com as informações referentes ao DNS1 e DNS2, respectivamente
            html_text1 = f"
{dns1}
"
            self.lb_dns1_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))

            html_text1 = f"
{dns2}
"
            self.lb_dns2_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))

        # Executa o comando ipconfig no Windows
        result = subprocess.run(["ipconfig"], capture_output=True, text=True)

        # Verifica o resultado
        if result.returncode == 0:
            output_lines = result.stdout.split('\n')

            # Verifica se a lista tem pelo menos 11 linhas
            if len(output_lines) >= 11:
                linha_ipv6 = output_lines[7]
                linha_ip = output_lines[8]
                linha_mascara = output_lines[9]
                linha_gateway = output_lines[10]

                # Divide apenas no primeiro ":"
                parts = linha_ipv6.split(':', 1)
                parts2 = linha_ip.split(':', 1)
                parts3 = linha_mascara.split(':', 1)
                parts4 = linha_gateway.split(':', 1)

                # Verifica se a linha foi dividida em pelo menos 2 partes
                if len(parts) >= 2:
                    # Remove espaços extras e seta a variável ipv6 com a segunda posição da lista parts
                    ipv6 = parts[1].strip()
                else:
                    ipv6 = ""

                if len(parts2) >= 2:
                    ip = parts2[1].strip()
                else:
                    ip = ""

                if len(parts3) >= 2:
                    mascara = parts3[1].strip()
                else:
                    mascara = ""

                if len(parts4) >= 2:
                    gateway = parts4[1].strip()
                else:
                    gateway = ""

                # Seta os labels da mainWindows com os respectivos valores de ipv6, ip, mascara e gateway
                html_text1 = f"
{ipv6}
"
                self.lb_ipv6_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))

                html_text = f"
{ip}
"
                self.lb_ip_resultado.setText(QCoreApplication.translate("MainWindow", html_text, None))

                html_text = f"
{mascara}
"
                self.lb_mascara_resultado.setText(QCoreApplication.translate("MainWindow", html_text, None))

                html_text = f"
{gateway}
"
                self.lb_gateway_resultado.setText(QCoreApplication.translate("MainWindow", html_text, None))

            return dns1, dns2

    # Função que checa se a internet está funcionando em looping e em cado de alguma mudança, ele avisa por áudio.
    def check_internet_connection(self):
        previous_status = None
        num_failures = 0

        while True:
            try:
                socket.create_connection(("www.google.com", 80))
                current_status = "Online"
            except OSError:
                current_status = "Offline"

            if previous_status is None:
                if current_status == "Online":
                    self.altera_img_internet_ok()
                    # print("Status da Internet:", current_status)
                else:
                    self.altera_img_internet_nao_ok()
                    # print("Status da Internet:", current_status)
            elif previous_status != current_status:
                if current_status == "Online":
                    self.altera_img_internet_voltou()
                    # print("A Internet voltou!")
                else:
                    if num_failures < 1:
                        num_failures += 1
                        self.altera_img_internet_caiu()
                        # print("A Internet caiu.")
                    elif num_failures >= 1:
                        self.altera_img_internet_caiu_dinovo()
                        # print("A Internet caiu OUTRA VEZ.")

            previous_status = current_status
            time.sleep(5)

    # Função que pega o site e a quantidade de pings passada atraves da função da thread executada, e gera os
    # resultados dos pings
    def test_verbose_ping(self, hostname, quantidade_de_ping):
        self.bloquear_btnPing_lnPing()

        temp_file = tempfile.NamedTemporaryFile(delete=False)

        try:
            subprocess.run(["ping", "-n", str(quantidade_de_ping), hostname], stdout=temp_file)
        except Exception as e:
            print(f"Failed to perform verbose ping: {e}")
        finally:
            temp_file.close()

        with open(temp_file.name, 'r') as file:
            captured_output = file.read()

        os.unlink(temp_file.name)

        # Convertendo bytes para str usando decode()
        captured_output_str = str(captured_output)

        # Separar as linhas relevantes
        lines = captured_output_str.splitlines()

        # Filtrar as linhas que contêm "Resposta"
        response_lines = [line for line in lines if "Resposta" in line]

        # Juntar as linhas filtradas novamente em uma string
        formatted_output = '\n'.join(response_lines)
        self.adiciona_ao_log_ping(formatted_output, str(self.ln_entrada_ping.text()))
        self.lbl_log_ping.setText(formatted_output)

        # Roda a função de liberar as linhas após a execução da função de ping
        self.liberar_lnPing()

        # Limpa o campo ln_quantidade_ping após a execução da função de ping
        self.ln_quantidade_ping.setText("")

        # Após qualquer inserção de texto ou números nos campos abaixo, irá chamar a função para testar se pode ou não
        # liberar o botão de pingar. Só irá liberar se os dois campos estiverem preenchidos.
        self.ln_entrada_ping.textChanged.connect(self.bloquear_botao_ping)
        self.ln_quantidade_ping.textChanged.connect(self.bloquear_botao_ping)

        # Retorno da funçao
        return formatted_output

    # Seta os sons para cada tipo de aviso do programa
    def definindo_sons(self):
        # inicia a entrada de sons no programa
        pygame.mixer.init()
        self.sons = pygame.mixer.Channel(7)
        self.sons.set_volume(2.0)

        self.som_internet_ok = pygame.mixer.Sound(diretorio_atual + "\sounds\internet_ok_1.mp3")
        self.som_internet_sem_internet = pygame.mixer.Sound(diretorio_atual + "\sounds\sem_internet_1.mp3")
        self.som_internet_caiu = pygame.mixer.Sound(diretorio_atual + "\sounds\caiu_internet_1.mp3")
        self.som_internet_voltou = pygame.mixer.Sound(diretorio_atual + "\sounds\internet_voltou.mp3")
        self.som_internet_caiu_dinovo = pygame.mixer.Sound(diretorio_atual + "\sounds\sem_internet_dinovo_1.mp3")

    # Testa se a quantidade inserida no campo ln_quantidade_ping é entre 1 e 19. Se não for, ele automáticamente
    # preenche com um dos valores, ou o mais alto ou o mais baixo
    def teste_valor_quantidade_ping(self, text):
        valor_minimo = 1
        valor_maximo = 19

        try:
            valor = int(text)
            if valor < valor_minimo:
                self.ln_quantidade_ping.setText(str(valor_minimo))
            elif valor > valor_maximo:
                self.ln_quantidade_ping.setText(str(valor_maximo))
        except ValueError:
            pass

    # Testa se a o site digitano no campo do ping é válido
    def test_site_ip_valido_ping(self):
        self.hostname = self.ln_entrada_ping.text()  #
        self.quantidade_de_ping = self.ln_quantidade_ping.text()

        try:
            # Verifica se é um IP válido
            socket.inet_aton(self.hostname)

            # Realize o teste de ping aqui
            self.chamada_da_NossaThread2()
        except socket.error:
            # Se não for um IP válido, tente resolver como um nome de domínio
            try:
                socket.gethostbyname(self.hostname)

                # Realize o teste de ping aqui
                self.chamada_da_NossaThread2()
            except socket.gaierror:
                # Se não for um nome de domínio válido, mostre uma mensagem de erro
                self.lbl_log_ping.setText("Domínio ou IP inválido!")

    # Função que chama a janela de log acionada pelo botão logs (btn_abrir_janela_logs)
    def mostrar_janela_log_conexao(self):
        self.log_windows = LogWindow(self.lista_log_conexao)
        self.historico_log = "\n".join(self.lista_log_conexao)
        self.log_windows.ptx_log.setPlainText(self.historico_log)
        self.log_windows.exec_()

    def mostrar_janela_log_ping(self):
        self.log_windows = LogWindow(self.lista_log_ping)
        self.historico_log = "\n".join(self.lista_log_ping)
        self.log_windows.ptx_log.setPlainText(self.historico_log)
        self.log_windows.exec_()

    # Função chamada pelo botão de alterar dns para o google, na qual chama a função change_dns_to_google do arquivo
    # rede.py passando o argumento do endereço de IP da rede principal
    def alterar_dns_google(self):
        status_troca_dns = rede.change_dns_to_google(endereco_interface_ativa)
        self.busca_informacoes_rede()
        if status_troca_dns == "ok":
            self.lbl_log_rede.setText(
                f"DNS da interface com IP {endereco_interface_ativa} foi atualizado \npara DNS1: 8.8.8.8  &  "
                f" DNS2: 8.8.4.4")
        else:
            self.lbl_log_rede.setText(
                f"DNS da interface com IP {endereco_interface_ativa} não teve êxito \nna alteração")

    # Função chamada pelo botão de alterar dns para o google, na qual chama a função change_dns_to_dhcp do arquivo
    # rede.py passando o argumento do endereço de IP da rede principal
    def alterar_dns_dhcp(self):
        self.btn_dns_google.setEnabled(True)
        status_troca_dns = rede.change_dns_to_dhcp(endereco_interface_ativa)
        self.busca_informacoes_rede()
        if status_troca_dns == "ok":
            self.lbl_log_rede.setText(
                f"DNS da interface com IP {endereco_interface_ativa} foi atualizado \npara automático")
        else:
            self.lbl_log_rede.setText(
                f"DNS da interface com IP {endereco_interface_ativa} não teve êxito \nna alteração")

    # Adiciona o evento ao log (Está sendo chamado cada vez que a internet cai, volta, etc, na função de trocar imagem
    # e executar os sons.
    def adiciona_ao_log_conexao(self, evento):
        log = datetime.now().strftime('%d-%m-%Y %H:%M:%S')
        self.lista_log_conexao.append(f"{log}: {evento}")

    def adiciona_ao_log_ping(self, evento, site_pingado):
        log = datetime.now().strftime('%d-%m-%Y %H:%M:%S')
        if site_pingado == "":
            site = "www.google.com.br - Padrão primeiro ping"
        else:
            site = str(site_pingado)
        self.lista_log_ping.append(f"{log} ({site}): \n{evento}")

    # ____________________________________ Sessão de funções de alteração da img da internet ________________
    # Função chamada pela função check_internet_connection em caso da internet estiver ok!
    def altera_img_internet_ok(self):
        self.show_window() # Exibe a janela do programa se ele estiver no tray
        self.lb_img_status_conexao.setPixmap(diretorio_atual + '\images\sinal_verde_grande.png')
        html_text1 = (f"
Funcionando
")
        self.lb_status_da_conexao_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))
        self.sons.play(self.som_internet_ok, loops=0)
        self.adiciona_ao_log_conexao("Internet funcionando na primeira execução do programa")

    # Função chamada pela função check_internet_connection em caso da internet não estiver ok!
    def altera_img_internet_nao_ok(self):
        self.show_window() # Exibe a janela do programa se ele estiver no tray
        self.lb_img_status_conexao.setPixmap(diretorio_atual + '\images\sinal_vermelho_grande.png')
        html_text1 = (f"
Sem "
                      f"Internet
")
        self.lb_status_da_conexao_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))
        self.sons.play(self.som_internet_sem_internet, loops=0)
        self.adiciona_ao_log_conexao("Sem Internet na primeira execução do programa")

    # Função chamada pela função check_internet_connection em caso da internet cair!
    def altera_img_internet_caiu(self):
        self.show_window() # Exibe a janela do programa se ele estiver no tray
        self.lb_img_status_conexao.setPixmap(diretorio_atual + '\images\sinal_vermelho_grande.png')
        html_text1 = (f"
A "
                      f"Internet caiu!
")
        self.lb_status_da_conexao_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))
        self.sons.play(self.som_internet_caiu, loops=0)
        self.adiciona_ao_log_conexao("Internet caiu")

    # Função chamada pela função check_internet_connection em caso da internet voltar!
    def altera_img_internet_voltou(self):
        self.show_window() # Exibe a janela do programa se ele estiver no tray
        self.lb_img_status_conexao.setPixmap(diretorio_atual + '\images\sinal_verde_grande.png')
        html_text1 = (f"
A "
                      f"Internet voltou!
")
        self.lb_status_da_conexao_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))
        self.sons.play(self.som_internet_voltou, loops=0)
        self.adiciona_ao_log_conexao("Internet voltou")

    # Função chamada pela função check_internet_connection em caso da internet cair a partir da segunda vez!
    def altera_img_internet_caiu_dinovo(self):
        self.show_window() # Exibe a janela do programa se ele estiver no tray
        self.lb_img_status_conexao.setPixmap(diretorio_atual + '\images\sinal_vermelho_grande.png')
        html_text1 = (f"
A "
                      f"Internet caiu dinovo!
")
        self.lb_status_da_conexao_resultado.setText(QCoreApplication.translate("MainWindow", html_text1, None))
        self.sons.play(self.som_internet_caiu_dinovo, loops=0)
        self.adiciona_ao_log_conexao("Internet caiu dinovo")

    # ____________________________________ Sessão de bloqueio de botões e linhas  _____________________________
    # Função para bloquear as entradas de linha e botão referenets ao ping. Essa função também é responsável por criar
    # e mensagem de processando ping na lb de exibição de ping
    def bloquear_btnPing_lnPing(self):
        texto_processando_ping = "Processando ping para " + self.hostname
        self.lbl_log_ping.setText(texto_processando_ping)
        self.btn_pingar.setDisabled(True)
        self.ln_entrada_ping.setDisabled(True)
        self.ln_quantidade_ping.setDisabled(True)

    # Função para liberar as entradas de linha referentes ao ping (site e quantidade de pings)
    def liberar_lnPing(self):
        self.ln_entrada_ping.setEnabled(True)
        self.ln_quantidade_ping.setEnabled(True)

    # Função que libera somente o botão de pingar
    def bloquear_botao_ping(self):
        habilitado = bool(self.ln_entrada_ping.text() and self.ln_quantidade_ping.text())
        self.btn_pingar.setEnabled(habilitado)

# Classe da janela de log
class LogWindow(QDialog, Ui_janela_log):
    def __init__(self, lista_log):
        super(LogWindow, self).__init__()
        self.setupUi(self)
        self.lista_log = lista_log

        self.setWindowTitle("Cadê minha internet? - Logs")
        self.setWindowIcon(QIcon(diretorio_atual + "\images\icon.png"))
        self.setFixedSize(535, 505)

        self.btn_exportar_log.clicked.connect(self.exportar_log)

    # Função que gera o txt do log.
    def exportar_log(self):
        self.historico_log = "\n".join(self.lista_log)

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        file_name, _ = QFileDialog.getSaveFileName(self, "Exportar Log", "",
                                                   "Arquivos de Texto (*.txt);;Todos os Arquivos (*)",
                                                   options=options)

        if file_name:
            try:
                file_name += ".txt"
                with open(file_name, 'w') as file:
                    file.write(self.historico_log)
                self.mostrar_mensagem("Log exportado com sucesso para:\n" + file_name)
            except Exception as e:
                self.mostrar_mensagem("Erro ao exportar o log:\n" + str(e))

    # Função para mostrar uma mensagem para o usuário na tela
    def mostrar_mensagem(self, mensagem):
        msg_box = QMessageBox()
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setText(mensagem)
        msg_box.setWindowTitle("Mensagem")
        msg_box.exec_()

# Precisa de apenas uma instância por aplicação
app = QApplication(sys.argv)
# Chama a função de verificar atualização do progrma
verifica_atualizacao(app)
# Criação do qtwidget que será a janela
window = MainWindow()
# Começa o evento loop
window.show()

app.exec_()