import math
import numpy as np
import scipy.constants as sc
import units as unit

def db_to_abs(db_value):
    """
    :param db_value: list or float
    :return: Convert dB to absolute value
    """
    absolute_value = 10**(db_value/float(10))
    return absolute_value

def abs_to_db(absolute_value):
    """
    :param absolute_value: list or float
    :return: Convert absolute value to dB
    """
    db_value = 10*np.log10(absolute_value)
    return db_value

class TransmissionSystem(object):

    def __init__(self):

        # active_channels =
        # {link_id:
        #   {span_id: [
        #       {channel_id: power_level},
        #       {channel_id: noise_levels},
        #       {channel_id: amplifier_attenuation}]
        #   }
        # }
        self.input_power = {}
        self.output_power = {}
        self.amplified_spontaneous_emission_noise = {}
        self.nonlinear_interference_noise = {}

    def init_interfaces(self, links):

        for link in links:
            self.input_power[link] = {}
            self.output_power[link] = {}
            self.amplified_spontaneous_emission_noise[link] = {}
            self.nonlinear_interference_noise[link] = {}
            spans = link.spans
            for span, _amplifier in spans:
                self.input_power[link][span] = {}
                self.output_power[link][span] = {}
                self.amplified_spontaneous_emission_noise[link][span] = {}
                self.nonlinear_interference_noise[link][span] = {}

    def propagate(self, path, signals):
        """

        :param path: list of Span tuples (span, amplifier)
        :param signals: list of signals in transmission - list[Signal(),]
        :return: Run transmission system, returning True on success
        """

        input_power = {}
        output_power = {}
        signal_power_nonlinear = {}
        amplified_spontaneous_emission_noise = {}
        nonlinear_interference_noise = {}
        wdg = {}
        for signal in signals:
            signal_index = signal.index
            input_power[signal_index] = db_to_abs(signal.launch_power)
            output_power[signal_index] = db_to_abs(signal.launch_power)
            nonlinear_interference_noise[signal_index] = db_to_abs(0.0)

        # get last node in path (Rx)
        rx_node = path[-1][0]
        # Calculate the current signal behaviour across the
        # path elements (nodes and links)
        for node, link in path:
            # If we are at the Rx node, then we are done with this path
            if node == rx_node:
                break
            else:
                # Calculate impairments of the node and its compensation
                node_attenuation = db_to_abs(node.attenuation())
                node_amplifier = node.amplifier
                previous_amplifier = node_amplifier

                for signal in signals:
                    signal_index = signal.index
                    signal_frequency = signal.frequency
                    signal_launch_power = signal.launch_power  # MAYBE TO BE REMOVED
                    signal_power = output_power[signal_index]
                    # Needed for computation of nonlinear interference noise
                    signal_power_nonlinear[signal_index] = output_power[signal_index]

                    signal_power = signal_power / node_attenuation

                    if node_amplifier:
                        amplifier_target_gain = node_amplifier.target_gain
                        amplifier_noise_figure = node_amplifier.noise_figure
                        amplifier_mode = node_amplifier.mode
                        amplifier_bandwidth = node_amplifier.bandwidth
                        amplifier_wavelength_dependent_gain = node_amplifier.wavelength_dependent_gain[signal_index]

                        signal_noise = self.stage_amplified_spontaneous_emission_noise(
                            signal_frequency, amplifier_target_gain, amplifier_wavelength_dependent_gain,
                            amplifier_noise_figure, amplifier_bandwidth)
                        amplified_spontaneous_emission_noise[signal_index] = signal_noise

                        # Output signal power levels after amplification
                        signal_power = self.output_amplified_power(
                            signal_power, amplifier_target_gain, amplifier_mode,
                            signal_launch_power, amplifier_wavelength_dependent_gain)

                    # Signal performance after node
                    # Output power levels after amplification
                    output_power[signal_index] = signal_power

                # Links are composed of fibre spans and amplifiers.
                # Iterate through the link elements and compute the
                # impairments raised by each
                for span, amplifier in link.spans:
                    # Retrieve linear degradation effects due to the optical fiber
                    fibre_attenuation = db_to_abs(span.fibre_attenuation * span.length)

                    for signal in signals:
                        # Compute linear effects
                        signal_index = signal.index
                        signal_power = output_power[signal_index]

                        signal_power = signal_power / fibre_attenuation
                        # dispersion requires revision
                        # dispersion = self.dispersion(signal, span)
                        # signal_power = signal_power / dispersion

                        # Signal performance at the end of span
                        # considering linear effects
                        input_power[signal_index] = signal_power
                        if amplifier:
                            wdg[signal_index] = amplifier.wavelength_dependent_gain[signal_index]

                    # Check if active channels is  not single channel, or
                    # if the loop is not at the last EDFA.
                    if len(input_power) > 1:
                        # Compute nonlinear effects
                        # compute SRS impairment
                        input_power = self.zirngibl_srs(signals,
                                                        input_power,
                                                        span)

                        if amplifier:
                            # Store not normalized power and noise levels
                            # to be considered in the power excursion calculation
                            not_normalized_power = input_power
                            not_normalized_noise = amplified_spontaneous_emission_noise

                            normalized_power, normalized_noise = self.normalize_channel_levels(
                                input_power,
                                amplified_spontaneous_emission_noise,
                                wdg)
                            # Consider power excursion and propagation per-span
                            input_power = self.power_excursion_propagation(
                                normalized_power, normalized_noise,
                                not_normalized_power, not_normalized_noise)

                    if len(input_power) > 2:
                        # Compute nonlinear interference noise, passing the node_amplifier
                        # because its amplification gain impacts negatively the nonlinear
                        # interference.
                        if amplifier:
                            nonlinear_interference_noise = self.output_nonlinear_noise(
                                signals,
                                nonlinear_interference_noise,
                                signal_power_nonlinear,
                                span,
                                node_amplifier)
                            self.nonlinear_interference_noise[link][span] = nonlinear_interference_noise

                    for signal in signals:
                        # Compute linear effects
                        signal_index = signal.index
                        signal_frequency = signal.frequency
                        signal_launch_power = signal.launch_power
                        signal_power = input_power[signal_index]

                        self.input_power[link][span][signal_index] = signal_power * unit.mW

                        if amplifier:
                            amplifier_target_gain = amplifier.target_gain
                            amplifier_previous_gain = previous_amplifier.target_gain
                            amplifier_noise_figure = amplifier.noise_figure
                            amplifier_mode = amplifier.mode
                            amplifier_bandwidth = node_amplifier.bandwidth
                            amplifier_wavelength_dependent_gain = amplifier.wavelength_dependent_gain[signal_index]
                            amplifier_previous_wavelength_dependent_gain = \
                                previous_amplifier.wavelength_dependent_gain[signal_index]

                            signal_noise = self.stage_amplified_spontaneous_emission_noise(
                                signal_frequency, amplifier_previous_gain, amplifier_previous_wavelength_dependent_gain,
                                amplifier_noise_figure, amplifier_bandwidth)
                            self.amplified_spontaneous_emission_noise[link][span][signal_index] = signal_noise

                            # Output signal power levels after amplification
                            signal_power = self.output_amplified_power(
                                signal_power, amplifier_target_gain, amplifier_mode,
                                signal_launch_power, amplifier_wavelength_dependent_gain)

                            previous_amplifier = amplifier

                        # Output power levels after amplification
                        self.output_power[link][span][signal_index] = signal_power

    @staticmethod
    def dispersion(signal, span):
        symbol_rate = signal.symbol_rate
        bits_per_symbol = signal.bits_per_symbol
        gross_bit_rate = symbol_rate * np.log2(bits_per_symbol)
        bandwidth_nm = unit.c / signal.bandwidth
        dispersion = -(2 * unit.pi * unit.c/signal.wavelength**2) * span.dispersion_coefficient
        dispersion_penalty = 5 * np.log10(1 + (4 * bandwidth_nm*unit.nm * gross_bit_rate * span.length * dispersion)**2)
        dispersion_penalty_abs = db_to_abs(dispersion_penalty)
        return dispersion_penalty_abs

    @staticmethod
    def output_amplified_power(signal_power, target_gain, mode, launch_power, amplifier_wavelength_dependent_gain):
        """
        :param signal_power: units: mW - float
        :param target_gain: units mW (absolute value) - float
        :param mode: amplifier mode - string
        :param launch_power: units: mW, only used if mode=AGC - float
        :param amplifier_wavelength_dependent_gain: units: mW - float
        :param amplifier_wavelength_dependent_gain: units: mW - float
        :return: amplification-compensated power levels - float
        """
        if mode == 'AGC':
            # Adjust the gain to keep signal power constant
            target_gain = db_to_abs(abs(abs_to_db(signal_power)-launch_power))
        # Conversion from dB to linear
        target_gain_linear = db_to_abs(target_gain)
        wavelength_dependent_gain_linear = db_to_abs(amplifier_wavelength_dependent_gain)
        return signal_power * target_gain_linear * wavelength_dependent_gain_linear

    @staticmethod
    def stage_amplified_spontaneous_emission_noise(signal_frequency, amplifier_target_gain,
                                                   amplifier_wavelength_dependent_gain,
                                                   amplifier_noise_figure, amplifier_bandwidth):
        """
        :param signal_frequency: units: THz
        :param amplifier_target_gain: units: dB
        :param amplifier_wavelength_dependent_gain: units: dB
        :param amplifier_noise_figure: units: dB
        :param amplifier_bandwidth: units: GHz
        :return: ASE noise in linear form
        Ch.5 Eqs. 4-16,18 in: Gumaste A, Antony T. DWDM network designs and engineering solutions. Cisco Press; 2003.
        """

        # Compute parameters needed for ASE model
        population_inversion = 0.5 * 10**(amplifier_noise_figure/10.0)
        amplifier_gain = amplifier_target_gain - 1

        # Conversion from dB to linear
        gain_linear = db_to_abs(amplifier_gain)
        wavelength_dependent_gain_linear = db_to_abs(amplifier_wavelength_dependent_gain)

        # Calculation of the amplified spontaneous emission (ASE) noise.
        # Simpler formula
        # ase_noise = db_to_abs(amplifier_noise_figure) * sc.h * signal_frequency * amplifier_bandwidth
        ase_noise = 2 * population_inversion * (gain_linear * wavelength_dependent_gain_linear) * \
            sc.h * signal_frequency * amplifier_bandwidth
        return ase_noise

    def output_nonlinear_noise(self, signals, nonlinear_interference_noise,
                               signal_power_nonlinear, span, node_amplifier):
        """
        :param signals: signals interacting at given transmission - list[Signal() object]
        :param nonlinear_interference_noise: accumulated NLI noise - dict{signal_index: NLI noise levels}
        :param signal_power_nonlinear: power levels at beginning of span - dict{signal_index: power levels}
        :param span: Span() object
        :param node_amplifier: Amplifier() object at beginning of span
        :return: dict{signal_index: accumulated NLI noise levels}
        """
        node_amplifier_gain = db_to_abs(node_amplifier.target_gain)
        nonlinear_noise = self.nonlinear_noise(signals, signal_power_nonlinear, span, node_amplifier_gain)
        out_noise = {}
        for signal_index, value in nonlinear_noise.items():
            out_noise[signal_index] = nonlinear_interference_noise[signal_index] + nonlinear_noise[signal_index]
        return out_noise

    @staticmethod
    def nonlinear_noise(signals, signal_power, span, lump_gain):
        """
        Computation taken from: Poggiolini, P., et al. "Accurate Non-Linearity Fully-Closed-Form Formula
        based on the GN/EGN Model and Large-Data-Set Fitting." Optical Fiber Communication Conference.
        Optical Society of America, 2019. Equations 1-4

        :param signals: signals interacting at given transmission - list[Signal() object]
        :param signal_power: power levels at beginning of span - dict{signal_index: power levels}
        :param span: Span() object
        :param lump_gain: EDFA target gain + wavelength dependent gain - float
        :return: Nonlinear Interference noise - dictionary{signal_index: NLI}
        """
        nonlinear_noise_struct = {}
        channels_index = sorted(signal_power.keys())
        for channel_index in channels_index:
            nonlinear_noise_struct[channel_index] = None
        channel_center = channels_index[int(math.floor(len(signal_power.keys()) / 2))]
        for signal in signals:
            if signal.index == channel_center:
                frequency_center = signal.frequency
                break

        # Retrieve fiber properties from span
        b2 = span.dispersion_coefficient
        b3 = span.dispersion_slope
        alpha = span.loss_coefficient
        gamma = span.non_linear_coefficient
        span_length = span.length

        for signal in signals:
            channel_under_test = signal.index
            frequency_cut = signal.frequency
            symbol_rate_cut = signal.symbol_rate
            bits_per_symbol_cut = signal.bits_per_symbol
            gross_bit_rate_cut = symbol_rate_cut * np.log2(bits_per_symbol_cut)
            bw_cut = gross_bit_rate_cut / (2 * np.log2(4))  # full bandwidth of the nth channel (THz).
            pwr_cut = signal_power[signal.index]
            g_cut = pwr_cut / bw_cut  # G is the flat PSD per channel power (per polarization)

            nonlinear_noise_term2 = 0

            for ch in signals:
                # omit channel under test
                if ch == channel_under_test:
                    continue

                frequency_ch = ch.frequency
                symbol_rate_ch = signal.symbol_rate
                bits_per_symbol_ch = signal.bits_per_symbol
                gross_bit_rate_ch = symbol_rate_ch * np.log2(bits_per_symbol_ch)
                bw_ch = gross_bit_rate_ch / (2 * np.log2(4))  # full bandwidth of the nth channel (THz).
                pwr_ch = signal_power[ch.index]
                g_ch = pwr_ch / bw_ch  # G is the flat PSD per channel power (per polarization)

                b2_eff_nch = b2 + unit.pi * b3 * (
                            frequency_ch + frequency_cut - 2 * frequency_center)  # FWM-factor - [1], Eq. (5)
                b2_eff_ncut = b2 + unit.pi * b3 * (
                        2 * frequency_cut - 2 * frequency_center)  # FWM-factor - [1], Eq. (6)

                nch_dividend1 = math.asinh(
                    (unit.pi ** 2 / 2) * abs(b2_eff_nch / alpha) *
                    (frequency_ch - frequency_cut + (bw_ch / 2)) * bw_cut)
                nch_divisor1 = 8 * unit.pi * abs(b2_eff_nch) * alpha

                nch_dividend2 = math.asinh(
                    (unit.pi ** 2 / 2) * abs(b2_eff_nch / alpha) *
                    (frequency_ch - frequency_cut - (bw_ch / 2)) * bw_cut)
                nch_divisor2 = 8 * unit.pi * abs(b2_eff_nch) * alpha

                _nch = (nch_dividend1 / float(nch_divisor1)) - (
                            nch_dividend2 / float(nch_divisor2))  # [1], Eq. (3)

                cut_dividend = math.asinh((unit.pi ** 2 / 2) * abs(b2_eff_ncut / (2 * alpha)) * bw_cut ** 2)
                cut_divisor = 4 * unit.pi * abs(b2_eff_ncut) * alpha
                _cut = cut_dividend / float(cut_divisor)  # [1], Eq. (4)

                nonlinear_noise_term2 += (2 * g_ch ** 2 * _nch + g_cut ** 2 * _cut)

            nonlinear_noise_term1 = 16 / 27.0 * gamma ** 2 * lump_gain * math.e ** (-2 * alpha * span_length) * g_cut
            nonlinear_noise = nonlinear_noise_term1 * nonlinear_noise_term2
            nonlinear_noise_struct[channel_under_test] = nonlinear_noise
        return nonlinear_noise_struct

    @staticmethod
    def zirngibl_srs(signals, active_channels, span):
        """
        Computation taken from : M. Zirngibl Analytical model of Raman gain effects in massive
        wavelength division multiplexed transmission systems, 1998. - Equations 7,8.

        :param signals: signals interacting at given transmission - list[Signal() object]
        :param active_channels: power levels at the end of span - dict{signal_index: power levels}
        :param span: Span() object
        :return:
        """
        min_wavelength_index = 90
        max_wavelength_index = 0
        min_signal = None
        max_signal = None
        for signal in signals:
            if signal.index < min_wavelength_index:
                min_signal = signal
                min_wavelength_index = signal.index
            if signal.index > max_wavelength_index:
                max_signal = signal
                max_wavelength_index = signal.index
        frequency_min = min_signal.frequency  # minimum frequency of longest wavelength
        frequency_max = max_signal.frequency  # maximum frequency of shortest wavelength

        effective_length = span.effective_length  # SMF effective distance
        beta = span.raman_coefficient

        total_power = 0  # Total input power calculated by following loop
        for channel, power_per_channel in active_channels.items():
            total_power += power_per_channel*unit.mW

        # Calculate delta P for each channel
        for signal in signals:
            signal_index = signal.index
            frequency = signal.frequency
            r1 = beta * total_power * effective_length * (frequency_max - frequency_min) * math.e ** (
                        beta * total_power * effective_length * (frequency_max - frequency))  # term 1
            r2 = math.e ** (beta * total_power * effective_length * (frequency_max - frequency_min)) - 1  # term 2

            delta_p = float(r1/r2)  # Does the arithmetic in mW
            active_channels[signal_index] *= delta_p

        return active_channels

    @staticmethod
    def normalize_channel_levels(power_levels, noise_levels, wavelength_dependent_gains):
        """
        :param power_levels: units: mW - list[float,]
        :param noise_levels: units: linear - list[float,]
        :param wavelength_dependent_gains: units: dB list[float,]
        :return: dictionary of normalized power and noise - dict{signal_index: power/noise}
        """
        # Sum amplifier attenuation for each channel
        # Calculate the main system gain of the loaded channels
        # (i.e. mean wavelength gain)
        loaded_gains_db = wavelength_dependent_gains.values()
        total_system_gain_db = sum(loaded_gains_db)
        channel_count = len(wavelength_dependent_gains)
        mean_system_gain_db = total_system_gain_db/float(channel_count)
        mean_system_gain_abs = db_to_abs(mean_system_gain_db)

        # Affect the power and noise with the mean of wavelength gain
        normalized_power = {k: abs(x/mean_system_gain_abs) for k, x in power_levels.items()}
        normalized_noise = {k: abs(x/mean_system_gain_abs) for k, x in noise_levels.items()}

        return normalized_power, normalized_noise

    @staticmethod
    def power_excursion_propagation(normalized_power, normalized_noise,
                                    not_normalized_power, not_normalized_noise):
        """
        :param normalized_power: dict{signal_index: power - float}
        :param normalized_noise: dict{signal_index: noise - float}
        :param not_normalized_power: dict{signal_index: power - float}
        :param not_normalized_noise: dict{signal_index: noise - float}
        :return: dictionary with the power excursion propagated in the signal power levels
        """
        # Calculate total power values given by the form: P*N
        total_power = {}
        for k in normalized_power.keys():
            power = normalized_power[k]
            noise = normalized_noise[k]
            total_power[k] = abs(power * noise + power)
        total_power_old = {}
        for k in normalized_power.keys():
            power = not_normalized_power[k]
            noise = not_normalized_noise[k]
            total_power_old[k] = abs(power * noise + power)

        # Calculate excursion
        excursion = max(p/op for p, op in zip(total_power.values(), total_power_old.values()))

        # Propagate power excursion
        power_excursion_prop = {k: p*excursion for k, p in total_power.items()}  # new

        # update current power levels with the excursion propagation
        return power_excursion_prop


