#import csv
import cv2
import time
import random
import imutils
import numpy as np
from PIL import ImageGrab
import pydirectinput as pdi
from PIL import Image, ImageOps

say = 0

global soltara
soltara = 63
global sagtara
sagtara = 64

def tara():
    global sagtara
    sagtara = 64
    global soltara
    soltara = 64
    pixel = img[30, sagtara]

    minLineLength = 5
    maxLineGap = 1
    lines = cv2.HoughLinesP(img,1,np.pi/180,100,minLineLength,maxLineGap)
    if lines is not None:
        list1 = []
        list2 = []

        for x in range(0, len(lines)):
            for x1,y1,x2,y2 in lines[x]:
                list1.append((x1,y1))
                list2.append((x2,y2))

            for i in range(0, int(len(list1) / 2)):
                sequence = [i for i in range(0, len(list2))]
                q = random.choice(sequence)
                mesafe = list1[i][0] - list2[q][0]
                if mesafe < 0:
                    mesafe = mesafe * -1
                if mesafe < 20:
                    cv2.line(img,list1[i],list2[q],(255,255,255),2)

    while sagtara < 127:
        pixel = img[50, sagtara]
        if pixel == 0:
            sagtara = sagtara + 1
        else:
            break

    while soltara > 1:
        pixel = img[50, soltara]
        if pixel == 0:
            soltara = soltara - 1
        else:
            break

while(True):
    global img
    global gray
    # Capture frame-by-frame
    img = ImageGrab.grab(bbox=(0,0,1280,720)) #ets tam ekran
    img = np.array(img)

    height, width, channels = img.shape

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img = cv2.medianBlur(img, 5)
    img = cv2.Canny(img, 100, 200)

    img = img[int(height / 3):int((height / 3) * 2), int((width / 8) * 2):int((width / 8) * 6)]
    height, width = img.shape
    img = img[int((height / 8) * 6):height, 0:width]

    img = cv2.resize(img, (128, 128))
    kernel = np.ones((5,2),np.uint8)
    img = cv2.dilate(img,kernel,iterations = 3)

    if say > 100:
        tara()

    if say == 200:
        print('\a')

    say = say + 1

    cikti = cv2.line(img,(soltara, 50), (sagtara, 50), (255, 255, 255), 1)
    orta = int((soltara + sagtara) / 2)
    #sure = int((64 - orta) / 100)
    #if sure < 0:
    #    sure = sure * -1

    if say > 100:
        if soltara < 5 or sagtara > 123:
            print("x")
        else:
            if orta < 60:
                pdi.press("a")
            elif orta > 68:
                pdi.press("d")

    # Display the resulting frame
    cikti = cv2.resize(cikti, (512, 512))
    cv2.imshow('wow',cikti)
    #cv2.imshow('wow2',araba)

    if sagtara == 128:
        sagtara = 64

    if soltara == 0:
        soltara = 64

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

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()


"""Musical entity representation and manipulation.

MIDI message bytes are defined by the `MMA MIDI Specifications`_ for the sake
of compatibility with the many synthesizers and applications that adhere.

The current implementation only uses MIDI channel 1, but there are actually
16 channels available. For instance, to send a note-on message to channel 2
instead of channel 1, the note-on status byte should be 0x91 instead of 0x90.
To send a control change to channel 16 instead of channel 1, the control status
byte should be 0xBF instead of 0xB0.

.. _MMA MIDI Specifications
   https://www.midi.org/specifications/category/reference-tables
"""

import music21
import numpy as np

import muser.utils

N_PITCHES = 128
VELOCITY_LO = 0
VELOCITY_HI = 127
VELOCITY_LIMS = (VELOCITY_LO, VELOCITY_HI + 1)
"""MIDI constants."""

STATUS_BYTES = dict(
    NOTE_ON=0x90, ON=0x90,
    NOTE_OFF=0x80, OFF=0x80,
    CONTROL=0xB0,
)
CONTROL_BYTES = dict(
    PEDAL_SUSTAIN=0x40,
    PEDAL_PORTAMENTO=0x41,
    PEDAL_SOSTENUTO=0x42,
    PEDAL_SOFT=0x43,
    RESET_ALL_CONTROLLERS=0x79,
    ALL_NOTES_OFF=0x7B,
)
"""MIDI message (event) bytes."""

PITCH_LIMS = dict(
    midi=(0, 127),
    piano=(21, 108),
)
PITCH_RANGES = {name: np.arange(lim[0], lim[1] + 1)
                for name, lim in PITCH_LIMS.items()}
"""MIDI pitch (note number) limits and ranges for different instruments."""

def notation_to_notes(notation):
    """ Parse a notation string and return a list of Note objects.

    Args:
        notation (str): Melody notated in a music21-parsable string format.

    Returns:
        notes (list): Sequence of ``music21.note.Note`` objects.
    """
    sequence = music21.converter.parse(notation)
    notes = list(sequence.flat.getElementsByClass(music21.note.Note))
    return notes

def random_note(pitch=None, pitch_range='midi', velocity=None,
                velocity_lims=VELOCITY_LIMS):
    """Return a ``music21.note.Note`` with specified or randomized attributes.

    Args:
        pitch (int or str): Pitch of the returned ``music21.note.Note``.
            A MIDI note number or music21-parsable string. Randomly assigned
            if ``None`` (default).
        pitch_range (iterable or string): Vector of MIDI pitches for random
            selection. May be a key from ``PITCH_RANGES`` corresponding to a
            pre-defined range vector.
        velocity (int): Defined velocity. Randomly assigned if ``None``.
        velocity_lims (tuple): Range of velocities for random assignment.

    Returns:
        note (music21.note.Note): Note object with assigned properties.
    """

    if pitch is None:
        pitch_range = muser.utils.key_check(pitch_range, PITCH_RANGES, 'lower')
        pitch = np.random.choice(pitch_range)
    if velocity is None:
        velocity = np.random.randint(*velocity_lims)
    note = music21.note.Note(pitch)
    note.volume.velocity = velocity
    return note

def random_chord(chord_size=3, pitch_range='midi', velocity=None,
                 velocity_lims=VELOCITY_LIMS, unique=True):
    """Return a music21 Chord object with random pitches and velocity.

    TODO: MIDI velocity (int) or normalized velocity (/1.0)

    Args:
        chord_size (int): Number of notes in the returned chord.
        pitch_range (iterable or str): Vector of MIDI pitches for
            random selection. May be a key from ``PITCH_RANGES``
            corresponding to a pre-defined range.
        velocity (int): MIDI velocity of the returned chord.
            Randomly assigned if ``None`` (default).
        velocity_lims (tuple): Range of velocities for random assignment.
        unique (bool): If `True`, no duplicate pitches in returned chord.

    Returns:
        chord (music21.chord.Chord): Chord object.
    """
    pitch_range = muser.utils.key_check(pitch_range, PITCH_RANGES, 'lower')
    pitches = np.random.choice(pitch_range, chord_size, replace=not unique)
    notes = [random_note(pitch=p, velocity=velocity,
                         velocity_lims=velocity_lims) for p in pitches]
    chord = music21.chord.Chord(notes)
    return chord

def chord_to_velocity_vector(chord):
    """Return a MIDI velocity vector for a music21 Chord object.

    Args:
        chord (music21.chord.Chord): Chord object to convert to vector form.

    Returns:
        velocity_vector (np.ndarray): Vector of velocities of each MIDI pitch
    """
    chord_velocity = chord.volume.velocity
    if chord_velocity is None:
        chord_velocity = 1.0
    vector = velocity_vector()
    vector[[(p.midi - 1) for p in chord.pitches]] = chord_velocity
    return vector

def note_to_velocity_vector(note):
    """Return a MIDI pitch vector for a music21 Note object."""
    vector = chord_to_velocity_vector(music21.chord.Chord([note]))
    return vector

def random_velocity_vector(n_pitches=1, pitch_range='midi', velocity=None):
    """Return a random velocity vector.

    Args:
        n_pitches (int): Number of pitches in the velocity vector.
            If function is given: assigns call to function as ``n_pitches``.
        pitch_range (iterable or string): Vector of MIDI pitches for
            random selection.
        velocity (int or tuple): MIDI velocities of returned chord.
            If ``None``: random velocities in [0, 1).
            If a number constant is given: constant velocity.
    Returns:
        vector (np.ndarray): Velocities of each MIDI pitch/note number.
    """
    pitch_range = muser.utils.key_check(pitch_range, PITCH_RANGES, 'lower')
    try:
        n_pitches = n_pitches()
    except TypeError:
        pass
    pitches = np.random.choice(pitch_range, n_pitches, replace=False)
    vector = velocity_vector(pitch_range)
    try:
        vector[pitches,] = np.random.rand(n_pitches)
    except TypeError:
        vector[pitches,] = velocity
    return vector

def midi_all_notes_off(midi_basic=False, pitch_range='midi'):
    """Return MIDI event(s) to turn off all notes in range.

    Args:
        midi_basic (bool): Switches MIDI event type to turn notes off.
            Use NOTE_OFF events for each note if True, and single
            ALL_NOTES_OFF event if False.
        pitch_range (Tuple[int]): Range of pitches for NOTE_OFF events, if used.
            Defaults to entire MIDI pitch range.
    """
    pitch_range = muser.utils.key_check(pitch_range, PITCH_RANGES, 'lower')
    if midi_basic:
        pitches_off = np.zeros(N_PITCHES)
        pitches_off[slice(*pitch_range)] = 1
        return vector_to_midi_events(STATUS_BYTES['NOTE_OFF'], pitches_off)
    else:
        return np.array(((STATUS_BYTES['CONTROL'],
                          CONTROL_BYTES['ALL_NOTES_OFF'], 0),))

def vector_to_midi_events(status, vector):
    """ Return MIDI event parameters for given velocity vector.

    Status can be specified as one of the keys in ``STATUS_BYTES``.

    Args:
        status: The status parameter of the returned events.
        velocity_vector (np.ndarray): Vector of velocities of each MIDI pitch

    Returns:
        chord_events (np.ndarray): MIDI event parameters, one event per row.
    """
    status = muser.utils.key_check(status, STATUS_BYTES, 'upper')
    pitches = np.flatnonzero(vector)
    velocities = vector[pitches] * VELOCITY_HI
    chord_events = np.zeros((3, len(pitches)), dtype=np.uint8)
    chord_events[0] = status
    chord_events[1] = pitches
    chord_events[2] = velocities
    chord_events = chord_events.transpose()
    return chord_events

def note_to_midi_onoff(note):
    """Returns MIDI note-on and note-off events for a music21 note.

    Args:
        note (music21.Note.note): The ``music21`` note to convert to events.
    """
    vector = note_to_velocity_vector(note)
    note_on = vector_to_midi_events(STATUS_BYTES['NOTE_ON'], vector)
    note_off = vector_to_midi_events(STATUS_BYTES['NOTE_OFF'], vector)
    return note_on, note_off

def control_event(data_byte1, data_byte2=0, channel=1):
    """Return a MIDI control event with the given data bytes."""
    data_byte1 = muser.utils.key_check(data_byte1, CONTROL_BYTES, 'upper')
    return (STATUS_BYTES['CONTROL'] + channel - 1, data_byte1, data_byte2)

def continuous_event(status, data_byte1, channel=1):
    """Return a function that varies the second data byte of a MIDI event.

    Args:
        status (int or str): The MIDI status byte.
        data_byte1 (int or str): The first MIDI data byte (control byte).
        channel (int): The MIDI channel (1-16).
            Only applies to channel-dependent MIDI messages.
    """
    status = muser.utils.key_check(status, STATUS_BYTES, 'upper')
    def event(data_byte2):
        return (status + channel - 1, data_byte1, data_byte2)
    return event

def continuous_control(data_byte1, channel=1):
    """Return a function that varies the second data byte of a control event."""
    data_byte1 = muser.utils.key_check(data_byte1, CONTROL_BYTES, 'upper')
    return continuous_event(STATUS_BYTES['CONTROL'],
                            data_byte1=data_byte1,
                            channel=channel)

def velocity_vector(pitch_range='midi', dtype=np.float32):
    """Returns a velocity vector of zeros for all MIDI pitches."""
    pitch_range = muser.utils.key_check(pitch_range, PITCH_RANGES, 'lower')
    return np.zeros_like(pitch_range, dtype=dtype)

def beat_bias(beat_float, timesig, beat_biases):
    """Returns a bias depending on relative position in a measure.

    Currently uses linear interpolation between values in ``beat_biases``.

    Args:
        beat_float (float): Relative position in the measure.
            Refers to beats using indices, so a value of 0.5 refers to the
            position halfway between the first and second beats in the measure.
        timesig (Tuple[int]): The time signature of the measure.
            For example, ``(4, 4)`` corresponds to the time signature 4/4.
        beat_biases (dict):
    """
    beats = range(timesig[0])
    return np.interp(beat_float, beats, beat_biases[timesig])

def read_midifile(filepath):
    """Read a MIDI file and return a music21 ``MidiFile`` object."""
    midifile = music21.midi.MidiFile()
    midifile.open(filepath, 'rb')
    midifile.read()
    midifile.close()
    return midifile

def midifile_to_notes(midifile):
    """Read a MIDI file and return."""
    return music21.midi.translate.midiFileToStream(midifile).flat

def m21_midievent_to_event(midievent):
    """Convert a music21 MidiEvent to a tuple of MIDI bytes."""
    status = midievent.data + midievent.channel - 1
    return (status, midievent.pitch, midievent.velocity)


"""
group_reader.py

Containers to parse and hold for the functional group information.

"""

import copy
try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import SafeConfigParser as ConfigParser
import glob
import re
from collections import OrderedDict
from os import path

import numpy as np
from numpy import array, identity, asarray, dot, cross
from numpy.linalg import norm

from fapswitch.config import options
from fapswitch.config import info, debug, error
from fapswitch.core.components import Atom
from fapswitch.core.elements import UFF
from fapswitch.core.util import vecdist3, subgroup

class FunctionalGroupLibrary(OrderedDict):
    """
    Container for all the available functional groups just subclasses
    the standard dict adding some new methods.

    """
    def __init__(self, *args, **kwargs):
        """Initialise a dictionary and update with functional groups."""
        # Make sure that the dict is properly initilaised
        OrderedDict.__init__(self, *args, **kwargs)

        # Functional groups can be put in several places
        # Defaults '*.lib' files in library directory always loaded
        library_glob = path.join(path.dirname(path.realpath(__file__)),
                                 'library', '*.flib')
        for library in sorted(glob.glob(library_glob)):
            self._from_file(path.join(library))

        # Custom user groups stored in .faps supercede defaults
        faps_glob = path.join(path.expanduser('~'), '.faps', '*.flib')
        for library in glob.glob(faps_glob):
            self._from_file(path.join(library))

        # Job specific groups in the working directory
        for library in glob.glob('*.flib'):
            self._from_file(path.join(library))

    def _from_file(self, flib_file_name='functional_groups.flib'):
        """Parse groups from the configparser .ini style file."""
        # just a standard configparser conversion to a dict of
        # FunctionalGroup objects
        mepo_only = options.getbool('mepo_only')
        flib_file = ConfigParser()
        debug("Reading groups from {}".format(flib_file_name))
        flib_file.read(flib_file_name)
        for group_name in flib_file.sections():
            try:
                new_group = FunctionalGroup(group_name,
                                            flib_file.items(group_name))
                if mepo_only and not new_group.mepo_compatible:
                    debug("Skipped non-MEPO {}".format(group_name))
                else:
                    if group_name in self:
                        debug("Overriding group {}".format(group_name))
                    self[group_name] = new_group
            except KeyError:
                error("Group {} is missing data".format(group_name))

    @property
    def group_list(self):
        """Compile a soretd list of all the available groups."""
        return sorted(list(self))