import time
from tkinter import *
canvas = Tk()
canvas.title("Reconnext&Teleplan")
canvas.geometry("1366x768")
canvas.resizable(1,1)
bg = PhotoImage(file="images\mb.png")
canvas.attributes ('-transparentcolor','')
mycan = Canvas( width=1366, height=768)
label = Label(font=("Arial", 140, "bold"), fg="green")
label.pack(pady=20)
def digitalclock():
   text_input = time.strftime("%H:%M:%S.%p",)
   label.place( relx=0.5, rely=0.5, anchor=CENTER)
   label.config( text=text_input)
   label.after(1000, digitalclock)
digitalclock()
mycan.create_image(0,0, image=bg,  anchor="nw")
mycan.pack(fill="both", expand=True)
text_lab = Label(mycan,text="Teleplan&Reconext",font=("Courier", 60,"bold"), fg="blue")
label.place( relx=1.5, rely=1.5, anchor=S)
text_lab.pack(side=BOTTOM)
canvas.mainloop()


import numpy as np
import os
from PIL import Image
import cv2
import matplotlib.pyplot as plt
from tqdm import tqdm
import pandas as pd
from config import *
import dlib

def convert_csv_to_jpg(csv_path):
    # 加载opencv的人脸识别文件
    # 'haarcascade_frontalface_alt' higher accuracy, but slower
    # 'haarcascade_frontalface_default' lower accuracy, but faster and lighter
    # detector = cv2.CascadeClassifier(haarcascade_frontalface_alt)
    detector = dlib.get_frontal_face_detector()
    landmark_predictor = dlib.shape_predictor(shape_predictor_68_face_landmarks)

    # 将csv转换为numpy数组，再通过PIL转换为jpg
    data = pd.read_csv(csv_path, encoding="ISO-8859-1")

    train_path_data = {'path': [], 'emotion': []}
    valid_path_data = {'path': [], 'emotion': []}
    test_path_data = {'path': [], 'emotion': []}

    train_landmark = []
    valid_landmark = []
    test_landmark = []

    if not os.path.exists(TRAIN_DIR):
        os.mkdir(TRAIN_DIR)

    if not os.path.exists(TEST_DIR):
        os.mkdir(TEST_DIR)

    if not os.path.exists(VALID_DIR):
        os.mkdir(VALID_DIR)

    total = 0
    for label, pixels, usage in tqdm(zip(data['emotion'], data['pixels'], data['Usage'])):
        img = np.asarray(pixels.split()).astype(np.int32).reshape([img_size, img_size])
        all_faces, all_landmarks = crop_face_area(detector, landmark_predictor, img, img_size)
        if all_faces is None:
            continue
        for img, landmarks in zip(all_faces, all_landmarks):
            img = Image.fromarray(img).convert(mode='L')
            fname = str(total) + '.jpg'
            if usage == 'Training':
                save_path = TRAIN_DIR + '/' + fname
                train_path_data['path'].append(fname)
                train_path_data['emotion'].append(label)
                train_landmark.append(landmarks)
            elif usage == 'PrivateTest':
                save_path = VALID_DIR + '/' + fname
                valid_path_data['path'].append(fname)
                valid_path_data['emotion'].append(label)
                valid_landmark.append(landmarks)
            else:
                save_path = TEST_DIR + '/' + fname
                test_path_data['path'].append(fname)
                test_path_data['emotion'].append(label)
                test_landmark.append(landmarks)
            img.save(save_path)
            total += 1

    train_landmark = np.asarray(train_landmark)
    valid_landmark = np.asarray(valid_landmark)
    test_landmark = np.asarray(test_landmark)

    np.savez(TRAIN_LANDMARK_PATH, landmark=train_landmark)
    np.savez(VALID_LANDMARK_PATH, landmark=valid_landmark)
    np.savez(TEST_LANDMARK_PATH, landmark=test_landmark)

    train_path_data = pd.DataFrame(train_path_data)
    train_path_data.to_pickle(TRAIN_PATH)
    valid_path_data = pd.DataFrame(valid_path_data)
    valid_path_data.to_pickle(VALID_PATH)
    test_path_data = pd.DataFrame(test_path_data)
    test_path_data.to_pickle(TEST_PATH)

    print('Total: {}, training: {}, valid: {}, test: {}'.format(
        total, len(train_path_data), len(valid_path_data), len(test_path_data)))

def crop_face_area(detector, landmark_predictor, image, img_size):
    """
    裁剪图像的人脸部分，并resize到img_size尺寸

    :param detector:
    :param image:
    :param img_size:
    :return: Two numpy arrays containing the area and landmarks of all faces.
    None if no face was detected.
    """
    # p_img = Image.fromarray(image).convert(mode='RGB')
    # cv_img = cv2.cvtColor(np.asarray(p_img), cv2.COLOR_RGB2GRAY)
    # faces = detector.detectMultiScale(
    #     image=cv_img,
    #     scaleFactor=1.1,
    #     minNeighbors=1,
    #     minSize=(30, 30),
    #     flags=0
    # )
    # if len(faces) != 0:
    #     x, y, w, h = faces[0]
    #     cv_img = cv2.resize(cv_img[x:x + w, y:y + h], (img_size, img_size))
    #     return np.asarray(cv_img)
    # else:
    #     return None

    p_img = Image.fromarray(image).convert(mode='RGB')
    cv_img = cv2.cvtColor(np.asarray(p_img), cv2.COLOR_RGB2GRAY)
    faces = detector(cv_img, 1)
    all_landmarks = []
    all_faces = []
    if len(faces) > 0:
        for face in faces:
            shape = landmark_predictor(cv_img, face)
            landmarks = np.ndarray(shape=[68, 2])
            for i in range(68):
                landmarks[i] = (shape.part(i).x, shape.part(i).y)
            all_landmarks.append(landmarks)
            x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom()
            if x1 < 0:
                x1 = 0
            if x1 > cv_img.shape[1]:
                x1 = cv_img.shape[1]
            if x2 < 0:
                x2 = 0
            if x2 > cv_img.shape[1]:
                x2 = cv_img.shape[1]
            if y1 < 0:
                y1 = 0
            if y1 > cv_img.shape[0]:
                y1 = cv_img.shape[0]
            if y2 < 0:
                y2 = 0
            if y2 > cv_img.shape[0]:
                y2 = cv_img.shape[0]
            img = cv2.resize(cv_img[y1:y2, x1:x2], (img_size, img_size))
            all_faces.append(img)
        return np.asarray(all_faces), np.asarray(all_landmarks)
    else:
        return None, None