class FunctionalGroup(object):
    """
    Substitutable functional group. Bunch of atoms with information on how
    to connect to the framework

    """

    def __init__(self, group_name, items):
        """Initialize from a list of tuples as the attributes."""
        # These are defaults, best that they are overwritten
        self.ident = group_name
        self.atoms = []
        self.bonds = {}
        self.orientation = [0, 1, 0]
        self.smiles = ""
        self.mepo_compatible = False

        # pop the items from a dict giving neater code
        items = dict(items)

        self._parse_atoms(items.pop('atoms'))
        self.orientation = normalise(string_to_tuple(items.pop('orientation'),
                                                     float))
        self.normal = normalise(string_to_tuple(items.pop('normal'), float))
        self.bond_length = float(items.pop('carbon_bond'))
        self._parse_bonds(items.pop('bonds'))
        self.connection_point = 0  # always connect to the first atom
        if 'mepo_compatible' in items:
            # This parsing is taken from config.py as it doesn't like "False"
            compat = items.pop('mepo_compatible').lower()
            if compat in ["1", "yes", "true", "on"]:
                self.mepo_compatible = True
        # FIXME(tdaff) Add the synthesis stuff
        # Arbitrary attributes can be set
        self.__dict__.update(items)
        self._gen_neighbours()

    def _parse_atoms(self, atom_text):
        """Read atom information from the file."""
        self.atoms = []
        for atom in atom_text.splitlines():
            atom = atom.strip().split()
            if not atom:
                continue
            new_atom = Atom(atom[0], [float(x) for x in atom[2:5]])
            new_atom.uff_type = atom[1]
            new_atom.vdw_radius = UFF[new_atom.type][0]/2.0
            self.atoms.append(new_atom)

    def _parse_bonds(self, bond_block):
        """
        Extract the bonds from the text and calculate the distances between the
        atoms as these are needed for the cif file.

        """

        bond_split = subgroup(bond_block.split(), width=3)
        for bond_trio in bond_split:
            bond = (int(bond_trio[0]), int(bond_trio[1]))
            distance = vecdist3(self.atoms[bond[0]].pos,
                                self.atoms[bond[1]].pos)
            self.bonds[bond] = (distance, float(bond_trio[2]))

    def _gen_neighbours(self):
        """Update atoms with neighbouring atoms."""
        # Iterate over all pairs
        # Assume non periodic and geometries are good
        # dummy atom at the tether point
        self.atoms.append(Atom('C', [-self.bond_length*x
                                     for x in self.orientation]))
        for atom in self.atoms:
            # distance matrix for all neighbours except self
            neighbours = []
            for ot_idx, other in enumerate(self.atoms):
                if atom is other:
                    continue
                length = vecdist3(atom.pos, other.pos)
                neighbours.append((length, ot_idx))
            # these are expected to be is distance order
            atom.neighbours = sorted(neighbours)
        # remove the dummy atom
        self.atoms.pop()
        # first atom should be bonded to the tether, flag this as '-1'
        #self.atoms[0].bonds[self.atoms[0].bonds.index(self.natoms)] = -1

    def atoms_attached_to(self, point, direction, normal, attach_point,
                          start_index):
        """Return a list of atoms at the specified position."""
        new_atoms = [copy.copy(atom) for atom in self.atoms]
        rotate_matrix = matrix_rotate(self.orientation, direction)
        my_rotated_normal = np.dot(rotate_matrix, self.normal)
        orient_matrix = matrix_rotate(my_rotated_normal, normal)
        for index, atom in enumerate(new_atoms):
            atom.pos = np.dot(orient_matrix, np.dot(rotate_matrix, atom.pos))
            atom.pos = (atom.pos + point + self.bond_length*np.array(direction))
            atom.idx = start_index + index
        new_bonds = {}
        for bond_pair, bond_info in self.bonds.items():
            new_bond = (bond_pair[0] + start_index, bond_pair[1] + start_index)
            new_bonds[new_bond] = bond_info
        # bond to structure is single...
        bond_to_structure = (attach_point, self.connection_point + start_index)
        new_bonds[bond_to_structure] = (self.bond_length, 1.0)

        return new_atoms, new_bonds

    def log_info(self):
        """Send all the information about the group to the logging functions."""
        info("[{}]".format(self.ident))
        info("name = {}".format(self.name))
        info("smiles = {}".format(self.smiles))
        info("mepo_compatible = {}".format(self.mepo_compatible))

        debug("atoms =")
        for atom in self.atoms:
            debug("    {0:4} {1:5} {2[0]:10.6f} {2[1]:10.6f} {2[2]:10.6f}".format(atom.type, atom.uff_type, atom.pos))
        debug("orientation = {0[0]:.1f} {0[1]:.1f} {0[2]:.1f}".format(self.orientation))
        debug("normal = {0[0]:.1f} {0[1]:.1f} {0[2]:.1f}".format(self.normal))
        debug("carbon_bond = {}".format(self.bond_length))
        debug("bonds =")
        for bond in self.bonds:
            debug("    {0[0]:4} {0[1]:4} {1[1]:5.2f}".format(bond, self.bonds[bond]))
        info("")

    @property
    def natoms(self):
        """The number of atoms in the functional group."""
        return len(self.atoms)

def matrix_rotate(source, target):
    """Create a rotation matrix that will rotate source on to target."""
    # Normalise so there is no scaling in the array
    source = asarray(source)/norm(source)
    target = asarray(target)/norm(target)
    v = cross(source, target)
    vlen = dot(v, v)
    if vlen == 0.0:
        # already aligned, no rotation needed
        return identity(3)
    c = dot(source, target)
    h = (1 - c)/vlen
    return array([[c + h*v[0]*v[0], h*v[0]*v[1] - v[2], h*v[0]*v[2] + v[1]],
                  [h*v[0]*v[1] + v[2], c + h*v[1]*v[1], h*v[1]*v[2] - v[0]],
                  [h*v[0]*v[2] - v[1], h*v[1]*v[2] + v[0], c + h*v[2]*v[2]]])

def normalise(vector):
    """Return an array with magnitude 1."""
    return asarray(vector)/norm(vector)

def string_to_tuple(value, dtype=None):
    """Parse a list of items, ignoring whitespace, brackets and commas."""
    value = [x for x in re.split(r'[\s,\(\)\[\]]*', value) if x]
    if dtype is not None:
        return tuple([dtype(x) for x in value])
    else:
        return tuple(value)


from datetime import timedelta
from time import time

try:
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
except ImportError:
    from PySide2.QtWidgets import *
    from PySide2.QtGui import *
    from PySide2.QtCore import *
import numpy as np

import hou

from . import ui
from .text import MONOSPACE_FONT

class TimeEstimation(object):
    Off = 0
    First = 1
    Last = 2
    Minimum = 3
    Maximum = 4
    Mean = 5
    Median = 6

def timeRemaining(durations, remainder, method):
    if method == TimeEstimation.Off:
        return 0
    elif method == TimeEstimation.First:
        return durations[0] * remainder
    elif method == TimeEstimation.Last:
        return durations[-1] * remainder
    elif method == TimeEstimation.Minimum:
        return min(durations) * remainder
    elif method == TimeEstimation.Maximum:
        return max(durations) * remainder
    elif method == TimeEstimation.Mean:
        return np.mean(durations) * remainder
    elif method == TimeEstimation.Median:
        return np.median(durations) * remainder

class InterruptableOperation(QDialog):
    def __init__(self, count=None, time_estimation_method=TimeEstimation.Mean,
                 operation='', icon='MISC_empty', parent=None):
        super(InterruptableOperation, self).__init__(parent)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        self._operation = operation
        self._count = count
        self._time_estimation_method = time_estimation_method
        self._start_time = None
        self._previous_update = None
        self._durations = []
        self._stop = False

        self.setWindowTitle(operation)
        self.setWindowIcon(ui.icon(icon, 32))

        layout = QGridLayout(self)
        layout.setContentsMargins(6, 6, 6, 6)
        layout.setSpacing(4)

        self._icon_label = QLabel()
        if icon and icon != 'MISC_empty':
            self._icon_label.setPixmap(ui.icon(icon, 64).pixmap(64))
        else:
            self._icon_label.setHidden(True)
        layout.addWidget(self._icon_label, 0, 0, -1, 1)

        self._progress_status_label = QLabel('Performing...')
        self._progress_status_label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self._progress_status_label, 0, 1, 1, -1)

        self._progress_time_label = QLabel()
        self._progress_time_label.setFont(MONOSPACE_FONT)
        self._progress_time_label.setAlignment(Qt.AlignCenter)
        self._progress_time_label.setToolTip('Elapsed / Remaining')
        layout.addWidget(self._progress_time_label, 1, 1)

        self._progress = QProgressBar()
        self._progress.setTextVisible(False)
        self._progress.setFixedHeight(5)
        self._progress.setRange(0, count or 0)
        layout.addWidget(self._progress, 2, 1)

        self.setSizeGripEnabled(False)

    def hideEvent(self, event):
        self._stop = True

    def closeEvent(self, event):
        self._stop = True

    def __enter__(self):
        self.open()
        self._start_time = time()
        self._previous_update = time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
        self.deleteLater()
        return exc_type == hou.OperationInterrupted

    def updateProgress(self, num=None, status=None):
        if self._stop:
            raise hou.OperationInterrupted

        time_elapsed = timedelta(seconds=int(time() - self._start_time))
        progress = (int(num / float(self._count) * 100) if num and self._count else '~')

        if status is not None:
            self._progress_status_label.setText(status)
            message = '{} (Press Esc to Cancel) {} ({}%)'.format(
                time_elapsed, status, progress
            )
            hou.ui.setStatusMessage(message, hou.severityType.Message)

        if num is None:
            return

        current_time = time()
        self._durations.append(current_time - self._previous_update)
        self._previous_update = current_time

        time_remaining = timedelta(
            seconds=int(timeRemaining(
                self._durations,
                self._count - num,
                self._time_estimation_method
            ))
        )
        self._progress_time_label.setText('{} / {}'.format(time_elapsed, time_remaining))
        if self._count:
            self._progress.setValue(num)

        if status is None:
            message = '{} (Press Esc to Cancel) {} ({}%)'.format(
                time_elapsed, self._operation, progress
            )
            hou.ui.setStatusMessage(message, hou.severityType.Message)

        QApplication.processEvents()


import os
import re
import torch
import random
import librosa
import numpy as np
from torch.utils.data import Dataset
from collections import Counter

from .text import Language
from .text.cmudict import CMUDict
from modules.mel import Audio2Mel

class TextMelDataset(Dataset):
    def __init__(self, hp, data_dir, metadata_path, train=True, norm=False):
        super().__init__()
        self.hp = hp
        self.lang = Language(hp.data.lang, hp.data.text_cleaners)
        self.train = train
        self.norm = norm
        self.data_dir = data_dir
        self.meta = self.load_metadata(metadata_path)
        self.speaker_dict = {speaker: idx for idx, speaker in enumerate(hp.data.speakers)}

        if train:
            # balanced sampling for each speaker
            speaker_counter = Counter((spk_id \
                for audiopath, text, spk_id in self.meta))
            weights = [1.0 / speaker_counter[spk_id] \
                for audiopath, text, spk_id in self.meta]
            self.mapping_weights = torch.DoubleTensor(weights)

        self.remove_existing_mel()
        self.audio2mel = Audio2Mel(
            n_fft=hp.audio.filter_length, hop_length=hp.audio.hop_length,
            win_length=hp.audio.win_length, sampling_rate=hp.audio.sampling_rate,
            n_mel_channels=hp.audio.n_mel_channels,
            mel_fmin=hp.audio.mel_fmin, mel_fmax=hp.audio.mel_fmax)

        if hp.data.lang == 'cmu':
            self.cmudict = CMUDict(hp.data.cmudict_path)
            self.cmu_pattern = re.compile(r'^(?P<word>[^!\'(),-.:~?]+)(?P<punc>[!\'(),-.:~?]+)$')
        else:
            self.cmudict = None

    def __len__(self):
        return len(self.meta)

    def __getitem__(self, idx):
        if self.train:
            idx = torch.multinomial(self.mapping_weights, 1).item()

        audiopath, text, spk_id = self.meta[idx]
        audiopath = os.path.join(self.data_dir, audiopath)
        mel = self.get_mel(audiopath)
        text_norm = self.get_text(text)
        spk_id = self.speaker_dict[spk_id]
        return text_norm, mel, spk_id

    def get_mel(self, audiopath):
        melpath = os.path.join(self.data_dir, '{}.pt'.format(audiopath))
        try:
            mel = torch.load(melpath, map_location='cpu')
            assert mel.size(0) == self.hp.audio.n_mel_channels, \
                'Mel dimension mismatch: expected %d, got %d' % \
                (self.hp.audio.n_mel_channels, mel.size(0))
        except (FileNotFoundError, RuntimeError, TypeError):
            wav, sr = librosa.load(audiopath, sr=None, mono=True)
            assert sr == self.hp.audio.sampling_rate, \
                'sample mismatch: expected %d, got %d at %s' % (self.hp.audio.sampling_rate, sr, audiopath)
            wav = torch.from_numpy(wav).view(1, 1, -1)

            if self.norm:
                wav = wav * (0.99 / (torch.max(torch.abs(wav)) + 1e-7))
            mel = self.audio2mel(wav).squeeze(0)

            torch.save(mel, melpath)

        return mel

    def get_text(self, text):
        if self.cmudict is not None:
            text = ' '.join([self.get_arpabet(word) for word in text.split(' ')])
        text_norm = torch.IntTensor(self.lang.text_to_sequence(text, self.hp.data.text_cleaners))
        return text_norm

    def get_arpabet(self, word):
        arpabet = self.cmudict.lookup(word)
        if arpabet is None:
            match = self.cmu_pattern.search(word)
            if match is None:
                return word
            subword = match.group('word')
            arpabet = self.cmudict.lookup(subword)
            if arpabet is None:
                return word
            punc = match.group('punc')
            arpabet = '{%s}%s' % (arpabet[0], punc)
        else:
            arpabet = '{%s}' % arpabet[0]

        if random.random() < 0.5:
            return word
        else:
            return arpabet

    def load_metadata(self, path, split="|"):
        with open(path, 'r', encoding='utf-8') as f:
            metadata = [line.strip().split(split) for line in f]

        return metadata

    def remove_existing_mel(self):
        for meta in self.meta:
            audiopath = meta[0]
            melpath = os.path.join(
                self.data_dir, '{}.pt'.format(audiopath))
            if os.path.exists(melpath):
                try:
                    os.remove(melpath)
                except FileNotFoundError:
                    pass

def text_mel_collate(batch):
    input_lengths, ids_sorted_decreasing = torch.sort(
        torch.LongTensor([len(x[0]) for x in batch]),
        dim=0, descending=True)
    max_input_len = torch.empty(len(batch), dtype=torch.long)
    max_input_len.fill_(input_lengths[0])

    text_padded = torch.zeros((len(batch), max_input_len[0]), dtype=torch.long)
    n_mel_channels = batch[0][1].size(0)
    max_target_len = max([x[1].size(1) for x in batch])
    mel_padded = torch.zeros(len(batch), n_mel_channels, max_target_len)
    output_lengths = torch.empty(len(batch), dtype=torch.long)
    speakers = torch.empty(len(batch), dtype=torch.long)

    for idx, key in enumerate(ids_sorted_decreasing):
        text = batch[key][0]
        text_padded[idx, :text.size(0)] = text
        mel = batch[key][1]
        mel_padded[idx, :, :mel.size(1)] = mel
        output_lengths[idx] = mel.size(1)
        speakers[idx] = batch[key][2]

    return text_padded, mel_padded, speakers, \
        input_lengths, output_lengths, max_input_len


import os
import argparse
import time
import torch
from torch.utils.data import DataLoader
import torch.nn as nn
import numpy as np
from tqdm import trange
from tensorboardX import SummaryWriter

from models import LPRNet, STNet
from utils import sparse_tuple_for_ctc, CHARS
from utils import LPRDataset, collate_fn
from utils import eval, decode

def main(train_data, val_data, img_size, batch_size, num_epochs):

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    lprnet = LPRNet(class_num=len(CHARS))
    lprnet.to(device)
    lprnet.load_state_dict(torch.load('weights/LPRNet_model_Init.pth', map_location=lambda storage, loc: storage))

    STN = STNet()
    STN.to(device)
    STN.load_state_dict(torch.load('weights/STN_model_Init.pth', map_location=lambda storage, loc: storage))

    train_dataset = LPRDataset([train_data], img_size)
    val_dataset = LPRDataset([val_data], img_size)

    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False, num_workers=4, collate_fn=collate_fn)
    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=4, collate_fn=collate_fn)

    lr = 0.001
    gamma=0.1
    milestones = [0.5 * num_epochs, 0.75 * num_epochs]

    optimizer = torch.optim.Adam([{'params': STN.parameters(), 'weight_decay': 2e-5},
                                  {'params': lprnet.parameters()}], lr=lr)
    scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=gamma)

    ctc_loss = nn.CTCLoss(blank=len(CHARS)-1, reduction='mean')

    save_dir = os.path.join('./output', time.strftime("%y%m%d_%H%M%S"))
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)

    total_iters = 0
    best_acc = 0
    best_iter = 0
    T_length = 18
    best_lprnet = lprnet
    best_stn = STN

    writer = SummaryWriter(log_dir=os.path.join(save_dir, 'Tensorboard_Results'))

    for epoch in trange(num_epochs):

        lprnet.train()
        STN.train()

        for imgs, labels, lengths in train_loader:
            imgs, labels = imgs.to(device), labels.to(device)
            optimizer.zero_grad()

            with torch.set_grad_enabled(True):

                transfer = STN(imgs)

                logits = lprnet(transfer)
                log_probs = logits.permute(2, 0, 1)
                log_probs = log_probs.log_softmax(2).requires_grad_()
                input_lengths, target_lengths = sparse_tuple_for_ctc(T_length, lengths)
                loss = ctc_loss(log_probs, labels, input_lengths=input_lengths, target_lengths=target_lengths)

                loss.backward()
                optimizer.step()

                total_iters += 1

                writer.add_scalar('train_loss_logs', loss.item(), total_iters)

                if total_iters % 100 == 0:

                    preds = logits.cpu().detach().numpy()
                    _, pred_labels = decode(preds, CHARS)
                    total = preds.shape[0]
                    start = 0
                    TP = 0
                    for i, length in enumerate(lengths):
                        label = labels[start:start+length]
                        start += length
                        if np.array_equal(np.array(pred_labels[i]), label.cpu().numpy()):
                            TP += 1

                    for p in optimizer.param_groups:
                        lr = p['lr']

                    print("Epoch %d/%d, Iters: %d, learning rate: %f, loss: %.4f, train_accuracy: %.4f"
                          % (epoch+1, num_epochs, total_iters, lr, loss.item(), TP/total))

            if total_iters % 800 == 0:

                lprnet.eval()
                STN.eval()

                train_loss, train_acc = eval(lprnet, STN, ctc_loss, T_length, train_loader, train_dataset, device)
                test_loss, acc = eval(lprnet, STN, ctc_loss, T_length, val_loader, val_dataset, device)

                writer.add_scalar('train_acc', train_acc, total_iters)
                writer.add_scalar('test_acc', acc, total_iters)
                writer.add_scalar('test_loss', test_loss, total_iters)

                if best_acc <= acc:
                    best_acc = acc
                    best_iter = total_iters

                    best_lprnet = lprnet
                    best_stn = STN

                lprnet.train()
                STN.train()

                print("Epoch %d/%d, Iters: %d, test_loss: %.4f, test_accuracy: %.4f, current_best_acc: %.4f"
                          % (epoch+1, num_epochs, total_iters, test_loss, acc, best_acc))

        scheduler.step()

    print('Best Accuracy: %.4f in iters: %d' % (best_acc, best_iter))
    torch.save(best_lprnet.state_dict(), os.path.join(save_dir, 'best_LPRNet_model.pth'))
    torch.save(best_stn.state_dict(),  os.path.join(save_dir, 'best_STN_model.pth'))

    writer.close()

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('--img_size', default=(94, 24), help='input image size')
    parser.add_argument('--train_data', default="./data/train", help='dir path of training data')
    parser.add_argument('--val_data', default="./data/validation", help='dir path of validation data')
    parser.add_argument('--num_epochs', default=60, type=int, help='number of epochs for training')
    parser.add_argument('--batch_size', default=128, type=int, help='batch size')
    args = parser.parse_args()

    img_size = args.img_size
    train_data = args.train_data
    val_data = args.val_data
    num_epochs = args.num_epochs
    batch_size = args.batch_size

    main(train_data, val_data, img_size, batch_size, num_epochs)