def count_lines(csv_path):
    data = pd.read_csv(csv_path, encoding="ISO-8859-1")
    return data.shape[0]

def show_class_distribution(file_path):
    label_num = np.zeros([7], dtype=np.int32)
    data = pd.read_csv(file_path)

    for label in data['emotion']:
        label_num[label] += 1

    rects = plt.bar(class_names, label_num)
    plt.title('Label Distribution')
    plt.xlabel("Label")
    plt.ylabel("Number")

    for rect in rects:
        height = rect.get_height()
        plt.text(rect.get_x() + rect.get_width() / 2, height + 1, str(height), ha="center", va="bottom")
    plt.show()

if __name__ == '__main__':
    convert_csv_to_jpg(DATA_PATH)


from spacy.lang.en import English
import numpy as np

import srsly

from flask import Flask, render_template

patterns = srsly.read_jsonl("Backend/skill_patterns.jsonl")

nlp = English()

ruler = nlp.add_pipe("entity_ruler")
ruler.add_patterns(patterns)

def extract_keywords(txt):

    doc = nlp(txt)
    keywords = list(doc.ents)
    # remove duplicates
    keywords = [str(k) for k in keywords]
    keywords = list(set(keywords))

    return keywords

def calculate_score(resume_kws, job_kws):

    resume_kws = np.array(resume_kws)
    job_kws = np.array(job_kws)

    match_count = 0
    for i in resume_kws:
      for j in job_kws:
        if i == j:
          match_count += 1
          continue

    score = 2 * match_count / (resume_kws.size + job_kws.size)
    return score

def calculate_similarity(resume_str, job_str):
    resume_keywords = extract_keywords(resume_str)
    job_keywords = extract_keywords(job_str)

    score = calculate_score(resume_keywords, job_keywords)
    return score


import pygame
import os

pygame.font.init()

WIDTH, HEIGHT = 1100, 800
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Cowboy shooter")