"""
============
Multiprocess
============
Demo of using multiprocessing for generating data in one process and
plotting in another.
Written by Robert Cimrman
"""

import time

import scipy.stats
import numpy as np
import warnings
warnings.simplefilter('ignore', np.RankWarning)
import sys

import tosdb
import json
from multiprocessing import Process, Pipe

# This example will likely not work with the native OSX backend.
# Uncomment the following lines to use the qt5 backend instead.
#
# import matplotlib
# matplotlib.use('qt5agg')
#
# Alternatively, with Python 3.4+ you may add the line
#

#
# immediately after the ``if __name__ == "__main__"`` check.

import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
plt.rcParams.update({'font.size': 8})
from datetime import timedelta
import datetime, time

from flask import Flask, render_template
from flask_socketio import SocketIO, emit

from socketIO_client import SocketIO as sio

# Fixing random state for reproducibility
np.random.seed(19680801)

###############################################################################
#
# Processing Class
# ================
#
# This class plots data it receives from a pipe.
#
refreshInterval = 1
arraySize = 60

class ProcessPlotter(object):
    def __init__(self):

        self.volumeData2 = {}
        self.priceData = {}
        self.colors = {}

        self.stock = 'SPY'

        self.x = []
        self.y = []
        self.a = 0;
        self.agg1 = 2;
        self.agg2 = 15;
        self.agg3 = 30;
        self.aggs = [self.agg1]

        self.agg1Length = 18;
        self.agg2Length = 10;
        self.agg3Length = 12

        self.aggsLength = [self.agg1Length, self.agg2Length, self.agg3Length]

    def terminate(self):
        plt.close('all')

    # def initialize(self):
    #     snapshot1 = self.b1.stream_snapshot('SPY', 'Volume',date_time=True)
    #     print(snapshot1);
    #     micro, sec, minute, hour, day, month, year = snapshot1[0][1];

    #     latestT = time.mktime(datetime.datetime(year, month, day, hour, minute, sec).timetuple())

    #     for index in range(1):
    #         print(snapshot1[0][1])
    #         i = 0;

    #         ourCurrentFuckingIndex = self.aggsLength[index] -1;
    #         largerVol =  snapshot1[0][0];

    #         while True:
    #             micro, sec, minute, hour, day, month, year = snapshot1[i][1]
    #             t = time.mktime(datetime.datetime(year, month, day, hour, minute, sec).timetuple())

    #             theDateTimeWeAreLookingFor =  latestT - (  (self.aggs[index]*self.aggsLength[index]) -  (ourCurrentFuckingIndex/self.aggsLength[index])*(self.aggs[index]*self.aggsLength[index]));
    #             # print("theDateTimeWeAreLookingFor")
    #             # print(theDateTimeWeAreLookingFor)
    #             # print("currentT")
    #             # print(t)

    #             if(ourCurrentFuckingIndex == -1 or  i + 1 >= len(snapshot1) ):
    #                 # print('bye')
    #                 break;
    #             elif(t < theDateTimeWeAreLookingFor ):
    #                 # print('hi')
    #                 self.timeData[item][index].insert(0,ourCurrentFuckingIndex*self.aggs[index])
    #                 ourCurrentFuckingIndex = ourCurrentFuckingIndex - 1;
    #                 smallerVol = snapshot1[i][0];

    #                 self.volumeData2[item][index].insert(0,(largerVol - smallerVol));

    #                 largerVol = smallerVol;

    #             i = i +1;

    def graph(self):

        item = self.stock;

        Ys = np.diff(np.array(self.volumeData2[item][0]));

        #YsSorted.sort();
        Xs = np.array(range(len(Ys)))

        # priceChanges = np.diff(np.array(self.priceData[item][0]));
        # colors = []

        # for price in priceChanges:
        #     if(price > 0):
        #         colors.append('g')
        #     elif(price == 0):
        #         colors.append('k')
        #     else:
        #         colors.append('r')

        # colors = colors[-len(YsSorted):]

        self.ax.clear()
        self.ax.axhline(y=0, color='k')

        if(len(Ys)==0):
            return
        else:
            self.ax.scatter(Xs, Ys,)
            self.ax.plot(Xs, Ys, 'k-', linewidth=.5)

            # xIndex = 0;
            # for c in colors:
            #     if(c == 'r'):
            #         redYs.append(int(YsSorted[xIndex]));
            #         redXs.append(xIndex);
            #     elif(c == 'g'):
            #         greenYs.append(int(YsSorted[xIndex]));
            #         greenXs.append(xIndex);
            #     xIndex = xIndex + 1;

            # if(len(greenXs)>2):

            #     result = np.polyfit(greenXs, greenYs, 1)

            #     p = np.poly1d(result);
            #     yhat = p(Xs)                         # or [p(z) for z in x]
            #     ybar = np.sum(Ys)/len(Ys)          # or sum(y)/len(y)
            #     ssreg = np.sum((yhat-ybar)**2)   # or sum([ (yihat - ybar)**2 for yihat in yhat])
            #     sstot = np.sum((Ys - ybar)**2)    # or sum([ (yi - ybar)**2 for yi in y])
            #     rsquared = ssreg / sstot

            #     self.ax.plot(Xs, p(Xs), 'g-')
            #     self.ax.text(Xs[0],Ys[0],rsquared)

            # if(len(redXs)>2):

            #     result = np.polyfit(redXs, redYs, 1)

            #     p = np.poly1d(result);
            #     yhat = p(Xs)                         # or [p(z) for z in x]
            #     ybar = np.sum(Ys)/len(Ys)          # or sum(y)/len(y)
            #     ssreg = np.sum((yhat-ybar)**2)   # or sum([ (yihat - ybar)**2 for yihat in yhat])
            #     sstot = np.sum((Ys - ybar)**2)    # or sum([ (yi - ybar)**2 for yi in y])
            #     rsquared = ssreg / sstot

            #     self.ax.plot(Xs, p(Xs), 'r-')
            #     self.ax.text(Xs[0],Ys[0],rsquared)

        # else:
        #     self.ax.scatter(Xs, YsSorted,  c= self.colors[item][0] )

            # verts = [(Xs[0], 0)] + list(zip(Xs, YsSorted)) + [(Xs[-1], 0)]
            # poly = Polygon(verts, facecolor='0.9', edgecolor='0.0')
            # self.ax[index][1].add_patch(poly)

            # thirdGraph = self.ax[index][2];
            # #thirdGraph.clear()

            # thirdGraph.axhline(y=0, color='k')

            # thirdGraph.plot(Xs, Ys,  'b-' )
            # verts2 = [(Xs[0], 0)] + list(zip(Xs, Ys)) + [(Xs[-1], 0)]
            # poly2 = Polygon(verts2, facecolor='0.9', edgecolor='0.0')
            # thirdGraph.add_patch(poly2)

            # if len(Ys) > self.aggsLength[index]:
            #     #self.timeData[item][index].pop(0)
            #     Ys = np.diff(np.array(self.volumeData2[item][index]))[-self.aggsLength[index]:];
            #     Xs = np.array(range(len(Ys)))

            #i.clear();
            #i.scatter(Xs, Ys );

            #result = np.polyfit(Xs, Ys, 2)

            # p = np.poly1d(result);
            # yhat = p(Xs)                         # or [p(z) for z in x]
            # ybar = np.sum(Ys)/len(Ys)          # or sum(y)/len(y)
            # ssreg = np.sum((yhat-ybar)**2)   # or sum([ (yihat - ybar)**2 for yihat in yhat])
            # sstot = np.sum((Ys - ybar)**2)    # or sum([ (yi - ybar)**2 for yi in y])
            # rsquared = ssreg / sstot

            # self.ax[index][0].plot(Xs, p(Xs), 'r-')
            # self.ax[index][0].text(Xs[0],Ys[0],rsquared)

            # dprice = np.diff(self.priceData[item][index])
            # v = np.diff(self.volumeData2[item][index]);

            # v_buy = v * scipy.stats.norm.cdf(dprice / dprice.std())
            # v_sell = v - v_buy
            # bvpin = abs (v_sell - v_buy) / v
            # if(len(bvpin) != 0):
            #     self.ax[index][0].text(Xs[-1],Ys[-1],bvpin[-1])

    def call_back(self):

        while self.pipe.poll():
            command = self.pipe.recv()
            if command is None:
                self.terminate()
                return False
            # elif(command.find('GetInfo-')!= -1):
            #     item = command[command.find('-')+1:]
            #     total_frame = self.b1.total_frame(date_time= True, labels=True);
            #     print(total_frame)
            #     info = {
            #         "BID":float(total_frame[item].BID[0]),
            #         "ASK":float(total_frame[item].ASK[0])
            #         };
            #     print(info)
            #     self.pipe.send(info)

            else:
                self.stock = command

                self.ax.clear()

                if (command in self.b1.items()) == False:
                    self.b1.add_items(command)

                    self.priceData[command] = [[],[],[]]
                    self.volumeData2[command] = [[],[],[]]
                    self.colors[command] = [[],[],[]]
                    self.pipe.send('ADDED')

                else:
                    self.graph();

                    total_frame = self.b1.total_frame(labels=True);
                    # print(total_frame)
                    # info = {
                    #     "BID":float(total_frame[item].BID[0]),
                    #     "ASK":float(total_frame[item].ASK[0])
                    #     };
                    # print()
                    self.pipe.send(json.dumps(total_frame))

        for item in self.b1.items():

            index = 0;
            while index< len(self.aggs):

                if ((self.a) % (self.aggs[index]) == 0) == False:
                    index += 1
                    continue

                #self.priceData[item][index].append( float(self.b1.get(item,'LAST')));
                vol = float( self.b1.get(item,'VOLUME',check_indx=False));
                last = float( self.b1.get(item,'LAST',check_indx=False));

                if(vol > 0):
                    self.volumeData2[item][index].append(vol);
                    self.priceData[item][index].append(last)

                if(len(self.volumeData2[item][index])>arraySize):
                    self.volumeData2[item][index].pop(0)
                    self.priceData[item][index].pop(0)

                index += 1

                self.graph();

        self.a += 1
        self.fig.suptitle(self.stock)

        self.fig.canvas.draw()

        return True

    def __call__(self, pipe):
        print('starting plotter...')
        tosdb.init(dllpath="C:/TOSDataBridge-master/bin/Release/Win32/tos-databridge-0.9-x86.dll")
        b1 = tosdb.TOSDB_DataBlock(50, False);

        b1.add_topics('Volume');
        b1.add_topics('Last');
        b1.add_topics('LAST_SIZE');

        b1.add_items('SPY')
        self.b1 = b1;

        for item in b1.items():
            self.volumeData2[item] = [[],[],[]];
            self.priceData[item] = [[],[],[]];
            self.colors[item] = [[],[],[]];

        self.pipe = pipe
        self.fig, self.ax = plt.subplots(1, sharex=False)
        self.fig.set_size_inches((4,2.5))
        self.fig.tight_layout()
        self.fig.subplots_adjust(top=.95)

        timer = self.fig.canvas.new_timer(interval=refreshInterval*1000)
        timer.add_callback(self.call_back)
        timer.start()
        #self.socketIO = sio('localhost', 5001,  wait_for_connection=False)
        print('...done')
        plt.show()

###############################################################################
#
# Plotting class
# ==============
#
# This class uses multiprocessing to spawn a process to run code from the
# class above. When initialized, it creates a pipe and an instance of
# ``ProcessPlotter`` which will be run in a separate process.
#
# When run from the command line, the parent process sends data to the spawned
# process which is then plotted via the callback function specified in
# ``ProcessPlotter:__call__``.
#

class NBPlot(object):
    def __init__(self):

        self.plot_pipe, plotter_pipe = Pipe()
        self.plotter = ProcessPlotter()
        self.plot_process = Process(
            target=self.plotter,
            args=(plotter_pipe,)
        )
        self.plot_process.daemon = True
        self.plot_process.start()

    def plot(self, line, finished=False):
        send = self.plot_pipe.send
        recv = self.plot_pipe.recv

        if finished:
            send(None)
        else:

            send(line.strip())
            return recv()

    def check_for_triggers(self):

        command = self.plot_pipe.recv()
        print (command)
        return command;

def main():

    pl = NBPlot()

    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret!'
    socketio = SocketIO(app)

    @socketio.on('mymessage')
    def test_message(message):
        print(message)
        pl.plot(message['src'])

    socketio.run(app, port=5001)

# def add_input(input_queue):
#     while True:
#         input_queue.put(sys.stdin.readline())

    # input_queue = Queue.Queue()

    # input_thread = threading.Thread(target=add_input, args=(input_queue,))
    # input_thread.daemon = True
    # input_thread.start()

    # last_update = time.time()

    # while True:

    #     if time.time()-last_update>0.5:
    #         sys.stdout.write(".")
    #         last_update = time.time()

    #     if not input_queue.empty():
    #         line = input_queue.get()
    #         if(len(line) != 0 ):

    #
    # while True:
    #     line = sys.stdin.readline();
    #     print(line)
    #

if __name__ == '__main__':
    main()


"""
Environment
 (1) set the attribute of Node, App, BasicThroughput,
     Currently we fix the No. of App with 9, homogeneous cluster.
     The No. of Nodes could be set, No. of Containers in the batch is not required to know
 (2) Functions:
    1. _state_reset: clear state matrix
    2. step: allocate one container to a node, return new state
    3. get_tput_total_env: get the throughput of the entire cluster (after each episode)
"""
import numpy as np
from subScheduler27nodes import subScheduler
from simulator.simulator import Simulator

class LraClusterEnv():

    def __init__(self, num_nodes):
        #: Cluster configuration
        self.NUM_NODES = num_nodes # node_id: 0,1,2,...
        #: fixed 9 apps
        self.NUM_APPS = 7
        #: initialized state to zero matrix
        self._state_reset()
        # clustering
        self.baisc_oath_name = 'subScheduler_'
        path_surffix = "./checkpoint/"
        self.subScheduler_api_0 = subScheduler(path_name=self.baisc_oath_name + '0', surffix='0', path_surffix=path_surffix)
        self.subScheduler_api_1 = subScheduler(path_name=self.baisc_oath_name + '10', surffix='10', path_surffix=path_surffix)
        self.subScheduler_api_2 = subScheduler(path_name=self.baisc_oath_name + '20', surffix='20', path_surffix=path_surffix)
        self.subScheduler_api_3 = subScheduler(path_name=self.baisc_oath_name + '30', surffix='30', path_surffix=path_surffix)
        self.subScheduler_api_4 = subScheduler(path_name=self.baisc_oath_name + '40', surffix='40', path_surffix=path_surffix)
        self.subScheduler_api_5 = subScheduler(path_name=self.baisc_oath_name + '50', surffix='50', path_surffix=path_surffix)
        self.subScheduler_api_6 = subScheduler(path_name=self.baisc_oath_name + '60', surffix='60', path_surffix=path_surffix)
        self.subScheduler_api_7 = subScheduler(path_name=self.baisc_oath_name + '70', surffix='70', path_surffix=path_surffix)
        self.subScheduler_api_8 = subScheduler(path_name=self.baisc_oath_name + '80', surffix='80', path_surffix=path_surffix)
        self.subScheduler_api_9 = subScheduler(path_name=self.baisc_oath_name + '90', surffix='90', path_surffix=path_surffix)
        self.subScheduler_api_10 = subScheduler(path_name=self.baisc_oath_name + '100', surffix='100', path_surffix=path_surffix)
        self.subScheduler_api_11 = subScheduler(path_name=self.baisc_oath_name + '110', surffix='110', path_surffix=path_surffix)
        self.subScheduler_api_12 = subScheduler(path_name=self.baisc_oath_name + '120', surffix='120', path_surffix=path_surffix)
        self.subScheduler_api_13 = subScheduler(path_name=self.baisc_oath_name + '130', surffix='130', path_surffix=path_surffix)
        self.subScheduler_api_14 = subScheduler(path_name=self.baisc_oath_name + '140', surffix='140', path_surffix=path_surffix)
        self.subScheduler_api_15 = subScheduler(path_name=self.baisc_oath_name + '150', surffix='150', path_surffix=path_surffix)
        self.subScheduler_api_16 = subScheduler(path_name=self.baisc_oath_name + '160', surffix='160', path_surffix=path_surffix)
        self.subScheduler_api_17 = subScheduler(path_name=self.baisc_oath_name + '170', surffix='170', path_surffix=path_surffix)
        self.subScheduler_api_18 = subScheduler(path_name=self.baisc_oath_name + '180', surffix='180', path_surffix=path_surffix)
        self.subScheduler_api_19 = subScheduler(path_name=self.baisc_oath_name + '190', surffix='190', path_surffix=path_surffix)

        self.sim = Simulator()

    def _state_reset(self):
        self.state = np.zeros([self.NUM_NODES, self.NUM_APPS])

    def reset(self):
        self._state_reset()
        return self._get_state()

    def step(self, action, appid):
        """
        :param action: node chosen
        :param appid: current app_id of the container to be allocated
        :return: new state after allocation
        """
        curr_app = appid
        self.state[action][curr_app] += 1  # locate
        state = self._get_state()
        return state

    def _get_state(self):
        return self.state

    @property
    def _get_throughput(self):

        state_all = np.empty([0, self.NUM_APPS])

        for nid in range(self.NUM_NODES):
            container_list = self.state[nid]
            num_container = sum(container_list)
            predictor_class = int((num_container-1)/10)
            if predictor_class > 19:
                predictor_class = 19
            assert (predictor_class >= 0) & (predictor_class <= 19)
            if predictor_class == 0:
                state_this = self.subScheduler_api_0.get_total_tput(container_list)
            elif predictor_class == 1:
                state_this = self.subScheduler_api_1.get_total_tput(container_list)
            elif predictor_class == 2:
                state_this = self.subScheduler_api_2.get_total_tput(container_list)
            elif predictor_class == 3:
                state_this = self.subScheduler_api_3.get_total_tput(container_list)
            elif predictor_class == 4:
                state_this = self.subScheduler_api_4.get_total_tput(container_list)
            elif predictor_class == 5:
                state_this = self.subScheduler_api_5.get_total_tput(container_list)
            elif predictor_class == 6:
                state_this = self.subScheduler_api_6.get_total_tput(container_list)
            elif predictor_class == 7:
                state_this = self.subScheduler_api_7.get_total_tput(container_list)
            elif predictor_class == 8:
                state_this = self.subScheduler_api_8.get_total_tput(container_list)
            elif predictor_class == 9:
                state_this = self.subScheduler_api_9.get_total_tput(container_list)
            elif predictor_class == 10:
                state_this = self.subScheduler_api_10.get_total_tput(container_list)
            elif predictor_class == 11:
                state_this = self.subScheduler_api_11.get_total_tput(container_list)
            elif predictor_class == 12:
                state_this = self.subScheduler_api_12.get_total_tput(container_list)
            elif predictor_class == 13:
                state_this = self.subScheduler_api_13.get_total_tput(container_list)
            elif predictor_class == 14:
                state_this = self.subScheduler_api_14.get_total_tput(container_list)
            elif predictor_class == 15:
                state_this = self.subScheduler_api_15.get_total_tput(container_list)
            elif predictor_class == 16:
                state_this = self.subScheduler_api_16.get_total_tput(container_list)
            elif predictor_class == 17:
                state_this = self.subScheduler_api_17.get_total_tput(container_list)
            elif predictor_class == 18:
                state_this = self.subScheduler_api_18.get_total_tput(container_list)
            elif predictor_class == 19:
                state_this = self.subScheduler_api_19.get_total_tput(container_list)
            state_all = np.append(state_all, state_this, 0)

        total_tput = (self.sim.predict(state_all.reshape(-1, self.NUM_APPS)) * state_all).sum()

        return total_tput

    def get_tput_total_env(self):
        return self._get_throughput