class Draw_Controller:
    def __init__(self, covers, P1, P2, Bullet_Controller):
        self._DESERT = pygame.transform.scale(pygame.image.load(os.path.join('Assets', 'Desert.png')), (WIDTH, HEIGHT))
        self._covers = covers
        self._P1 = P1
        self._P2 = P2
        self._Bullet_Ctrl = Bullet_Controller
        self._caput_m = (35, 15, 13)
        self._winner_font = pygame.font.SysFont('comicsans', 100)
        self._timer_font = pygame.font.SysFont('comicsans', 50)

    def draw_winner(self, text):
        winner_text = self._winner_font.render(text, 1, self._caput_m)
        WIN.blit(winner_text, (WIDTH/2 - winner_text.get_width()/2, HEIGHT/2 - winner_text.get_height()/2))
        pygame.display.update()
        pygame.time.delay(5000)

    def draw_time(self, timer):
        timer_text = pygame.transform.rotate(self._timer_font.render("Time: " + str(int(timer / 1000)) + "/120" + "s", True, (255, 255, 255)), 270)
        WIN.blit(timer_text, (1000, HEIGHT//2 - timer_text.get_height()//2))

    def draw_window(self, timer):
        WIN.blit(self._DESERT, (0, 0))
        self._P1.draw_health(WIN, self._P1.get_health())
        self._P2.draw_health(WIN, self._P2.get_health())

        for cover in self._covers:
            if cover.get_status():
                cover.draw(WIN)

        self.draw_time(timer)
        self._P1.draw(WIN)
        self._P2.draw(WIN)
        self._Bullet_Ctrl.draw_bullets(WIN)
        pygame.display.update()


from bs4 import BeautifulSoup
from selenium import webdriver
import requests
import csv

browser = webdriver.Chrome()
URL = "https://search.shopping.naver.com/search/all?query=%EB%B0%80%ED%82%A4%ED%8A%B8%20%EB%96%A1%EB%B3%B6%EC%9D%B4&pagingIndex=1"
URLTEST = "https://search.shopping.naver.com/search/all?query=%EC%83%9D%EC%88%98&prevQuery=todtn"

response = requests.get(URL)
html = browser.page_source
soup = BeautifulSoup(html, "lxml")
element = soup.find("a", attrs={
                    "class": "product_link__TrAac linkAnchor", "data-testid": "SEARCH_PRODUCT"})
price = soup.find("span", attrs={"class": "price_num__S2p_v"})
file = open("/users/famelee/desktop/dataset.csv", "w")
writer = csv.writer(file)

# elementhref = element.get("href")

# elementList = (soup.find_all(
#     "a", attrs={"class": "product_link__TrAac linkAnchor"}))
writer

# for elementList in elementList:
#     print(elementList.get_text())
#     print(price.get_text())


from django.test import TestCase
from django.core.urlresolvers import reverse
from committee.models import Committee, Meeting

class ResponseStatus(TestCase):

    def test_committees(self):
        response = self.client.get(reverse('committee-hub'))
        self.assertEqual(response.status_code, 200)

    def test_committee(self):
        response = self.client.get('/committee/')
        self.assertEqual(response.status_code, 200)

    def test_committee_detail_resp(self):
        committee = Committee(name="Committee Name",
                              main_contact="Main Contact", slug="commitee-name")
        committee.save()

        response = self.client.get(committee.get_absolute_url())
        self.assertEqual(response.status_code, 200)

    def test_meeting_detail_resp(self):
        meeting = Meeting(notes="Blah blah blah \n Blah Blue")
        meeting.save()

        response = self.client.get(meeting.get_absolute_url())
        self.assertEqual(response.status_code, 200)


from AIPUBuilder.Optimizer.utils import *
from AIPUBuilder.Optimizer.framework import *

from AIPUBuilder.Optimizer.ops.activation import apply_with_activation, with_activation_out_is_signed, apply_with_activation_quantize, with_activation_allow_merge_out_zerop_to_bias
from AIPUBuilder.Optimizer.logger import *
from AIPUBuilder.Optimizer.ops.convwinograd import *
import torch
import math
import importlib

def _conv2d_torch_impl(self, *args):
    inp = self.inputs[0].betensor.float()
    weights = self.constants['weights'].betensor.clone().float()
    bias = self.constants['biases'].betensor.clone().float()
    stride = (self.get_param("stride_y"), self.get_param("stride_x"))
    dilation = (self.get_param('dilation_y'), self.get_param('dilation_x'))
    padding = (self.get_param('pad_left'), self.get_param('pad_right'),
               self.get_param('pad_top'), self.get_param('pad_bottom'))
    group = self.get_param('group')
    pad_val = 0
    if self.quantized:
        # input's zerop has been absorbed to bias.
        # inp += self.inputs[0].zerop
        inp_zp = self.inputs[0].zerop if isinstance(self.inputs[0].zerop, (float, int)) else self.inputs[0].zerop[0]
        pad_val = -inp_zp
        w_zp = self.constants["weights"].zerop
        w_zshape = [1] * weights.dim()
        w_zshape[0] = -1
        weights += w_zp.reshape(w_zshape) if isinstance(w_zp, torch.Tensor) else w_zp
        bias += self.constants['biases'].zerop

    inp = nhwc2nchw(inp)
    weights = nhwc2nchw(weights)
    if WinogradChecker.run(self) or self.get_param('with_winograd', optional=True, default_value=False):
        x = WinogradAllocator(self, inp, weights, bias)
    else:
        inp = torch.nn.functional.pad(inp, padding, value=pad_val)
        x = torch.nn.functional.conv2d(inp,
                                       weights,
                                       bias,
                                       stride=stride,
                                       padding=0,
                                       dilation=dilation,
                                       groups=group)
    x = nchw2nhwc(x)
    return x

@op_register(OpType.Convolution)
def conv2d(self, *args):
    in_shape = self.inputs[0].shape
    ih, iw = in_shape[1], in_shape[2]
    ky = self.get_param('kernel_y')
    kx = self.get_param('kernel_x')

    if not torch.cuda.is_available() and (ih >= 2048 and iw >= 2048) and (ky == 1 and kx == 1):
        OPT_DEBUG(f"when ih>=2048, iw>=2048 and ky==1, kw==1 with cpu device forward, we will use tf.nn.conv2d to execute.")
        conv2d_tf = importlib.import_module('AIPUBuilder.Optimizer.ops.tf_ops.conv2d')
        x = conv2d_tf.conv2d_tf_impl(self, *args)
    else:
        x = _conv2d_torch_impl(self, *args)

    requant_scale = 1
    requant_shift = 0
    if self.quantized:
        if 'scale_value' in self.params:
            requant_scale = self.params['scale_value']
        elif "scale" in self.constants:
            requant_scale = self.constants["scale"].betensor

        if 'shift_value' in self.params:
            requant_shift = self.params['shift_value']
        elif "shift" in self.constants:
            requant_shift = self.constants["shift"].betensor

    x = apply_with_activation(self,
                              x,
                              self.inputs[0].scale * self.constants["weights"].scale,
                              0,
                              requant_scale,
                              requant_shift,
                              *args)

    self.outputs[0].betensor = x
    return self.outputs[0].betensor

@quant_register(OpType.Convolution)
def conv2d_quantize(self, *args):
    if WinogradChecker.run(self):
        self.constants["weights"] = self.constants['WinogradWeights']
        linear_op_quantize(self, *args)
        self.constants.pop('WinogradWeights')
        if self.get_param('with_winograd', optional=True, default_value=False):
            self.attrs.update({'optimization_info': {'with_winograd': True}})
    else:
        linear_op_quantize(self, *args)

    absorb_input_zp_to_bias_and_compress_bias_for_aiff(self, *args)

def linear_op_quantize(self, *args):
    q_mode_bias = self.attrs["q_mode_bias"]
    q_mode_weight = self.attrs["q_mode_weight"]
    q_mode_activation = self.attrs["q_mode_activation"]
    if q_mode_weight != q_mode_bias:
        OPT_FATAL("Currently quantization mode of weight (q_mode_weight) and bias (q_mode_bias) must be the same!")
    if QuantMode.is_per_channel(q_mode_activation) == True:
        OPT_FATAL("Currently not support per-channel quantization of activations")
    q_bits_weight = self.attrs["q_bits_weight"]
    q_bits_bias = self.attrs["q_bits_bias"]
    q_bits_activation = self.attrs["q_bits_activation"]
    multiplier_bits = self.attrs['multiplier_bits']

    inp = self.inputs[0]

    w = self.constants["weights"]
    key_axis = w.key_axis
    w_out_cnum = w.shape[key_axis]
    w_scale_expand = []
    w_zerop_expand = []
    group = self.get_param('group', optional=True, default_value=1)

    out = self.outputs[0]
    out_signed = with_activation_out_is_signed(self) or self.force_dtype_int
    out.qbits = q_bits_activation

    out.scale, out.zerop, out.qmin, out.qmax, out.dtype = get_linear_quant_params_from_tensor(
        out, q_mode_activation, q_bits_activation, is_signed=out_signed)
    out.qinvariant = False

    if group > 1 or QuantMode.is_per_channel(q_mode_weight):
        if QuantMode.is_per_channel(q_mode_weight):
            mgroup = w_out_cnum
        else:
            mgroup = group

        do_scale, do_scale_type, do_shift, do_shift_type = unify_shifts_for_aiff_with_per_n_channel_quant(
            self, w, q_mode_weight, q_bits_weight, True, lambda xt: out.scale / (inp.scale * xt.scale), initial_group=mgroup)

        w_scale_expand = w.scale
        w_zerop_expand = w.zerop
        self.constants["scale"] = PyTensor(self.name+"/scale",
                                           do_scale.cpu().numpy().astype(dtype2nptype(do_scale_type)))
        self.constants["scale"].dtype = do_scale_type
        self.constants["shift"] = PyTensor(self.name+"/shift",
                                           do_shift.cpu().numpy().astype(dtype2nptype(do_shift_type)))
        self.constants["shift"].dtype = do_shift_type

    else:
        w.scale, w.zerop, w.qmin, w.qmax, w.dtype = get_linear_quant_params_from_tensor(w, q_mode_weight, q_bits_weight,
                                                                                is_signed=True)
        local_rescale = out.scale / (inp.scale * w.scale)
        do_scale, do_scale_type, do_shift, do_shift_type = get_scale_approximation_params(local_rescale,
                                                                                mult_bits=multiplier_bits,
                                                                                force_shift_positive=self.force_shift_positive)
        w_scale_expand.extend([w.scale] * w_out_cnum)
        w_zerop_expand.extend([w.zerop] * w_out_cnum)
        _, do_scale_type = range2dtype(0, do_scale)
        self.params["shift_value"] = int(do_shift)
        self.params["shift_type"] = do_shift_type
        self.params["scale_value"] = int(do_scale)
        self.params["scale_type"] = do_scale_type

    # quantize weights
    if not isinstance(w_scale_expand, torch.Tensor):
        w_scale_expand = torch.tensor(w_scale_expand, device=inp.betensor.device)
        w_zerop_expand = torch.tensor(w_zerop_expand, device=inp.betensor.device)
    scale_zp_shape = [w.shape[ax] if ax == key_axis else 1 for ax in range(len(w.shape))]
    w.betensor = linear_quantize_clip(w.betensor, w_scale_expand.reshape(scale_zp_shape),
                                      w_zerop_expand.reshape(scale_zp_shape), w.qmin, w.qmax)
    w.qbits = q_bits_weight
    w.qinvariant = False

    if 'biases' in self.constants:
        b = self.constants["biases"]
        # if self.get_param('with_activation', optional=True, default_value='none').lower() in with_activation_allow_merge_out_zerop_to_bias :
        #     #y_q = ((w_q + zp_w) (x_q + zp_x) + (b_q + zp_b)s_ws_x/s_b) s_y/s_ws_x - zp_y
        #     #y_q = ((w_q + zp_w) (x_q + zp_x) + (b_f - zp_y/s_y)s_ws_x) s_y/s_ws_x
        #     b.betensor = b.betensor - linear_dequantize(0, out.scale, out.zerop)
        b.scale = inp.scale * w.scale
        b.zerop = 0
        if isinstance(b.scale, torch.Tensor):
            b_scale_shape = [b.shape[ax] if ax == b.key_axis else 1 for ax in range(len(b.shape))]
            b.scale = torch.reshape(b.scale, b_scale_shape)

        if self.attrs['bias_effective_bits'] != q_bits_bias:
            search_bias_bit_and_quantize(self, *args)
        else:
            b.qmin = -2 ** (q_bits_bias - 1)
            b.qmax = 2 ** (q_bits_bias - 1) - 1
            b.qbits = q_bits_bias
            b.betensor = linear_quantize_clip(b.betensor, b.scale, b.zerop, b.qmin, b.qmax)

        b.dtype = bits2dtype(b.qbits, is_signed=True)
        b.qinvariant = False

    apply_with_activation_quantize(self, out.qinvariant, *args)

def clear_lower_bits_for_bias(self, *args, grouped=False, dim=-1):
    # AIFF will scale down biases to 16bit and rescale it back to 32bit later due to hardware restricts
    b = self.constants["biases"]
    lmin, lmax = bits2range(self.attrs['bias_effective_bits'], is_signed=True)
    if not grouped:
        bmin = min(b.betensor.min().item(), -1)
        bmax = max(b.betensor.max().item(), 1)
        lbits = math.ceil(max(math.log2(bmax/lmax), math.log2(bmin/lmin)))
        if lbits > 0:
            b.betensor = ((b.betensor.long() >> lbits) << lbits).float()
    else:
        bmin = torch.min(b.betensor, dim=dim)[0]
        bmax = torch.max(b.betensor, dim=dim)[0]
        lbits = torch.ceil(torch.maximum(torch.log2(bmax / lmax), torch.log2(bmin / lmin))).long().unsqueeze(dim)
        b.betensor = ((b.betensor.long() >> lbits) << lbits).float()

def compute_input_zp_mul_reduce_weight(zp, w):
    return w.reshape(w.shape[0], -1).sum(dim=1) * zp

def absorb_input_zp_to_bias(self, *args):
    w = self.constants["weights"]
    b = self.constants["biases"]

    if self.get_attrs('is_winograd_checker_passed', optional=True, default_value=False):
        device = w.betensor.device
        BT, _, AT = ArcReactor.run(2, 3)
        BT = torch.from_numpy(BT).to(device)
        AT = torch.from_numpy(AT).to(device)
        input_zp = construct_torch_tensor(self.inputs[0].zerop, device)
        weight = w.betensor.permute(0, 3, 1, 2)
        repeated_input_zp = input_zp.repeat([1, BT.shape[0]])
        data_tmp = torch.matmul(repeated_input_zp.float(), BT.permute(1, 0))
        data_repeat_shape = [*weight.shape[0:3]] + [1]
        BT_out = data_tmp.repeat(data_repeat_shape)
        BT_out = BT_out * weight
        AT_out = torch.matmul(BT_out, AT.permute(1, 0))
        input_zp_mul_weight = AT_out.sum(dim=[1, 2])[:, 0]
    else:
        input_zp_mul_weight = compute_input_zp_mul_reduce_weight(self.inputs[0].zerop, w.betensor)
        input_zp_mul_weight = input_zp_mul_weight.item() if b.ir_shape == TensorShape([]) else input_zp_mul_weight

    b.betensor += input_zp_mul_weight
    b.betensor = b.betensor.clamp(b.qmin, b.qmax)

def absorb_input_zp_to_bias_and_compress_bias_for_aiff(self, *args):
    absorb_input_zp_to_bias(self, *args)
    clear_lower_bits_for_bias(self, *args)

def search_bias_bit_and_quantize(self, *args):
    b = self.constants['biases']
    q_bits_bias = self.attrs["q_bits_bias"]
    bias_effective_bits = self.attrs['bias_effective_bits']
    if bias_effective_bits > q_bits_bias:
        OPT_WARN(f"layer_id = {self.attrs['layer_id']}, layer_type = {self.type}, layer_name = {self.name}",
                 f"the bias_effective_bits(={bias_effective_bits}) > bias_bits(={q_bits_bias}), "
                 f"we clip bias_effective_bits to bias_bits.")
        bias_effective_bits = q_bits_bias
        self.attrs['bias_effective_bits'] = bias_effective_bits

    bias_float_data = b.betensor.clone()
    b.qmin = -2 ** (q_bits_bias - 1)
    b.qmax = 2 ** (q_bits_bias - 1) - 1
    b.qbits = q_bits_bias
    b.betensor = linear_quantize_clip(b.betensor, b.scale, b.zerop, b.qmin, b.qmax)

    q_bias_data = b.betensor.clone()
    clear_lower_bits_for_bias(self)
    compressed_q_bias_data = b.betensor
    float_softmax = bias_float_data.clone().softmax(dim=-1)
    quantize_log_softmax = q_bias_data.log_softmax(dim=-1)
    compress_log_softmax = compressed_q_bias_data.log_softmax(dim=-1)
    float_quant_kld = torch.nn.functional.kl_div(quantize_log_softmax, float_softmax, reduction='batchmean')
    float_compress_kld = torch.nn.functional.kl_div(compress_log_softmax, float_softmax, reduction='batchmean')
    if (float_quant_kld - float_compress_kld).abs() > 0.05:
        begin_bits = min(max(bias_effective_bits, 19), q_bits_bias - 1)
        end_bits = q_bits_bias
        bits = torch.arange(begin_bits, end_bits, device=b.betensor.device)
        repeated_bias = torch.tile(bias_float_data, tuple([end_bits - begin_bits] + [1 for _ in range(len(b.shape))]))
        clamp_min = -2 ** (bits - 1)
        clamp_max = 2 ** (bits - 1) - 1
        q_biases = linear_quantize_clip(repeated_bias, construct_torch_tensor(b.scale, device=b.betensor.device).unsqueeze(0), b.zerop,
                                        clamp_min.unsqueeze(-1), clamp_max.unsqueeze(-1))
        b.betensor = q_biases.clone()
        clear_lower_bits_for_bias(self, grouped=True)
        compress_biases = b.betensor
        q_softmax = linear_dequantize(q_biases, b.scale, b.zerop).softmax(dim=-1)
        cq_log_softmax = linear_dequantize(compress_biases, b.scale, b.zerop).log_softmax(dim=-1)
        klds = []
        for i in range(end_bits - begin_bits):
            kld = torch.nn.functional.kl_div(cq_log_softmax[i], q_softmax[i], reduction='batchmean').abs()
            klds.append(kld.item())

        searched_bias_bits = klds.index(min(klds)) + begin_bits
        b.qmin = -2 ** (searched_bias_bits - 1)
        b.qmax = 2 ** (searched_bias_bits - 1) - 1
        b.qbits = searched_bias_bits
        b.betensor = linear_quantize_clip(bias_float_data, b.scale, b.zerop, b.qmin, b.qmax)
        OPT_DEBUG((f"layer_id = {self.attrs['layer_id']}, layer_type = {self.type}, layer_name = {self.name} "
                   f"searched bias bits = {searched_bias_bits} for better quantize bias "
                   f"to reduce the compression bias impact in AIFF"))
    else:
        b.betensor = q_bias_data


import numpy as np; #NumPy package for arrays, random number generation, etc
import matplotlib.pyplot as plt #for plotting
import pandas as pd

#Simulation window parameters
startpoint = [[-100,-1000],[-100,0],[-100,1000],[0,-100],[0,100],[100,-100],[100,0],[100,100]]
xx = np.array([])
yy = np.array([])
hz = np.array([])
xDelta=100;yDelta=100; #rectangle dimensions
areaTotal=xDelta*yDelta;

#Point process parameters
lambda0=1*10**-3 #intensity (ie mean density) of the Poisson process

#Simulate a Poisson point process
for i,j in startpoint:
    numbPoints = np.random.poisson(lambda0*areaTotal);#Poisson number of points
    xx = np.r_[xx,xDelta*np.random.uniform(0,1,numbPoints)+i];#x coordinates of Poisson points
    yy = np.r_[yy,yDelta*np.random.uniform(0,1,numbPoints)+j];#y coordinates of Poisson points
    hz = np.r_[hz,range(numbPoints)]

df = pd.DataFrame(data = (xx,yy,hz))
df.to_csv("./InterferenceBSposition.csv", index = False, header = False)


from telegram import Bot
from telegram.ext import Dispatcher, PicklePersistence

from handlers import handlers

def setup_bot(token, persistence_filename='persistence'):
    # Create bot, update queue and dispatcher instances
    bot = Bot(token)
    bot_persistence = PicklePersistence(filename=persistence_filename)

    dispatcher = Dispatcher(bot, None, workers=0,
                            use_context=True,
                            persistence=bot_persistence)

    ##### Register handlers here #####
    for handler in handlers:
        dispatcher.add_handler(handler)

    return bot, dispatcher


from plot import *
from bokeh.plotting import output_file, show
from bokeh.models import Div

# example values
layout = column(
    Div(text="
Cruise control (PI regulator)
", align="center"),
    make_plot(start_velocity=0, end_velocity=50),
    make_plots(start_velocity=0, end_velocity=50)
)

output_file("cruise_control.html", title="Cruise control")

show(layout)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
from rknn.api import RKNN
#import _init_paths
import cv2
import numpy as np
import math
import threading
from time import sleep
imreadLock = threading.Lock()
#from python_wrapper import *
#import os
import sys
PNET_PYRAMID= np.array([[270,207],[192,147],[136,104],[97,74],[69,53],[49,37],[35,27],[25,19],[18,14]])
ODD_PYRAMID = np.array([[270,207],[136,104],[69,53],[35,27],[18,14]])
ODD_SCALES = np.array([0.6,0.302,0.153,0.0778,0.04])
EVEN_PYRAMID = np.array([[192,147],[97,74],[49,37],[25,19]])
EVEN_SCALES = np.array([0.4267,0.2156,0.1089,0.0556])
#PNET_PYRAMID_ARR= np.array([[[1, 2, 130, 99],[1, 4, 130, 99]],[[1, 2, 91, 69],[1, 4, 91, 69]],[[1, 2, 63, 47],[1, 4, 63, 47]],[[1, 2, 44, 32],[1, 4, 44, 32]],[[1, 2, 30, 22],[1, 4, 30, 22]],[[1, 2, 20, 14],[1, 4, 20, 14]],[[1, 2, 13, 9],[1, 4, 13, 9]],[[1, 2, 8, 5],[1, 4, 8, 5]],[[1, 2, 4, 2],[1, 4, 4, 2]]])
PNET_ODD_ARR = np.array([[1, 2, 198, 99],[1, 4, 198, 99]])
PNET_EVEN_ARR = np.array([[1, 2, 140, 69],[1, 4, 140, 69]])
boundingbox_list = []
IMAGE = np.zeros((344,450,3))
IMAGE_list = []
IMAGE_list.append(IMAGE)
IMAGE_list.append(IMAGE)
proflag = 1

#----------------------------------------------多线程类

class MtcnnThread (threading.Thread):   #继承父类threading.Thread
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
        minsize = 20
        threshold = [0.8, 0.9, 0.95]
        factor = 0.709
        pnet_rknn_list=init_pnet()
        rnet_rknn = RKNN()
        onet_rknn = RKNN()
        rnet_rknn.load_rknn('./RNet.rknn')
        onet_rknn.load_rknn('./ONet.rknn')
        ret = rnet_rknn.init_runtime()
        if ret != 0:
        #print('Init rnet runtime environment failed')
            exit(ret)
        ret = onet_rknn.init_runtime()
        if ret != 0:
        #print('Init onet runtime environment failed')
            exit(ret)
        sys.stdout = open('/dev/stdout', 'w')
        sys.stderr = open('/dev/stderr', 'w')
        global proflag
        global IMAGE_list
        global boundingbox_list
        nonfacecount = 0
        #wrongimg = 1
        while(proflag ==1):
            imreadLock.acquire()
            img0 = IMAGE_list[0].copy()
            img = IMAGE_list[1].copy()
            imreadLock.release()
            #tic()
            score_cmp = compare_image(img0,img)
            #print("score_cmp",score_cmp)
            #toc()
            if score_cmp < 0.98:
            #imreadLock.release()
            #print("detect face start")
            #cv2.imwrite("aa.jpg",img)
                tic()
                boundingboxes, points = detect_face(img, minsize, pnet_rknn_list, rnet_rknn, onet_rknn, threshold, False,factor)
            #print("boundingboxes shape",boundingboxes.shape)
                print("total cost")
                toc()
                if boundingboxes.shape[0] != 0:
                    if len(boundingbox_list) != 0:
                        boundingbox_list.clear()
                    boundingbox_list.append(boundingboxes)
                else:
                #path = str(wrongimg)+".jpg"
                #cv2.imwrite(path,img)
                #wrongimg += 1
                    nonfacecount += 1
                    if nonfacecount >= 3:
                        boundingbox_list.clear()
                        nonfacecount = 0
        for i in range(2):
            pnet_rknn_list[i].release()
        rnet_rknn.release()
        onet_rknn.release()
    '''
    def return_res(self):
        try:
            return self.boundingboxes
        except Exception:
            return None
    '''
'''
class MtcnnThread(threading.Thread):
    def __init__(self, target, args):
        super().__init__()
        self.target = target
        self.args = args

    def run(self):
        self.target(*self.args)
'''
class ShowImgThread (threading.Thread):   #继承父类threading.Thread
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 \
        global proflag
        global IMAGE_list
        global boundingbox_list
        proflag = 1
        capture = cv2.VideoCapture(0)
        while (True):
        #tic()
            ret, img = capture.read()
            if ret == True:
            #img = cv2.imread('./test4.jpg')
                img = cv2.resize(img,(450,344))
                #print("img shape",img.shape)
                image = img.copy()
                del IMAGE_list[0]
                IMAGE_list.append(image)
                #print(IMAGE)
                #IMAGE = cv2.cvtColor(IMAGE, cv2.COLOR_BGR2RGB)
                if len(boundingbox_list) != 0:
                    imreadLock.acquire()
                    img = drawBoxes(img, boundingbox_list[0])
                    imreadLock.release()
                cv2.imshow('img', img)
                c = cv2.waitKey(1) & 0xff
                if c==27:
                    break
            #toc()
            #print("imshow--------------------")
	        #if boundingboxes.shape[0] > 0:
            #    error.append[imgpath]
            #print(error)
        proflag = 0
        cv2.destroyAllWindows()
        capture.release()

def compare_image(image1, image2):  #图片对比函数

    grayA = cv2.cvtColor(image1, cv2.COLOR_RGB2GRAY)
    grayB = cv2.cvtColor(image2, cv2.COLOR_RGB2GRAY)
    diff = np.sum((grayA-grayB)**2)
    score = 1-diff/450/344/255
    return score

def bbreg(boundingbox, reg):
    reg = reg.T

    # calibrate bouding boxes
    if reg.shape[1] == 1:
        #print("reshape of reg")
        pass # reshape of reg
    w = boundingbox[:,2] - boundingbox[:,0] + 1
    h = boundingbox[:,3] - boundingbox[:,1] + 1

    bb0 = boundingbox[:,0] + reg[:,0]*w
    bb1 = boundingbox[:,1] + reg[:,1]*h
    bb2 = boundingbox[:,2] + reg[:,2]*w
    bb3 = boundingbox[:,3] + reg[:,3]*h

    boundingbox[:,0:4] = np.array([bb0, bb1, bb2, bb3]).T
    #print("bb", boundingbox)
    return boundingbox

def pad(boxesA, w, h):
    boxes = boxesA.copy() # shit, value parameter!!!
    #print('#################')
    #print('boxes', boxes)
    #print('w,h', w, h)

    tmph = boxes[:,3] - boxes[:,1] + 1
    tmpw = boxes[:,2] - boxes[:,0] + 1
    numbox = boxes.shape[0]

    #print('tmph', tmph)
    #print('tmpw', tmpw)

    dx = np.ones(numbox)
    dy = np.ones(numbox)
    edx = tmpw
    edy = tmph

    x = boxes[:,0:1][:,0]
    y = boxes[:,1:2][:,0]
    ex = boxes[:,2:3][:,0]
    ey = boxes[:,3:4][:,0]

    tmp = np.where(ex > w)[0]
    if tmp.shape[0] != 0:
        edx[tmp] = -ex[tmp] + w-1 + tmpw[tmp]
        ex[tmp] = w-1

    tmp = np.where(ey > h)[0]
    if tmp.shape[0] != 0:
        edy[tmp] = -ey[tmp] + h-1 + tmph[tmp]
        ey[tmp] = h-1

    tmp = np.where(x < 1)[0]
    if tmp.shape[0] != 0:
        dx[tmp] = 2 - x[tmp]
        x[tmp] = np.ones_like(x[tmp])

    tmp = np.where(y < 1)[0]
    if tmp.shape[0] != 0:
        dy[tmp] = 2 - y[tmp]
        y[tmp] = np.ones_like(y[tmp])

    # for python index from 0, while matlab from 1
    dy = np.maximum(0, dy-1)
    dx = np.maximum(0, dx-1)
    y = np.maximum(0, y-1)
    x = np.maximum(0, x-1)
    edy = np.maximum(0, edy-1)
    edx = np.maximum(0, edx-1)
    ey = np.maximum(0, ey-1)
    ex = np.maximum(0, ex-1)

    #print("dy"  ,dy )
    #print("dx"  ,dx )
    #print("y "  ,y )
    #print("x "  ,x )
    #print("edy" ,edy)
    #print("edx" ,edx)
    #print("ey"  ,ey )
    #print("ex"  ,ex )

    #print('boxes', boxes)
    return [dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph]

def rerec(bboxA):
    # convert bboxA to square
    w = bboxA[:,2] - bboxA[:,0]
    h = bboxA[:,3] - bboxA[:,1]
    l = np.maximum(w,h).T

    #print('bboxA', bboxA)
    #print('w', w)
    #print('h', h)
    #print('l', l)
    bboxA[:,0] = bboxA[:,0] + w*0.5 - l*0.5
    bboxA[:,1] = bboxA[:,1] + h*0.5 - l*0.5
    bboxA[:,2:4] = bboxA[:,0:2] + np.repeat([l], 2, axis = 0).T
    return bboxA

def nms(boxes, threshold, type):
    """nms
    :boxes: [:,0:5]
    :threshold: 0.5 like
    :type: 'Min' or others
    :returns: TODO
    """
    if boxes.shape[0] == 0:
        return np.array([])
    x1 = boxes[:,0]
    y1 = boxes[:,1]
    x2 = boxes[:,2]
    y2 = boxes[:,3]
    s = boxes[:,4]
    area = np.multiply(x2-x1+1, y2-y1+1)
    I = np.array(s.argsort()) # read s using I

    pick = [];
    while len(I) > 0:
        xx1 = np.maximum(x1[I[-1]], x1[I[0:-1]])
        yy1 = np.maximum(y1[I[-1]], y1[I[0:-1]])
        xx2 = np.minimum(x2[I[-1]], x2[I[0:-1]])
        yy2 = np.minimum(y2[I[-1]], y2[I[0:-1]])
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        if type == 'Min':
            o = inter / np.minimum(area[I[-1]], area[I[0:-1]])
        else:
            o = inter / (area[I[-1]] + area[I[0:-1]] - inter)
        pick.append(I[-1])
        I = I[np.where( o <= threshold)[0]]
    return pick

def generateBoundingBox(map_prob, reg, scale, pyramid, threshold):
    stride = 2
    cellsize = 12
    map_prob = map_prob.T
    #print("map_prob shape",map_prob.shape)
    dx1 = reg[0,:,:].T
    dy1 = reg[1,:,:].T
    dx2 = reg[2,:,:].T
    dy2 = reg[3,:,:].T
    (x, y) = np.where(map_prob >= threshold)
    #print("x:",x)
    #print("y:",y)
    yy = y.copy()
    xx = x.copy()

    lenface = len(yy)
    #print("lenface:",lenface)
    lenpy = len(pyramid)
    w0 = pyramid[0][0]
    #print("w0:",w0)
    #print("(w0-6)/2+1:",(w0-6)/2+1)
    pyramid_reverse = []
    htmp = 0
    for i in range(1,lenpy):
        htmp += pyramid[i][1]
        pyramid_reverse.append(htmp)
    pyramid_reverse.reverse()
    #print("pyramid_reverse:",pyramid_reverse)
    label = np.zeros(lenface)+lenpy-1

    for i in range(lenface):
        if yy[i] > math.ceil((w0-6)/2)+1:
            yy[i] -= math.ceil((w0)/2)+1
            yy[i] = max(yy[i],0)
            if xx[i] < math.ceil((pyramid_reverse[lenpy-2]-6)/2)+1:
                label[i] = 1
            else:
                for j in range(1,lenpy-1):
                    if xx[i] > math.ceil((pyramid_reverse[j]-6)/2)+1:
                        xx[i] -= math.ceil((pyramid_reverse[j])/2)+1
                        xx[i] = max(xx[i],0)
                        label[i] -= j-1
                        break
        else:
            label[i] = 0

    scales_py = np.zeros(lenface)
    for i in range(0,lenface):
        scales_py[i] = scale[int(label[i])]
    #print(scales_py)
    #print("......................................")
    #print(scales_py)
    '''
    if y.shape[0] == 1: # only one point exceed threshold
        y = y.T
        x = x.T
        score = map_prob[x,y].T
        dx1 = dx1.T
        dy1 = dy1.T
        dx2 = dx2.T
        dy2 = dy2.T
        # a little stange, when there is only one bb created by PNet

        #print("1: x,y", x,y)
        a = (x*map_prob.shape[1]) + (y+1)
        x = a/map_prob.shape[0]
        y = a%map_prob.shape[0] - 1
        #print("2: x,y", x,y)
    else:
        score = map_prob[x,y]
    '''
    #print("dx1.shape", dx1.shape)
    #print('map_prob.shape', map_prob.shape)

    score = map_prob[x,y]
    reg = np.array([dx1[x,y], dy1[x,y], dx2[x,y], dy2[x,y]])

    if reg.shape[0] == 0:
        pass

    boundingbox = np.array([yy, xx]).T
    scales_py = np.vstack((scales_py,scales_py))
    scales_py = scales_py.T
    #print(boundingbox.shape)
    bb1 = np.fix((stride * (boundingbox) + 1) / scales_py).T # matlab index from 1, so with "boundingbox-1"
    bb2 = np.fix((stride * (boundingbox) + cellsize - 1 + 1) / scales_py).T # while python don't have to
    score = np.array([score])

    boundingbox_out = np.concatenate((bb1, bb2, score, reg), axis=0)

    #print('(x,y)',x,y)
    #print('score', score)
    #print('reg', reg)
    #print("generateBoundingBox over")
    return boundingbox_out.T

def drawBoxes(im, boxes):
    x1 = boxes[:,0]
    y1 = boxes[:,1]
    x2 = boxes[:,2]
    y2 = boxes[:,3]
    for i in range(x1.shape[0]):
        cv2.rectangle(im, (int(x1[i]), int(y1[i])), (int(x2[i]), int(y2[i])), (0,255,0), 1)
    return im

from time import time
_tstart_stack = []
def tic():
    _tstart_stack.append(time())
def toc(fmt="Elapsed: %s s"):
    print(fmt % (time()-_tstart_stack.pop()))

#输入原始图片，根据缩放金字塔系数生成奇偶拼接图
def img_joint(img):
    img_odd_pyramid = []
    img_even_pyramid = []
    for i in range(9):
        imgtmp = cv2.resize(img,(PNET_PYRAMID[i][0],PNET_PYRAMID[i][1]))
        #print("imgtmp shape:",imgtmp.shape)
        imgtmp = imgtmp.transpose(2,0,1)
        #print("imgtmp shape:",imgtmp.shape)

        if i%2 == 0:
            img_odd_pyramid.append(imgtmp)
        else:
            img_even_pyramid.append(imgtmp)
    # odd图片拼接
    w0 = ODD_PYRAMID[0][0]
    h0 = ODD_PYRAMID[0][1]
    w1 = ODD_PYRAMID[1][0]
    image_odd = np.zeros((3, h0, w0+w1))
    image_odd[:,0:h0,0:w0] = img_odd_pyramid[0]
    htmp = 0
    for i in range(1,len(img_odd_pyramid)):
        image_odd[:,htmp:htmp+img_odd_pyramid[i].shape[1],w0:w0+img_odd_pyramid[i].shape[2]] = img_odd_pyramid[i]
        htmp += img_odd_pyramid[i].shape[1]
    # even图片拼接
    w0 = EVEN_PYRAMID[0][0]
    h0 = EVEN_PYRAMID[0][1]
    w1 = EVEN_PYRAMID[1][0]
    image_even = np.zeros((3, h0, w0+w1))
    image_even[:,0:h0,0:w0] = img_even_pyramid[0]
    htmp = 0
    for i in range(1,len(img_even_pyramid)):
        image_even[:,htmp:htmp+img_even_pyramid[i].shape[1],w0:w0+img_even_pyramid[i].shape[2]] = img_even_pyramid[i]
        htmp += img_even_pyramid[i].shape[1]
    img_odd_even = [image_odd,image_even]
    return img_odd_even

def delete_abn(boxes, width,height):
    """delete abnormal window

    Arguments:
        boxes: a float numpy array of shape [n, 5],
            where each row is (xmin, ymin, xmax, ymax, score).
        width: a int number.
        height:a int number.
    Returns:
        list with indices of the selected boxes
    """

    # if there are no boxes, return the empty list
    if len(boxes) == 0:
        return []

    # grab the coordinates of the bounding boxes
    x1, y1, x2, y2, score = [boxes[:, i] for i in range(5)]

    area = (x2 - x1 + 1.0)*(y2 - y1 + 1.0)

    # compute intersections
    # of the box with the image

    # warning:在图片中y轴朝下
    # left top corner of intersection boxes
    ix1 = np.maximum(0, x1)
    iy1 = np.maximum(0, y1)

    # right bottom corner of intersection boxes
    ix2 = np.minimum(width, x2)
    iy2 = np.minimum(height, y2)

    # width and height of intersection boxes
    w = np.maximum(0.0, ix2 - ix1 + 1.0)
    h = np.maximum(0.0, iy2 - iy1 + 1.0)## 修改，原代码为h = np.maximum(0.0, iy2 - iy1 + 1.0)

    # intersections' areas
    inter = w * h
    overlap = inter/area

    # list of picked indices
    pick = []
    pick = np.where(overlap > 0.4)[0]

    return pick

def detect_face(img, minsize, PNet_list, RNet, ONet, threshold, fastresize, factor):
    points = []
    h = img.shape[0]
    w = img.shape[1]
    img_odd_even = img_joint(img)
    #print("img_joint start")
    #print("img_odd_even[0] shape:",img_odd_even[0].shape)
    #print("img_odd_even[1] shape:",img_odd_even[1].shape)
    # first stage
    #'''
    #print("img_odd_even[0]:",img_odd_even[0].shape)
    #img_odd_even[0] = np.swapaxes(img_odd_even[0], 1, 2)
    #img_odd_even[0] = np.swapaxes(img_odd_even[0], 0, 2)
    img_odd_even[0] = img_odd_even[0].transpose(1,2,0)
    img_odd_even[0] = np.array(img_odd_even[0], dtype = np.uint8)
    #cv2.imshow('img_odd_even[0]',img_odd_even[0])
    #ch = cv2.waitKey(50000) & 0xFF

    #img_odd_even[1] = np.swapaxes(img_odd_even[1], 1, 2)
    #img_odd_even[1] = np.swapaxes(img_odd_even[1], 0, 2)
    #print(img_odd_even[1].shape)
    img_odd_even[1] = img_odd_even[1].transpose(1,2,0)
    img_odd_even[1] = np.array(img_odd_even[1], dtype = np.uint8)
    #cv2.imshow('img_odd_even[1]',img_odd_even[1])
    #ch = cv2.waitKey(50000) & 0xFF
    #'''
    img_odd_even[0] = np.swapaxes(img_odd_even[0], 0, 2)
    img_odd_even[1] = np.swapaxes(img_odd_even[1], 0, 2)
    #img_joint is ok

    #tic()
    output0= PNet_list[0].inference(inputs=[img_odd_even[0]],data_format='nchw')
    #print("pnet0 inference over")
    #toc()
    odd_prob0 = output0[1]
    odd_conv4_2_0 = output0[0]
    odd_prob0=odd_prob0.reshape(PNET_ODD_ARR[0][1], PNET_ODD_ARR[0][2], PNET_ODD_ARR[0][3])
    odd_conv4_2_0=odd_conv4_2_0.reshape(PNET_ODD_ARR[1][1], PNET_ODD_ARR[1][2], PNET_ODD_ARR[1][3])
    odd_boxes = generateBoundingBox(odd_prob0[1,:,:], odd_conv4_2_0, ODD_SCALES,ODD_PYRAMID,threshold[0])
    #print("odd_boxes:",odd_boxes.shape)

    #tic()
    output1= PNet_list[1].inference(inputs=[img_odd_even[1]],data_format='nchw')
    #print("pnet inference1 over")
    #toc()
    even_prob1 = output1[1]
    #print("even_prob1 shape:",even_prob1.shape)
    even_conv4_2_1 = output1[0]
    even_prob1= even_prob1.reshape(PNET_EVEN_ARR[0][1], PNET_EVEN_ARR[0][2], PNET_EVEN_ARR[0][3])
    #print(even_prob1[1,:,:])
    even_conv4_2_1=even_conv4_2_1.reshape(PNET_EVEN_ARR[1][1], PNET_EVEN_ARR[1][2], PNET_EVEN_ARR[1][3])
    even_boxes = generateBoundingBox(even_prob1[1,:,:], even_conv4_2_1, EVEN_SCALES,EVEN_PYRAMID,threshold[0])
    #print("even_boxes:",even_boxes.shape)
    total_boxes = np.concatenate((odd_boxes, even_boxes), axis=0)
    if total_boxes.shape[0] != 0:
        pick = delete_abn(total_boxes, 450, 344)
    else:
        pick = []
    if len(pick) > 0 :
        total_boxes = total_boxes[pick, :]

    #print(total_boxes.shape)
    #print("pnet over")

    numbox = total_boxes.shape[0]
    #print("pnet numbox:",numbox)
    if numbox > 0:
        # nms
        pick = nms(total_boxes, 0.4, 'Union')
        total_boxes = total_boxes[pick, :]

        # revise and convert to square
        regh = total_boxes[:,3] - total_boxes[:,1]
        regw = total_boxes[:,2] - total_boxes[:,0]
        t1 = total_boxes[:,0] + total_boxes[:,5]*regw
        t2 = total_boxes[:,1] + total_boxes[:,6]*regh
        t3 = total_boxes[:,2] + total_boxes[:,7]*regw
        t4 = total_boxes[:,3] + total_boxes[:,8]*regh
        t5 = total_boxes[:,4]
        total_boxes = np.array([t1,t2,t3,t4,t5]).T

        total_boxes = rerec(total_boxes) # convert box to square
        #print("[4]:",total_boxes.shape[0])

        total_boxes[:,0:4] = np.fix(total_boxes[:,0:4])
        #print("[4.5]:",total_boxes.shape[0])
        #print(total_boxes)
        [dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph] = pad(total_boxes, w, h)
        '''
        print(dy)
        print(edy)
        print(dx)
        print(edx)
        print(y)
        print(ey)
        print(x)
        print(ex)
        '''
        #print(tmpw)
        #print(tmph)

    numbox = total_boxes.shape[0]
    #print("window number after pnet+nms:",numbox)
    #####
    # 1 #
    #####
    if numbox > 0:
        # second stage
        #tempimg = np.load('tempimg.npy')

        # construct input for RNet
        out_conv5_2=np.zeros((0,4))
        tempimg = np.zeros((numbox, 24, 24, 3)) # (24, 24, 3, numbox)
        tmptarget = np.zeros((24, 24,3))
        score=[]
        #out_prob=0
        '''
        out_conv5_2=np.zeros((0,4))
        img_test = cv2.imread('rnet-24_24_7.jpg')
        print("load img_test successfully")
        cv2.imshow('img_test',img_test)
        ch = cv2.waitKey(10000) & 0xFF
        img_test = np.swapaxes(img_test, 0, 2)
        img_test = np.array([img_test], dtype = np.uint8)
        out=RNet.inference(inputs=[img_test],data_format='nchw')
        print("pent is fine")

        tmp00 = np.zeros((24,24,3))
        tmp00[0:24, 0:24,:] = img[24:48, 24:48,:]
        tmptarget00 = np.zeros((24, 24,3))
        tmptarget00 = cv2.resize(tmp00, (24, 24))
        tmptarget00 = np.array(tmptarget00, dtype = np.uint8)
        print("tmptarget00 shape:",tmptarget00.shape)
        cv2.imshow('tmptarget00',tmptarget00)
        ch = cv2.waitKey(10000) & 0xFF
        print("try successfully")
        cv2.imshow('img',img)#######################################
        ch = cv2.waitKey(10000) & 0xFF
        '''
        for k in range(numbox):
            tmp = np.zeros((int(tmph[k]) +1, int(tmpw[k]) + 1,3))
            tmp[int(dy[k]):int(edy[k])+1, int(dx[k]):int(edx[k])+1,:] = img[int(y[k]):int(ey[k])+1, int(x[k]):int(ex[k])+1,:]
            tmptarget = cv2.resize(tmp, (24, 24))
            tmptarget = np.array(tmptarget, dtype = np.uint8)
            tmptarget = np.swapaxes(tmptarget, 0, 2)
            #print("tmptarget shape:",tmptarget.shape)
            #print("tmptarget type",type(tmptarget))
            #cv2.imshow('tmptarget',tmptarget)
            #ch = cv2.waitKey(10000) & 0xFF

            #tmptarget = np.array([tmptarget], dtype = np.uint8)
            #print("tmptarget type",type(tmptarget))
            #print("tmptarget shape:",tmptarget.shape)
            #print(tmptarget)
            #print("before pnet.inference")
            out=RNet.inference(inputs=[tmptarget],data_format='nchw')
            out_prob1=out[1]
            score=np.append(score,out_prob1[:,1])
            out_conv5_2=np.concatenate((out_conv5_2,out[0]),axis=0)

        pass_t = np.where(score>threshold[1])[0]
        score =  np.array([score[pass_t]]).T
        total_boxes = np.concatenate( (total_boxes[pass_t, 0:4], score), axis = 1)

        mv = out_conv5_2[pass_t, :].T
        if total_boxes.shape[0] > 0:
            pick = nms(total_boxes, 0.5, 'Union')
            #print('pick', pick)
            if len(pick) > 0 :
                total_boxes = total_boxes[pick, :]
                #print("[6]:",total_boxes.shape[0])
                total_boxes = bbreg(total_boxes, mv[:, pick])
                #print("[7]:",total_boxes.shape[0])
                total_boxes = rerec(total_boxes)
                #print("[8]:",total_boxes.shape[0])
        #print("rnet over")
        #####
        # 2 #
        #####

        numbox = total_boxes.shape[0]
        #print("rnet numbox is %d",numbox)
        if numbox > 0:
            # third stage

            total_boxes = np.fix(total_boxes)
            [dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph] = pad(total_boxes, w, h)

            tempimg = np.zeros((numbox, 48, 48, 3))
            tmptarget = np.zeros((3, 48, 48))
            out_conv6_2=np.zeros((0,4))
            out_conv6_3=np.zeros((0,10))
            score = []
            for k in range(numbox):
                tmp = np.zeros((int(tmph[k]), int(tmpw[k]),3))
                tmp[int(dy[k]):int(edy[k])+1, int(dx[k]):int(edx[k])+1] = img[int(y[k]):int(ey[k])+1, int(x[k]):int(ex[k])+1]
                tempimg[k,:,:,:] = cv2.resize(tmp, (48, 48))
                tmptarget = np.swapaxes(tempimg[k], 0, 2)
                tmptarget = np.array([tmptarget], dtype = np.uint8)
                #tic()
                out=ONet.inference(inputs=[tmptarget],data_format='nchw')
                #toc()
                out_conv6_3=np.concatenate((out_conv6_3,out[1]),axis=0)
                out_conv6_2=np.concatenate((out_conv6_2,out[0]),axis=0)
                score=np.append(score,out[2][:,1])
            #tempimg = (tempimg-127.5)*0.0078125 # [0,255] -> [-1,1]

            # ONet
            points = out_conv6_3
            pass_t = np.where(score>threshold[2])[0]#csqerr
            points = points[pass_t, :]
            score = np.array([score[pass_t]]).T
            #print("total_boxes shape ",total_boxes.shape)
            total_boxes = np.concatenate( (total_boxes[pass_t, 0:4], score), axis=1)
            #print("[9]:",total_boxes.shape[0])

            mv = out_conv6_2[pass_t, :].T
            w = total_boxes[:,3] - total_boxes[:,1] + 1
            h = total_boxes[:,2] - total_boxes[:,0] + 1

            points[:, 0:5] = np.tile(w, (5,1)).T * points[:, 0:5] + np.tile(total_boxes[:,0], (5,1)).T - 1
            points[:, 5:10] = np.tile(h, (5,1)).T * points[:, 5:10] + np.tile(total_boxes[:,1], (5,1)).T -1
            #print("onet total_boxes.shape[0] ",total_boxes.shape[0])
            if total_boxes.shape[0] > 0:
                total_boxes = bbreg(total_boxes, mv[:,:])
                #print("[10]:",total_boxes.shape[0])
                pick = nms(total_boxes, 0.7, 'Min')

                #print(pick)
                if len(pick) > 0 :
                    total_boxes = total_boxes[pick, :]
                    #print("[11]:",total_boxes.shape[0])
                    points = points[pick, :]

    #####
    # 3 #
    #####
    #print("3:",total_boxes.shape)
    #print("face_dect over")
    return total_boxes, points

def init_pnet():
    list = []
    rknn_odd_name = "PNet_%d_%d.rknn" %(406,207);
    pnet_odd_rknn = RKNN() #verbose=True,verbose_file='./mobilenet_build.log'
    pnet_odd_rknn.load_rknn(rknn_odd_name)
    ret = pnet_odd_rknn.init_runtime()
    if ret != 0:
        #print('Init pnet runtime environment failed')
        exit(ret)
    list.append(pnet_odd_rknn)

    rknn_even_name = "PNet_%d_%d.rknn" %(289,147);
    pnet_even_rknn = RKNN() #verbose=True,verbose_file='./mobilenet_build.log'
    pnet_even_rknn.load_rknn(rknn_even_name)
    ret = pnet_even_rknn.init_runtime()
    if ret != 0:
        #print('Init pnet runtime environment failed')
        exit(ret)
    list.append(pnet_even_rknn)

    return list

def main():

    imgthread = ShowImgThread()
    winthread = MtcnnThread()
    imgthread.start()
    print("imgthread start")
    winthread.start()
    print("winthread start")
    imgthread.join()
    #print(IMAGE)
    winthread.join()
    #cv2.destroyAllWindows()

if __name__ == "__main__":
    main()


from django.urls import path

from .views import (
    SignupAPIView,
    SigninAPIView,
    DeleteUserView,
    ProjectMixins,
    ProjectDetailMixins
)

urlpatterns = [
    path("users/signup/", SignupAPIView.as_view(), name='signup'),
    path("users/signin/", SigninAPIView.as_view(), name='signin'),
    path("users/<int:pk>/", DeleteUserView.as_view(), name='user-delete'),
    path("projects/", ProjectMixins.as_view(), name='project-c'),
    path('projects/<int:pk>/', ProjectDetailMixins.as_view(), name='project-rud'),
]


import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision.io import read_image
from torchvision.ops import masks_to_boxes

def show_mask(mask, ax, random_color=False):
    if random_color:
        color = np.concatenate([np.random.random(3), np.array([0.6])], axis=0)
    else:
        color = np.array([30/255, 144/255, 255/255, 0.6])
    h, w = mask.shape[-2:]
    mask_image = mask.reshape(h, w, 1) * color.reshape(1, 1, -1)
    ax.imshow(mask_image)

def show_points(coords, labels, ax, marker_size=375):
    pos_points = coords[labels==1]
    neg_points = coords[labels==0]
    ax.scatter(pos_points[:, 0], pos_points[:, 1], color='green', marker='*', s=marker_size, edgecolor='white', linewidth=1.25)
    ax.scatter(neg_points[:, 0], neg_points[:, 1], color='red', marker='*', s=marker_size, edgecolor='white', linewidth=1.25)

def show_box(box, ax):
    x0, y0 = box[0], box[1]
    w, h = box[2] - box[0], box[3] - box[1]
    ax.add_patch(plt.Rectangle((x0, y0), w, h, edgecolor='green', facecolor=(0,0,0,0), lw=2))

def prepare_image(image, transform, device):
    image = transform.apply_image(image)
    image = torch.as_tensor(image, device=device.device)
    return image.permute(2, 0, 1).contiguous()

def get_torch_prompts_labels(xycoo, prompt_size, device):
    n = min(len(xycoo), prompt_size)
    xy_coo_array = [[xycoo[i]["x"],xycoo[i]["y"]] for i in range(n)]
    xy_coo_array = [xy_coo_array]
    xy_label_array = [[1 for _ in range(n)]]
    xy_coo_array = torch.tensor(xy_coo_array, device = device)
    xy_label_array = torch.tensor(xy_label_array, device = device)
    return xy_coo_array, xy_label_array

def get_boxes(mask_path, device):
    mask = read_image(mask_path)
    boxes = masks_to_boxes(mask)
    boxes.to(device)
    return boxes


import csv, re, os
from typing import List, Dict, Tuple
from cProfile import Profile
from pstats import Stats
from vacancy import InputConnect
from statistic import Report, get_statistic, get_salary_level, get_count_vacancies, print_statistic
from Task322 import get_stat_by_year

prof = Profile()
prof.disable()

class DataSet:
    """
    Класс для формирования списка вакансий.

    Attributes:
        file_name (str): Название файла.
        vacancies_objects (List[Vacancy]): Сформированный список вакансий.

    """

    def __init__(self, file_name: str) -> None:
        """
        Инициализирует объект DataSet.

        Args:
            file_name (str): Имя файла.
        """
        self.file_name = file_name
        self.vacancies_objects = [Vacancy(vac) for vac in self.csv_filer(*self.csv_reader(file_name))]

    def clean_string(self, raw_html: str) -> str:
        """
        Очищает строку от HTML кода

        Args:
            raw_html (str): Строка, которую нужно очистить

        Returns:
            str: Очищенная строка.

        >>> DataSet('vacancies.csv').clean_string('
Группа компаний «МИАКОМ»
')
        'Группа компаний «МИАКОМ»'
        """
        result = re.sub("<.*?>", '', raw_html)
        return result if '\n' in raw_html else " ".join(result.split())

    def csv_reader(self, file_name: str) -> Tuple[List[str], List[List[str]]]:
        """
        Считывает данные из файла

        Args:
            file_name (str): Название файла.

        Returns:
            Tuple[List[str], List[List[str]]]: Название колонок и соответствующие им данные по каждой вакансии.
        """
        reader = csv.reader(open(file_name, encoding='utf_8_sig'))
        data_base = [line for line in reader]
        return data_base[0], data_base[1:]

    def csv_filer(self, list_naming: List[str], reader: List[List[str]]) -> List[Dict[str, str]]:
        """
        Преобразует данные в список словарей, где словарь содержит информацию об одной вакансии.

        Args:
            list_naming (List[str]): Поля вакансии
            reader (List[List[str]]): Данные из файла

        Returns:
            List[Dict[str, str]]: Список словарей.
        """
        new_vacans_list = list(filter(lambda vac: (len(vac) == len(list_naming) and vac.count('') == 0), reader))
        return [dict(zip(list_naming, map(self.clean_string, vac))) for vac in new_vacans_list]

class Vacancy:
    """
    Класс для представления вакансии

    Attributes:
        name (string): Название вакансии
        description (str): Описание вакансии
        key_skills (List[str]): Ключевые навыки для вакансии
        experience_id (str): Требуемый опят для вакансии
        premium (str): Атрибут, отвечающий за премиальность вакансии
        employer_name (str): Название компании, где есть вакансия
        salary (Salary): Информация о зарплате
        area_name (str): Название города
        published_at (str): Дата публикации вакансии
    """

    def __init__(self, dict_vac: Dict[str, str]):
        """
        Инициализирует объект Vacancy, проверяя наличие некоторых полей для вакансии

        Args: dict_vac (Dict[str, str]): Словарь, хранящий информацию о вакансии. Ключи - это названия полей,
        значения - информация о вакансии по соответствующему полю.
        """
        self.name = dict_vac['name']
        self.description = 'Нет данных' if 'description' not in dict_vac.keys() else dict_vac['description']
        self.key_skills = 'Нет данных' if 'key_skills' not in dict_vac.keys() else dict_vac['key_skills'].split('\n')
        self.experience_id = 'Нет данных' if 'experience_id' not in dict_vac.keys() else dict_vac['experience_id']
        self.premium = 'Нет данных' if 'premium' not in dict_vac.keys() else dict_vac['premium']
        self.employer_name = 'Нет данных' if 'employer_name' not in dict_vac.keys() else dict_vac['employer_name']
        salary_gross = 'Нет данных' if 'salary_gross' not in dict_vac.keys() else dict_vac['salary_gross']
        self.salary = Salary(dict_vac['salary_from'], dict_vac['salary_to'], salary_gross, dict_vac['salary_currency'])
        self.area_name = dict_vac['area_name']
        self.published_at = dict_vac['published_at']

class Salary:
    """
    Класс для представления зарплаты.

    Attributes:
        salary_from (str): Нижняя граница зарплаты
        salary_to (str): Верхняя граница зарплаты
        salary_gross (str): Наличие налогов
        salary_currency (str): Валюта оклада

    """

    def __init__(self, salary_from, salary_to, salary_gross, salary_currency):
        """
        Инициализирует объект Salary
        Args:
            salary_from (str): Нижняя граница зарплаты
            salary_to (str): Верхняя граница зарплаты
            salary_gross (str): Наличие налогов
            salary_currency (str): Валюта оклада
        """
        self.salary_from = salary_from
        self.salary_to = salary_to
        self.salary_gross = salary_gross
        self.salary_currency = salary_currency

    def to_RUB(self, salary: float) -> float:
        """
        Вычисляет зарплату в рублях, при помощи словаря - currency_to_rub.

        Args:
            salary (float): Зарплата в другой валюте.

        Returns:
            float: Зарплата в рублях.

        # >>> Salary('10', '1000', 'true', 'EUR').to_RUB(1000.0)
        # 59900.0
        # >>> Salary('10', '1000', 'true', 'RUR').to_RUB(1000)
        # 1000.0
        # >>> Salary('10', '1000', 'true', 'QWE').to_RUB(1000.0)
        >>> Salary('10', '1000', 'false', 'EUR').to_RUB(559)
        33484.1
        >>> Salary('10', '1000', 'true', 'RUR').to_RUB(500)
        500.0
        >>> Salary('10', '1000', 'true', 'QWE').to_RUB(1000.0)
        Traceback (most recent call last):
        ...
        KeyError: 'QWE'
        """
        return float(salary * currency_to_rub[self.salary_currency])

currency_to_rub = {"AZN": 35.68,
                   "BYR": 23.91,
                   "EUR": 59.90,
                   "GEL": 21.74,
                   "KGS": 0.76,
                   "KZT": 0.13,
                   "RUR": 1,
                   "UAH": 1.64,
                   "USD": 60.66,
                   "UZS": 0.0055, }

translation = {"name": "Название",
               "description": "Описание",
               "key_skills": "Навыки",
               "experience_id": "Опыт работы",
               "premium": "Премиум-вакансия",
               "employer_name": "Компания",
               "salary_from": "Нижняя граница вилки оклада",
               "salary_to": "Верхняя граница вилки оклада",
               "salary_gross": "Оклад указан до вычета налогов",
               "salary_currency": "Идентификатор валюты оклада",
               "area_name": "Название региона",
               "published_at": "Дата публикации вакансии",
               "Оклад": "Оклад",
               "Нет данных": "Нет данных",
               "True": "Да",
               "TRUE": "Да",
               "False": "Нет",
               "FALSE": "Нет",
               "noExperience": "Нет опыта",
               "between1And3": "От 1 года до 3 лет",
               "between3And6": "От 3 до 6 лет",
               "moreThan6": "Более 6 лет",
               "AZN": "Манаты",
               "BYR": "Белорусские рубли",
               "EUR": "Евро",
               "GEL": "Грузинский лари",
               "KGS": "Киргизский сом",
               "KZT": "Тенге",
               "RUR": "Рубли",
               "UAH": "Гривны",
               "USD": "Доллары",
               "UZS": "Узбекский сум"}

reverse_translation = {"Название": "name",
                       "Описание": "description",
                       "Навыки": "key_skills",
                       "Опыт работы": "experience_id",
                       "Премиум-вакансия": "premium",
                       "Компания": "employer_name",
                       "Оклад": "Оклад",
                       "Название региона": "area_name",
                       "Дата публикации вакансии": "published_at",
                       "Идентификатор валюты оклада": "salary_currency"}

rang_experience_id = {"noExperience": 0,
                      "between1And3": 1,
                      "between3And6": 2,
                      "moreThan6": 3}

def get_year(date_vac) -> str:
    """
    Возвращает год от даты.

    Args:
        date_vac (str): Дата публикации.

    Returns:
        str: Год публикации.
    """
    return date_vac[:4]

def exit_from_file(message: str):
    """
    Метод для выхода из программы.

    Args:
        message (str): Сообщение при выходе из программы
    """
    print(message)
    exit()

if __name__ == '__main__':
    type_output = input('Введите данные для печати: ')
    file_name = input('Введите название файла: ')
    if os.stat(file_name).st_size == 0:
        exit_from_file('Пустой файл')
    prof.enable()
    data = DataSet(file_name)
    prof.disable()
    if len(data.vacancies_objects) == 0:
        exit_from_file('Нет данных')
    if type_output == 'Статистика':
        vacancy_name = input('Введите название профессии: ')
        prof.enable()
        for vac in data.vacancies_objects:
            vac.published_at = get_year(vac.published_at)
        dict_cities = {}
        for vac in data.vacancies_objects:
            if vac.area_name not in dict_cities.keys():
                dict_cities[vac.area_name] = 0
            dict_cities[vac.area_name] += 1
        needed_vacancies_objects = list(
            filter(lambda vac: int(len(data.vacancies_objects) * 0.01) <= dict_cities[vac.area_name],
                   data.vacancies_objects))
        rp = Report()
        stat_by_years = get_stat_by_year(file_name, vacancy_name)
        print('Динамика уровня зарплат по годам:', stat_by_years[0])
        print('Динамика уровня зарплат по годам для выбранной профессии:', stat_by_years[1])
        print('Динамика количества вакансий по годам:', stat_by_years[2])
        print('Динамика количества вакансий по годам для выбранной профессии:', stat_by_years[3])
        list_statistic = [stat_by_years[0],
                          stat_by_years[1],
                          stat_by_years[2],
                          stat_by_years[3],
                          print_statistic(get_salary_level(needed_vacancies_objects, 'area_name').items(), 1,
                                          'Уровень зарплат по городам (в порядке убывания): ', True, 10),
                          print_statistic(get_count_vacancies(needed_vacancies_objects, 'area_name', data).items(), 1,
                                          'Доля вакансий по городам (в порядке убывания): ', True, 10)]
        rp.generate_excel(vacancy_name, list_statistic)
        rp.generate_image(vacancy_name, list_statistic)
        rp.generate_pdf(vacancy_name)
        prof.disable()
    elif type_output == 'Вакансии':
        parameter = input('Введите параметр фильтрации: ')
        sorting_param = input('Введите параметр сортировки: ')
        is_reversed_sort = input('Обратный порядок сортировки (Да / Нет): ')
        interval = list(map(int, input('Введите диапазон вывода: ').split()))
        columns = input('Введите требуемые столбцы: ')
        prof.enable()
        outer = InputConnect(parameter, sorting_param, is_reversed_sort, interval, columns)
        outer.check_parameters()
        outer.print_vacancies(data.vacancies_objects)
        prof.disable()
    prof.dump_stats('async')
    with open('async_stats.txt', 'wt') as _output:
        stats = Stats('async', stream=_output)
        stats.sort_stats('cumulative', 'time')
        stats.print_stats()


import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
plt.style.use('fivethirtyeight')

def fit_model(x_train, y_train):
    # Fits a linear regression to find the actual b and w that minimize the loss
    regression = LinearRegression()
    regression.fit(x_train, y_train)
    b_minimum, w_minimum = regression.intercept_[0], regression.coef_[0][0]
    return b_minimum, w_minimum

def figure1(x_train, y_train, x_val, y_val):
    fig, ax = plt.subplots(1, 2, figsize=(12, 6))

    ax[0].scatter(x_train, y_train)
    ax[0].set_xlabel('x')
    ax[0].set_ylabel('y')
    ax[0].set_ylim([0, 3.1])
    ax[0].set_title('Generated Data - Train')

    ax[1].scatter(x_val, y_val, c='r')
    ax[1].set_xlabel('x')
    ax[1].set_ylabel('y')
    ax[1].set_ylim([0, 3.1])
    ax[1].set_title('Generated Data - Validation')
    fig.tight_layout()

    return fig, ax

def figure3(x_train, y_train):
    b_minimum, w_minimum = fit_model(x_train, y_train)
    # Generates evenly spaced x feature
    x_range = np.linspace(0, 1, 101)
    # Computes yhat
    yhat_range = b_minimum + w_minimum * x_range

    fig, ax = plt.subplots(1, 1, figsize=(6, 6))
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_ylim([0, 3.1])

    # Dataset
    ax.scatter(x_train, y_train)
    # Predictions
    ax.plot(x_range, yhat_range, label='Final model\'s predictions', c='k', linestyle='--')

    # Annotations
    ax.annotate('b = {:.4f} w = {:.4f}'.format(b_minimum, w_minimum), xy=(.4, 1.5), c='k', rotation=34)
    ax.legend(loc=0)
    fig.tight_layout()
    return fig, ax


def check(data):
    s = [] # 호출할 떄마다 초기화해야되니까
    for i in data:
        if i == '(' or i == '{':
            s.append(i)
        elif i == ')' or i == '}':
            if data[-1] == i:
                s.pop()
            else:
                return 0
    if s:
        return 0
    else:
        return 1

import sys
sys.stdin = open()

T = int(input())
for test_case in range(T):
    data = input()

    print(check(data))


#!/usr/bin/env python
def fit_lambda(root='j100025+021706', newfunc=True, bucket_name='aws-grivam'):
    import time
    import os
    import numpy as np
    import boto3
    import json

    from grizli_aws.fit_redshift_single import run_grizli_fit

    beams, files = get_needed_paths(root, bucket_name=bucket_name)
    if len(beams) == 0:
        print('{0}: No beams to fit'.format(root))

    for obj in beams:
        print(obj)
        event = {
              's3_object_path': obj,
              'verbose':      "True",
              'skip_started': "True",
              'check_wcs' :   "False",
              'bucket' : bucket_name
            }

        try:
            run_grizli_fit(event)
        except:
            pass

    # Status again to check products
    beams, files = get_needed_paths(root)

def get_needed_paths(root, get_string=False, bucket_name='aws-grivam'):
    """
    Get the S3 paths of the "beams.fits" files that still need to be fit.
    """
    import boto3
    import time

    s3 = boto3.resource('s3')
    s3_client = boto3.client('s3')
    bkt = s3.Bucket(bucket_name)

    files = [obj.key for obj in bkt.objects.filter(Prefix='Pipeline/{0}/Extractions/'.format(root))]

    beams = []
    logs = []
    full = []
    start = []

    for file in files:
        if 'beams.fits' in file:
            beams.append(file)

        if 'log_par' in file:
            logs.append(file)

        if 'start.log' in file:
            start.append(file)

        if 'full.fits' in file:
            full.append(file)

    label = '{0} / {1} / Nbeams: {2}, Nfull: {3}, Nlog: {4}, Nstart: {5}'.format(root, time.ctime(), len(beams), len(full), len(logs), len(start))
    if get_string:
        return label

    print(label)

    for i in range(len(beams))[::-1]:
        test = (beams[i].replace('.beams.fits', '.full.fits') in full)
        test |= (beams[i].replace('.beams.fits', '.start.log') in start)
        if test:
            beams.pop(i)

    return beams, files

if __name__ == "__main__":
    import sys
    import numpy as np
    from grizli import utils
    from grizli.pipeline import auto_script
    utils.set_warnings()

    if len(sys.argv) < 2:
        print('Usage: fit_redshift_lambda.py {field}')
        exit

    root = sys.argv[1]
    if len(sys.argv) == 3:
        newfunc = bool(sys.argv[2].lower() == 'true')
    else:
        newfunc = False

    bucket_name='aws-grivam'
    bucket_name='grizli-grism'

    fit_lambda(root=root, newfunc=newfunc, bucket_name=bucket_name)


import socket

# host = "172.16.98.38"

class Client:
    def __init__(self, host = "172.16.98.38", port = 8080) -> None:
        self.s = socket.socket()

        self.s.connect((host, port))
        print("connected")

    def make_req(self, com):
        self.s.send(com.encode('utf8'))

    def read_sock(self, filename):

        # filename = "image.jpeg"
        self.make_req("getim")
        # s.send("get_im".encode('utf8'))

        file = open(filename, "wb")
        while True:
            file_data = self.s.recv(4096)
            file.write(file_data)
            if file_data[-1] == 64:
                break
        file.close()
        print("file downloaded")

# print(file_data)
# cv2.imshow("Camera", im)
# cv2.waitKey(1)


import csv
import os

budget_data_csv = "budget_data.csv"

# declare my variables
months = 0
money = 0
profit = 0
changes = []
greatest_increase = ['', 0]
greatest_decrease = ['', 0]

#open csv

with open(budget_data_csv, "r") as csv_file:
    csv_reader = csv.reader(csv_file, delimiter=",")

    #skip first row of data
    header = next(csv_reader)

    #loop through rows
    for row in csv_reader:
        months = months + 1
        money =  money + int(row[1])

        current_profit = int(row[1])
        change = current_profit - profit
        changes.append(change)
        profit = current_profit

        #greatest increase and decrease

        if change > greatest_increase[1]:
            greatest_increase = [row[0], change]

        if change < greatest_decrease[1]:
            greatest_decrease = [row[0], change]

average_change = sum(changes) / len(changes)

#print results to screen

print("Financial Analysis")
print("----------------------------")
print(f"Total Months: {months}")
print(f"Total Money: ${money}")
print(f"Average Change: ${average_change:.2f}")
print(f"Greatest Increase in Profits: {greatest_increase[0]} (${greatest_increase[1]})")
print(f"Greatest Decrease in Profits: {greatest_decrease[0]} (${greatest_decrease[1]})")

text_file = "financial_analysis.txt"

with open(text_file, "w") as file:
    # type results to text file
    file.write("Financial Analysis\n")
    file.write("----------------------------\n")
    file.write(f"Total Months: {months}\n")
    file.write(f"Total Money: ${money}\n")
    file.write(f"Average Change: ${average_change:.2f}\n")
    file.write(f"Greatest Increase in Profits: {greatest_increase[0]} (${greatest_increase[1]})\n")
    file.write(f"Greatest Decrease in Profits: {greatest_decrease[0]} (${greatest_decrease[1]})\n")


import configparser
import csv

from src.web_monitor import web_monitor

def read_config():
    config = configparser.ConfigParser()
    config.read('config.ini')
    with open("websites.txt", "r") as web_config:
        tsv_reader = csv.DictReader(web_config, delimiter='\t')
        web_dict = {}
        for row in tsv_reader:
            web_dict[row['website']] = row['content_file']

    config['url_content'] = web_dict
    return config

def main():
    config = read_config()
    web_monitor.main(config)

if __name__ == '__main__':
    main()