from __future__ import division, print_function

import os, sys
import logging
import yaml
import numpy as np
import time
from . import utils
from .exposure import HugsExposure, SynthHugsExposure
from .synths.catalog import GlobalSynthCat, generate_patch_cat

from .log import HugsLogger
logging.setLoggerClass(HugsLogger)

class PipeConfig(object):
    """
    Class for parsing the hugs configuration.

    Parameters
    ----------
    config_fn : string, optional
        The parameter file name (must be a yaml file).
        If None, will use default config.
    tract : int, optional
        HSC tract.
    patch : str, optional
        HSC patch
    log_level : string, optional
        Level of python logger.
    random_state : int, list of ints, RandomState instance, or None
        If int or list of ints, random_state is the rng seed.
        If RandomState instance, random_state is the rng.
        If None, the rng is the RandomState instance used by np.random.
    run_name : sting, optional
        Label for this pipeline run.
    """

    def __init__(self, config_fn=None, tract=None, patch=None,
                 log_level='info', random_state=None, log_fn=None,
                 run_name='hugs', rerun_path=None):

        # read parameter file & setup param dicts
        self.config_fn = config_fn if config_fn else utils.default_config_fn
        with open(self.config_fn, 'r') as f:
            params = yaml.load(f, Loader=yaml.FullLoader)

        self.data_dir = rerun_path if rerun_path else params['data_dir']
        self.hugs_io = params['hugs_io']
        self.log_fn = log_fn
        self.min_good_data_frac = params['min_good_data_frac']
        self.inject_synths = params['inject_synths']
        self.coadd_label  = params.pop('coadd_label', 'deepCoadd_calexp')
        self.use_andy_mask = params.pop('use_andy_mask', True)
        if self.inject_synths:
            self.synth_cat_type = params['synth_cat_type']
            self.synth_cat_fn = params.pop('synth_cat_fn', None)
            self.synth_check_masks = params.pop('synth_check_masks',
                                                ['BRIGHT_OBJECT'])
            self.synth_sersic_params = params.pop('synth_params', {})
            self.synth_image_params = params.pop('synth_image_params', {})
            self.synth_max_match_sep = params.pop('synth_max_match_sep', 5)
            self.synth_model = params.pop('model', 'sersic')

        self.thresh_type = params['thresh_type']
        self._thresh_low = params['thresh_low']
        self._thresh_high = params['thresh_high']
        self._clean = params['clean']
        self.rng = utils.check_random_state(random_state)
        self._clean['random_state'] = self.rng
        self.log_level = log_level
        self.run_name = run_name
        self._butler = None
        self._timer = None

        self.band_mask = params['band_mask']
        self.band_detect = params['band_detect']
        self.band_verify = params['band_verify']
        self.band_meas = params['band_meas']

        self.hsc_small_sources_r_max = params.pop('hsc_small_sources_r_max', None)

        # setup for sextractor
        sex_setup = params['sextractor']
        self.sex_config = sex_setup['config']
        self.sex_config['PHOT_APERTURES'] = '3,4,5,6,7,8,16,32,42,54' # in default
        self.sex_config['PHOT_FLUXFRAC'] = '0.1,0.2,0.3,0.4,0.5,0.6,0.65,0.7,0.8,0.9'
        self.delete_created_files = sex_setup['delete_created_files']
        self.sex_io_dir = sex_setup['sex_io_dir']
        self.verify_max_sep = sex_setup['verify_max_sep']

        self.circ_aper_radii = self.sex_config['PHOT_APERTURES'].split(',')
        self.circ_aper_radii = [
            utils.pixscale*float(a)/2 for a in self.circ_aper_radii]
        self.num_apertures = len(self.circ_aper_radii)

        # setup for sep
        self.sep_steps = params.pop('sep_steps', None)
        if self.sep_steps is not None:
            sep_point_sources = params['sep_steps']['sep_point_sources']
            self.sep_min_radius = sep_point_sources.pop('min_radius', 2.0)
            self.sep_mask_grow = sep_point_sources.pop('mask_grow', 5)

        # set patch id if given
        if tract is not None:
            assert patch is not None
            self.set_patch_id(tract, patch)
        else:
            self.tract = None
            self.patch = None

    def setup_logger(self, tract, patch):
        """
        Setup the python logger.
        """
        name = 'hugs: {} | {}'.format(tract, patch)
        self.logger = logging.getLogger(name)
        self.logger._set_defaults(self.log_level.upper())
        self.logger.info('starting ' + name)

        if self.log_fn is not None:
            fh = logging.FileHandler(self.log_fn)
            self.logger.addHandler(fh)

    @property
    def butler(self):
        """
        Let's only load the butler once.
        """

        if self._butler is None:
            if '/Users/jgreco' in self.data_dir:
                from .mybutler import PersonalButler
                self._butler = PersonalButler(self.data_dir)
            else:
                import lsst.daf.persistence
                self._butler = lsst.daf.persistence.Butler(self.data_dir)
        return self._butler

    @property
    def timer(self):
        """
        Timer for pipeline.
        """

        if self._timer is None:
            self._timer = time.time()
        else:
            delta_time = (time.time() - self._timer)/60.0
            self._timer = time.time()
            return delta_time

    def reset_mask_planes(self):
        """
        Remove mask planes created by hugs-pipe.
        """

        for band in self.bands:
            mask = self.exp[band].getMaskedImage().getMask()
            utils.remove_mask_planes(mask, ['SMALL',
                                            'CLEANED',
                                            'THRESH_HIGH',
                                            'THRESH_LOW'])

    def set_patch_id(self, tract, patch):
        """
        Setup the tract/patch. This must be done before running the pipeline

        Parameters
        ----------
        tract : int
            HSC tract.
        patch : str
            HSC patch.
        """

        self.tract = tract
        self.patch = patch
        self.setup_logger(tract, patch)

        # careful not to modify parameters
        self.thresh_low = self._thresh_low.copy()
        self.thresh_high = self._thresh_high.copy()
        self.clean = self._clean.copy()

        # get exposures
        bands = self.band_detect + self.band_verify + self.band_meas
        self.bands = ''.join(set(bands))

        if self.inject_synths:
            if self.synth_cat_type == 'global':
                assert self.synth_cat_fn is not None
                self.synth_cat = GlobalSynthCat(cat_fn=self.synth_cat_fn)
            elif self.synth_cat_type == 'on-the-fly':
                self.synth_cat = generate_patch_cat(
                    sersic_params=self.synth_sersic_params,
                    **self.synth_image_params)

            self.exp = SynthHugsExposure(self.synth_cat, tract, patch,
                                         self.bands, self.butler,
                                         rerun=self.data_dir,
                                         coadd_label=self.coadd_label,
                                         band_detect=self.band_detect,
                                         use_andy_mask=self.use_andy_mask,
                                         synth_model=self.synth_model)
        else:
            self.exp = HugsExposure(tract, patch, self.bands, self.butler,
                                    band_detect=self.band_detect,
                                    rerun=self.data_dir,
                                    coadd_label=self.coadd_label,
                                    use_andy_mask=self.use_andy_mask)

        # clear detected mask and remove unnecessary plane
        for band in self.bands:
            mask = self.exp[band].getMaskedImage().getMask()
            utils.remove_mask_planes(mask, ['CR',
                                            'CROSSTALK',
                                            'DETECTED_NEGATIVE',
                                            'NOT_DEBLENDED',
                                            #'SUSPECT',
                                            'UNMASKEDNAN',
                                            'INEXACT_PSF',
                                            'REJECTED',
                                            'CLIPPED'])

        try:
            self.psf_sigma = utils.get_psf_sigma(self.exp[self.band_detect])
        except AttributeError:
            self.logger.warning('no psf with exposure... using mean seeing')
            self.psf_sigma = self.mean_seeing_sigma

        # setup thresh low/high/det: n_sig_grow --> rgrow
        ngrow = self.thresh_low.pop('n_sig_grow')
        self.thresh_low['rgrow'] = int(ngrow*self.psf_sigma + 0.5)

        ngrow = self.thresh_high.pop('n_sig_grow')
        self.thresh_high['rgrow'] = int(ngrow*self.psf_sigma + 0.5)

        # convert clean min_pix to psf units
        if 'psf sigma' in str(self.clean['min_pix_low_thresh']):
            nsig = int(self.clean['min_pix_low_thresh'].split()[0])
            self.clean['min_pix_low_thresh'] = np.pi*(nsig*self.psf_sigma)**2

        # clean n_sig_grow --> rgrow
        ngrow = self.clean.pop('n_sig_grow')
        if ngrow is None:
            self.clean['rgrow'] = None
        else:
            self.clean['rgrow'] = int(ngrow*self.psf_sigma + 0.5)
            self.logger.info('growing clean footprints with rgrow = {:.1f}'.\
                             format(self.clean['rgrow']))

        # sextractor parameter file
        fn = '{}-{}-{}-{}.params'.format(
            tract, patch[0], patch[-1], self.run_name)
        self.sex_config['PARAMETERS_NAME'] = os.path.join(self.sex_io_dir, fn)


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf
import tensorflow.contrib.slim as slim
import numpy as np
import argparse
import os
import json
import glob
import random
import collections
import math
import time

parser = argparse.ArgumentParser()
parser.add_argument("--input_dir", default="data/AB", help="path to folder containing images")
parser.add_argument("--mode", default="test", choices=["train", "test", "export"])
parser.add_argument("--output_dir", default="dqn_output", help="where to put output files")
parser.add_argument("--set-seed", type=int)
parser.add_argument("--checkpoint", help="directory with checkpoint to resume training from or use for testing")
parser.add_argument("--exp_dir", default="policy_logs", help="directory for saving experiments")

parser.add_argument("--max_steps", type=int, help="number of training steps (0 to disable)")
parser.add_argument("--max_epochs", type=int, help="number of training epochs")
parser.add_argument("--summary_freq", type=int, default=100, help="update summaries every summary_freq steps")
parser.add_argument("--progress_freq", type=int, default=50, help="display progress every progress_freq steps")
parser.add_argument("--trace_freq", type=int, default=0, help="trace execution every trace_freq steps")
parser.add_argument("--display_freq", type=int, default=0, help="write current training images every display_freq steps")
parser.add_argument("--save_freq", type=int, default=5000, help="save model every save_freq steps, 0 to disable")

parser.add_argument("--aspect_ratio", type=float, default=1.0, help="aspect ratio of output images (width/height)")
parser.add_argument("--test-eval", action="store_true", help="split input image into brightness (A) and color (B)")
parser.add_argument("--batch_size", type=int, default=100, help="number of images in batch")
parser.add_argument("--which_direction", type=str, default="AtoB", choices=["AtoB", "BtoA"])
parser.add_argument("--ngf", type=int, default=15, help="number of generator filters in first encoding layer")
parser.add_argument("--ndf", type=int, default=128, help="number of discriminator filters in first encoding layer")
parser.add_argument("--flip", dest="flip", action="store_true", help="flip images horizontally")
parser.add_argument("--no_flip", dest="flip", action="store_false", help="don't flip images horizontally")
parser.set_defaults(flip=False)
parser.add_argument("--lr", type=float, default=0.0002, help="initial learning rate for adam")
parser.add_argument("--policy_lr", type=float, default=0.0009, help="initial learning rate for adam")
parser.add_argument("--beta1", type=float, default=0.5, help="momentum term of adam")
parser.add_argument("--l1_weight", type=float, default=100.0, help="weight on L1 term for generator gradient")
parser.add_argument("--gan_weight", type=float, default=1.0, help="weight on GAN term for generator gradient")
parser.add_argument("--n_actions", type=int, default=4, help="The number of generators to predict")
parser.add_argument("--real_actions", type=int, default=4, help="The real number of actions to predict")
parser.add_argument("--n_dims", type=int, help="The number of dimensions to predict")
parser.add_argument("--env", help="The name of the environment")

# export options
parser.add_argument("--output_filetype", default="png", choices=["png", "jpeg"])
args = parser.parse_args()

EPS = 1e-12

Examples = collections.namedtuple("Examples", "paths, inputs, targets, count, steps_per_epoch")
Model = collections.namedtuple(
     "Model", "outputs, expectation, min_output, actions, gen_loss_L1, gen_grads_and_vars, train")
BCModel = collections.namedtuple(
     "Model", "actions, gen_loss_L1, gen_grads_and_vars, train")

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.01)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.01, shape=shape)
    return tf.Variable(initial)

def fully_connected(inputs, n_outputs, reuse=False, scope=None):
    inputs = slim.flatten(inputs)

    return slim.fully_connected(inputs, n_outputs, activation_fn=None, reuse=reuse, scope=scope)

    with tf.variable_scope("fc"):
        w_fc = weight_variable([int(inputs.shape[-1]), n_outputs])
        b_fc = bias_variable([n_outputs])
        return tf.matmul(inputs, w_fc) + b_fc

def lrelu(x, a):
    with tf.name_scope("lrelu"):
        # adding these together creates the leak part and linear part
        # then cancels them out by subtracting/adding an absolute value term
        # leak: a*x/2 - a*abs(x)/2
        # linear: x/2 + abs(x)/2

        # this block looks like it has 2 inputs on the graph unless we do this
        x = tf.identity(x)
        return (0.5 * (1 + a)) * x + (0.5 * (1 - a)) * tf.abs(x)

def preprocess(image):
    with tf.name_scope("preprocess"):
        # [0, 1] => [-1, 1]
        return image * 2 - 1

def deprocess(image):
    with tf.name_scope("deprocess"):
        # [-1, 1] => [0, 1]
        return (image + 1) / 2

def conv(batch_input, out_channels, stride):
    with tf.variable_scope("conv"):
        in_channels = batch_input.get_shape()[3]
        filter = tf.get_variable("filter", [4, 4, in_channels, out_channels], dtype=tf.float32, initializer=tf.random_normal_initializer(0, 0.02))
        print(filter)
        # [batch, in_height, in_width, in_channels], [filter_width, filter_height, in_channels, out_channels]
        #     => [batch, out_height, out_width, out_channels]
        padded_input = tf.pad(batch_input, [[0, 0], [1, 1], [1, 1], [0, 0]], mode="CONSTANT")
        conv = tf.nn.conv2d(padded_input, filter, [1, stride, stride, 1], padding="VALID")
        return conv

def deconv(batch_input, out_channels):
    with tf.variable_scope("deconv"):
        batch = tf.shape(batch_input)[0]
        in_height = int(batch_input.shape[1])
        in_width = int(batch_input.shape[2])
        in_channels = int(batch_input.shape[3])
        filter = tf.get_variable("filter", [4, 4, out_channels, in_channels], dtype=tf.float32, initializer=tf.random_normal_initializer(0, 0.02))
        # [batch, in_height, in_width, in_channels], [filter_width, filter_height, out_channels, in_channels]
        #     => [batch, out_height, out_width, out_channels]
        conv = tf.nn.conv2d_transpose(batch_input, filter, [batch, in_height * 2, in_width * 2, out_channels], [1, 2, 2, 1], padding="SAME")
        return conv

def check_image(image):
    assertion = tf.assert_equal(tf.shape(image)[-1], 3, message="image must have 3 color channels")
    with tf.control_dependencies([assertion]):
        image = tf.identity(image)

    if image.get_shape().ndims not in (3, 4):
        raise ValueError("image must be either 3 or 4 dimensions")

    # make the last dimension 3 so that you can unstack the colors
    shape = list(image.get_shape())
    shape[-1] = 3
    image.set_shape(shape)
    return image