#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import time

import ujson

class DateUtil:
    """
    A simple way to retrieve the current date in different formats
    """

    @staticmethod
    def current_time(as_epoch: bool = True):
        """
        Return current time

        :param as_epoch:    Whether or not the time current time
        should be returned as a UNIX epoch
        (Default: True)
        Otherwise: current time will be returned as verbose dict

        :return:
        """

        time_now_struct = time.time()

        if as_epoch:
            time_now = time_now_struct
        else:
            time_struct = time.localtime(time_now_struct)
            time_now = {
                "day_name": DateUtil._convert_time("%A", time_struct),
                "month_name": DateUtil._convert_time("%B", time_struct),
                "date_day": DateUtil._convert_time("%d", time_struct),
                "date_month": DateUtil._convert_time("%m", time_struct),
                "date_year": DateUtil._convert_time("%Y", time_struct),
                "time_hour": DateUtil._convert_time("%H", time_struct),
                "time_minute": DateUtil._convert_time("%M", time_struct),
                "time_second": DateUtil._convert_time("%S", time_struct)
            }

        return time_now

    @staticmethod
    def _convert_time(format_string: str, time_struct) -> str:
        return time.strftime(format_string, time_struct)

class FileUtil:
    """
    A simple wrapper around file I/O
    """

    @staticmethod
    def read_json(file_path) -> dict:
        """
        Read JSON data from desired file
        """

        with open(file_path, "r") as json_file:
            return ujson.load(json_file)


""" Utilities for xml usage

Interface summary:

        import xml_utils

        notes, pedals = xml_utils.xml_notes_to_midi(xml_notes)

call in feature_extraction.py and data_class.py

get xml information like note information to generate or modify xml information
"""
import pretty_midi
import copy

from . import xml_direction_encoding as dir_enc
from . import pedal_cleaning, utils

def find_tempo_change(xml_notes):
    """ Returns position of note where the tempo changes

    Args:
        xml_notes (1-D list): list of Note() object in xml of shape (num_notes, )

    Returns:
        tempo_change_positions (1-D list): list of xml_position shape (num of tempo_change_position, )

    Example:
        (in data_class.py -> _load_score_xml()
        >>> self.section_positions = xml_utils.find_tempo_change(self.xml_notes)

    """
    # TODO: This function can be simplified if it takes xml_obj or directions as the input
    tempo_change_positions = []
    previous_abs_tempo = None
    previous_rel_tempo = None
    for note in xml_notes:
        current_abs_tempo = note.tempo.absolute
        current_rel_tempo = note.tempo.relative
        if previous_abs_tempo != current_abs_tempo or previous_rel_tempo != current_rel_tempo:
            tempo_change_positions.append(note.note_duration.xml_position)
            previous_abs_tempo = current_abs_tempo
            previous_rel_tempo = current_rel_tempo

    tempo_change_positions.append(xml_notes[-1].note_duration.xml_position+0.1)
    return tempo_change_positions

def apply_directions_to_notes(xml_notes, directions, time_signatures):
    """ apply xml directions to each xml_notes

    Args:
        xml_notes (1-D list): list of Note() object in xml of shape (num_notes, )
        directions (1-D list): list of Direction() object in xml of shape (num_direction, )
        time_signatures (1-D list): list of TimeSignature() object in xml of shape (num_time_signature, )

    Returns:
        xml_notes (1-D list): list of direction-encoded Note() object in xml of shape (num_notes, )

    Example:
        (in data_class.py -> _get_direction_encoded_notes())
        >>> notes, rests = self.xml_obj.get_notes()
        >>> directions = self.xml_obj.get_directions()
        >>> time_signatures = self.xml_obj.get_time_signatures()
        >>> self.xml_notes = xml_utils.apply_directions_to_notes(notes, directions, time_signatures)
        >>> self.num_notes = len(self.xml_notes)
    """
    absolute_dynamics, relative_dynamics, cresciutos = dir_enc.get_dynamics(directions)
    absolute_dynamics_position = [dyn.xml_position for dyn in absolute_dynamics]
    absolute_tempos, relative_tempos = dir_enc.get_tempos(directions)
    absolute_tempos_position = [tmp.xml_position for tmp in absolute_tempos]
    time_signatures_position = [time.xml_position for time in time_signatures]

    num_dynamics = len(absolute_dynamics)
    num_tempos = len(absolute_tempos)

    for note in xml_notes:
        note_position = note.note_duration.xml_position

        if num_dynamics > 0:
            index = utils.binary_index(absolute_dynamics_position, note_position)
            note.dynamic.absolute = absolute_dynamics[index].type['content']
            note.dynamic.absolute_position = absolute_dynamics[index].xml_position

        if num_tempos > 0:
            tempo_index = utils.binary_index(absolute_tempos_position, note_position)
        # note.tempo.absolute = absolute_tempos[tempo_index].type[absolute_tempos[tempo_index].type.keys()[0]]
            note.tempo.absolute = absolute_tempos[tempo_index].type['content']
            note.tempo.recently_changed_position = absolute_tempos[tempo_index].xml_position
        time_index = utils.binary_index(time_signatures_position, note_position)
        note.tempo.time_numerator = time_signatures[time_index].numerator
        note.tempo.time_denominator = time_signatures[time_index].denominator
        note.tempo.time_signature = time_signatures[time_index]

        # have to improve algorithm
        for rel in relative_dynamics:
            if rel.xml_position > note_position:
                continue
            if note_position < rel.end_xml_position:
                note.dynamic.relative.append(rel)
                if rel.xml_position > note.tempo.recently_changed_position:
                    note.tempo.recently_changed_position = rel.xml_position

        for cresc in cresciutos:
            if cresc.xml_position > note_position:
                break
            if note_position < cresc.end_xml_position:
                note_cresciuto = note.dynamic.cresciuto
                if note_cresciuto is None:
                    note.dynamic.cresciuto = copy.copy(cresc)
                else:
                    prev_type = note.dynamic.cresciuto.type
                    if cresc.type == prev_type:
                        note.dynamic.cresciuto.overlapped += 1
                    else:
                        if note_cresciuto.overlapped == 0:
                            note.dynamic.cresciuto = None
                        else:
                            note.dynamic.cresciuto.overlapped -= 1

        if len(note.dynamic.relative) >1:
            note = divide_cresc_staff(note)

        for rel in relative_tempos:
            if rel.xml_position > note_position:
                continue
            if note_position < rel.end_xml_position:
                note.tempo.relative.append(rel)

    return xml_notes

def divide_cresc_staff(note):
    """ update note.dynamic

    Args:
        note: Note() object in xml_notes

    Returns:
        note: dynamic updated Note() object in xml_notes

    Example:
        (in apply_directions_to_notes())
        >>> note = divide_cresc_staff(note)
    """
    #check the note has both crescendo and diminuendo (only wedge type)
    cresc = False
    dim = False
    for rel in note.dynamic.relative:
        if rel.type['type'] == 'crescendo':
            cresc = True
        elif rel.type['type'] == 'diminuendo':
            dim = True

    if cresc and dim:
        delete_list = []
        for i in range(len(note.dynamic.relative)):
            rel = note.dynamic.relative[i]
            if rel.type['type'] in ['crescendo', 'diminuendo']:
                if (rel.placement == 'above' and note.staff ==2) or (rel.placement == 'below' and note.staff ==1):
                    delete_list.append(i)
        for i in sorted(delete_list, reverse=True):
            del note.dynamic.relative[i]

    return note

def cal_total_xml_length(xml_notes):
    """ Return proper length of total xml notes

    Args:
        xml_notes (1-D list): list of Note() object in xml of shape (num_notes, )

    Returns:
        lates_end (integer) : proper length of total xml notes

    Example:
        (in feature_extraction.py -> _get_cresciuto())
        >>> total_length = xml_utils.cal_total_xml_length(piece_data.xml_notes)

    """
    latest_end = 0
    latest_start =0
    xml_len = len(xml_notes)
    for i in range(1,xml_len):
        note = xml_notes[-i]
        current_end = note.note_duration.xml_position + note.note_duration.duration
        if current_end > latest_end:
            latest_end = current_end
            latest_start = note.note_duration.xml_position
        elif current_end < latest_start - note.note_duration.duration * 4:
            break
    return latest_end

def check_corresponding_accidental(note, accidentals):
    """ Return a key correspond to the type of accidentals on note position

    Args:
        note (Note) : Note() object in xml_notes
        accidentals (1-D list) : list of accidentals in Note() objects

    Returns:
        final_key (integer) : final key corresponds to accidental type

    Example:
        (in find_corresp_trill_notes_from_midi())
        >>> accidentals = piece_data.xml_obj.get_accidentals()
        >>> accidental_on_trill = check_corresponding_accidental(note, accidentals)
    """
    final_key = None
    for acc in accidentals:
        if acc.xml_position == note.note_duration.xml_position:
            if acc.type['content'] == '#':
                final_key = 1
                break
            elif acc.type['content'] == '♭':
                final_key = -1
                break
            elif acc.type['content'] == '♮':
                final_key = 0
                break
    return final_key

def find_corresp_trill_notes_from_midi(piece_data, perform_data, index):
    """ Return information about trill(length of trill and trill parameter) which starts from current note

    Args:
        piece_data (PieceData object) : PieceData object
        perform_data (PerformData object) : PerformData object
        index (integer) : index of current note pair

    Returns:
        trill_vec (1-D list) : list of [num_trills, last_note_velocity, first_note_ratio, last_note_ratio, up_trill] shape (5, )
        trill_length (integer) : length of current trill

    Example1:
        (in feature_extraction.py -> get_articulation())
        >>> if note.note_notations.is_trill:
        >>>     _, actual_second = xml_utils.find_corresp_trill_notes_from_midi(piece_data, perform_data, i)
        >>> else:
        >>>     actual_second = midi.end - midi.start

    Example2:
        (in feature_extraction.py -> get_trill_parameters())
        >>> if note.note_notations.is_trill:
        >>>     trill_parameter, _ = xml_utils.find_corresp_trill_notes_from_midi(piece_data, perform_data, i)
        >>> else:
        >>>     trill_parameter = [0, 0, 0, 0, 0]
    """
    #start of trill, end of trill
    key_signatures = piece_data.xml_obj.get_key_signatures()
    note = piece_data.xml_notes[index]
    num_note = piece_data.num_notes
    accidentals = piece_data.xml_obj.get_accidentals()

    key = utils.get_item_by_xml_position(key_signatures, note)
    key = key.key

    accidental_on_trill = check_corresponding_accidental(note, accidentals)
    measure_accidentals = get_measure_accidentals(piece_data.xml_notes, index)
    trill_pitch = note.pitch[1]

    up_pitch, _ = cal_up_trill_pitch(note.pitch, key, accidental_on_trill, measure_accidentals)

    prev_search = 1
    prev_idx = index
    next_idx = index
    while index - prev_search >= 0:
        prev_idx = index - prev_search
        prev_note = piece_data.xml_notes[prev_idx]
        # if prev_note.voice == note.voice: #and not pairs[prev_idx] == []:
        if prev_note.note_duration.xml_position < note.note_duration.xml_position:
            break
        elif prev_note.note_duration.xml_position == note.note_duration.xml_position and \
            prev_note.note_duration.grace_order < note.note_duration.grace_order:
            break
        else:
            prev_search += 1

    next_search = 1
    trill_end_position = note.note_duration.xml_position + note.note_duration.duration
    while index + next_search < num_note:
        next_idx = index + next_search
        next_note = piece_data.xml_notes[next_idx]
        if next_note.note_duration.xml_position > trill_end_position:
            break
        else:
            next_search += 1

    skipped_pitches_start = []
    skipped_pitches_end = []
    while perform_data.pairs[prev_idx] == [] and prev_idx >0:
        skipped_note = piece_data.xml_notes[prev_idx]
        skipped_pitches_start.append(skipped_note.pitch[1])
        prev_idx -= 1
    while perform_data.pairs[next_idx] == [] and next_idx < num_note -1:
        skipped_note = piece_data.xml_notes[next_idx]
        skipped_pitches_end.append(skipped_note.pitch[1])
        next_idx += 1

    if perform_data.pairs[next_idx] == [] or perform_data.pairs[prev_idx] == []:
        print("Error: Cannot find trill start or end note")
        return [0] * 5, 0
    prev_midi_note = perform_data.pairs[prev_idx]['midi']
    next_midi_note = perform_data.pairs[next_idx]['midi']
    search_range_start = perform_data.midi_notes.index(prev_midi_note)
    search_range_end = perform_data.midi_notes.index(next_midi_note)
    trills = []
    prev_pitch = None
    if len(skipped_pitches_end) > 0:
        end_cue = skipped_pitches_end[0]
    else:
        end_cue = None
    for i in range(search_range_start+1, search_range_end):
        midi_note = perform_data.midi_notes[i]
        cur_pitch = midi_note.pitch
        if cur_pitch in skipped_pitches_start:
            skipped_pitches_start.remove(cur_pitch)
            continue
        elif cur_pitch == trill_pitch or cur_pitch == up_pitch:
            # if cur_pitch == prev_pitch:
            #     next_midi_note = midi_note
            #     break
            # else:
            trills.append(midi_note)
            prev_pitch = cur_pitch
        elif cur_pitch == end_cue:
            next_midi_note = midi_note
            break
        elif 0 < midi_note.pitch - trill_pitch < 4:
            print('check trill pitch - detected pitch: ', midi_note.pitch, ' trill note pitch: ', trill_pitch,
                  'expected up trill pitch: ', up_pitch, 'time:', midi_note.start, 'measure: ', note.measure_number)

    # while len(skipped_pitches_start) > 0:
    #     skipped_pitch = skipped_pitches_start[0]
    #     if trills[0].pitch == skipped_pitch:
    #         dup_note = trills[0]
    #         trills.remove(dup_note)
    #     skipped_pitches_start.remove(skipped_pitch)
    #
    # while len(skipped_pitches_end) > 0:
    #     skipped_pitch = skipped_pitches_end[0]
    #     if trills[-1].pitch == skipped_pitch:
    #         dup_note = trills[-1]
    #         trills.remove(dup_note)
    #     skipped_pitches_end.remove(skipped_pitch)

    trills_vec = [0] * 5 # num_trills, last_note_velocity, first_note_ratio, last_note_ratio, up_trill
    num_trills = len(trills)

    if num_trills == 0:
        return trills_vec, 0
    elif num_trills == 1:
        return trills_vec, 1
    elif num_trills > 2 and trills[-1].pitch == trills[-2].pitch:
        del trills[-1]
        num_trills -= 1

    if trills[0].pitch == up_pitch:
        up_trill = True
    else:
        up_trill = False

    ioi_seconds = []
    prev_start = trills[0].start
    next_note_start = next_midi_note.start
    trill_length = next_note_start - prev_start
    for i in range(1, num_trills):
        ioi = trills[i].start - prev_start
        ioi *= (num_trills / trill_length)
        ioi_seconds.append(ioi)
        prev_start = trills[i].start
    ioi_seconds.append( (next_note_start - trills[-1].start) *  num_trills / trill_length )
    trill_density = num_trills / trill_length

    if trill_density < 1:
        return trills_vec, trill_length

    trills_vec[0] = num_trills / trill_length
    trills_vec[1] = trills[-1].velocity / trills[0].velocity
    trills_vec[2] = ioi_seconds[0]
    trills_vec[3] = ioi_seconds[-1]
    trills_vec[4] = int(up_trill)

    if perform_data.pairs[index] == []:
        for pair in perform_data.pairs:
            if not pair == [] and pair['midi'] == trills[0]:
                pair = []
        perform_data.pairs[index] = {'xml': note, 'midi': trills[0]}

    # for num in trills_vec:
    #     if math.isnan(num):
    #         print('trill vec is nan')
    #         num = 0

    return trills_vec, trill_length

def get_measure_accidentals(xml_notes, index):
    """ Return pitch-accidental pairs list for current measure

    Args:
        xml_notes (1-D list): list of Note() object in xml of shape (num_notes, )
        index (integer) : index of current note pair

    Returns:
        measure_accidentals (1-D list): list of {pitch, accident} dictionary pair

    Example1:
        (in find_corresp_trill_notes_from_midi())
        >>> measure_accidentals = get_measure_accidentals(piece_data.xml_notes, index)
    """
    accs = ['bb', 'b', '♮', '#', 'x']
    note = xml_notes[index]
    num_note = len(xml_notes)
    measure_accidentals=[]
    for i in range(1,num_note):
        prev_note = xml_notes[index - i]
        if prev_note.measure_number != note.measure_number:
            break
        else:
            for acc in accs:
                if acc in prev_note.pitch[0]:
                    pitch = prev_note.pitch[0][0] + prev_note.pitch[0][-1]
                    for prev_acc in measure_accidentals:
                        if prev_acc['pitch'] == pitch:
                            break
                    else:
                        accident = accs.index(acc) - 2
                        temp_pair = {'pitch': pitch, 'accident': accident}
                        measure_accidentals.append(temp_pair)
                        break
    return measure_accidentals

def cal_up_trill_pitch(pitch_tuple, key, final_key, measure_accidentals):
    """ Return

    Args:
        pitch_tuple (tuple) : pitch information in (Pitch Name, MIDI number) format
        key (integer) : MIDI and MusicXML identify key by using "fifths"
              -1 = F, 0 = C, 1 = G etc.
        final_key (integer) : final key delta by check_corresponding_accidental()
        measure_accidentals (1-D list): list of {pitch, accident} dictionary pair

    Returns:
        up_pitch (integer) : final pitch value
        final_pitch_string (string) : final pitch value in string format

    Example1:
        (in find_corresp_trill_notes_from_midi())
        >>> up_pitch, _ = cal_up_trill_pitch(note.pitch, key, accidental_on_trill, measure_accidentals)

    """
    pitches = ['c', 'd', 'e', 'f', 'g', 'a', 'b']
    corresp_midi_pitch = [0, 2, 4, 5, 7, 9, 11]
    pitch_name = pitch_tuple[0][0:1].lower()
    octave = int(pitch_tuple[0][-1])
    next_pitch_name = pitches[(pitches.index(pitch_name)+1)%7]
    if next_pitch_name == 'c':
        octave += 1

    if final_key:
        acc = final_key
    else:
        accidentals = ['f', 'c', 'g', 'd', 'a', 'e', 'b']
        if key > 0 and next_pitch_name in accidentals[:key]:
            acc = +1
        elif key < 0 and next_pitch_name in accidentals[key:]:
            acc = -1
        else:
            acc = 0

    pitch_string = next_pitch_name + str(octave)
    for pitch_acc_pair in measure_accidentals:
        if pitch_string == pitch_acc_pair['pitch'].lower():
            acc = pitch_acc_pair['accident']

    if not final_key == None:
        acc= final_key

    if acc == 0:
        acc_in_string = ''
    elif acc ==1:
        acc_in_string = '#'
    elif acc ==-1:
        acc_in_string = '♭'
    else:
        acc_in_string = ''
    final_pitch_string = next_pitch_name.capitalize() + acc_in_string + str(octave)
    up_pitch = 12 * (octave + 1) + corresp_midi_pitch[pitches.index(next_pitch_name)] + acc

    return up_pitch, final_pitch_string

def xml_notes_to_midi(xml_notes, multi_instruments=False, ignore_overlapped=True):
    """ Returns midi-transformed xml notes in pretty_midi.Note() format

    Args:
        xml_notes (1-D list): list of Note() object in xml of shape (num_notes, )

    Returns:
        midi_notes (1-D list): list of pretty_midi.Note() of shape (num_notes, )
        midi_pedals (1-D list): list of pretty_midi pedal value of shape (num_pedals, )

    Example:
        (in data_class.py -> make_score_midi())
        >>> midi_notes, midi_pedals = xml_utils.xml_notes_to_midi(self.xml_notes)

    """
    if multi_instruments:
        num_instruments = max([x.voice for x in xml_notes]) // 10 + 1
        midi_notes = [ [] for i in range(num_instruments) ]
    else:
        midi_notes = []
    for i, note in enumerate(xml_notes):
        if note.is_overlapped and not multi_instruments and ignore_overlapped:  # ignore overlapped notes.
            continue

        pitch = note.pitch[1]
        start = note.note_duration.time_position
        end = start + note.note_duration.seconds

        if note.note_duration.seconds < 0.005:
            end = start + 0.005
        elif note.note_duration.seconds > 10:
            end = start + 10
        velocity = int(min(max(note.velocity,0),127))
        midi_note = pretty_midi.Note(velocity=velocity, pitch=pitch, start=start, end=end)
        midi_note.channel = note.voice // 10
        midi_note.xml_idx = i

        if hasattr(note, "cluster"):
            midi_note.cluster = note.cluster
        else:
            midi_note.cluster = 0
        if hasattr(note, "attention_weights"):
            midi_note.attention_weights = note.attention_weights
        if multi_instruments:
            instrument_idx = note.voice // 10
            midi_notes[instrument_idx].append(midi_note)
        else:
            midi_notes.append(midi_note)
    if multi_instruments:
        midi_pedals = []
        for i in range(num_instruments):
            notes = [note for note in xml_notes if (note.voice//10)==i]
            pedals = pedal_cleaning.predicted_pedals_to_midi_pedals(notes)
            midi_pedals.append(pedals)
    else:
        midi_pedals = pedal_cleaning.predicted_pedals_to_midi_pedals(xml_notes)

    return midi_notes, midi_pedals


import time
from optparse import OptionParser

from naoqi import ALProxy
from naoqi import ALBroker
from naoqi import ALModule

from helpers.segment import find_objects

class SegmentationModule(ALModule):
	"""
	A module to handle object detection
	"""

	def __init__(self, name):
		ALModule.__init__(self, name)

	def look_for_objects(self):
		"""
		This method causes the robot to stand up and look around.
		Returns an array of objects
		"""

		return find_objects()

def main():
	"""
	Boilerplate method to register the module
	"""

	parser = OptionParser()
	parser.add_option("--pip", dest="pip")
	parser.add_option("--pport", dest="pport", type="int")
	parser.set_defaults(pip="localhost", pport=9559)

	(opts, args_) = parser.parse_args()
	pip = opts.pip
	pport = opts.pport

	broker = ALBroker("broker", "0.0.0.0", 0, pip, pport)

	global Segmentation
	Segmentation = SegmentationModule("Segmentation")

	while True:
		time.sleep(1)

main()


import os
import subprocess
import unittest
mock
# from tic_tac_toe import X_0

p = subprocess.Popen(
    ['python3', './tic_tac_toe.py'], stdin=subprocess.PIPE,
    stdout=subprocess.PIPE, universal_newlines=True
)
out, err = p.communicate('A')
print(p.stdout, '++')
p.stdin.write('A')
p.stdin.write('B')
# while out:
#     out = p.stdout.readline()
#     print(out, end='')

print('dd\n', '\b' + out, err, '---')
# out, err = p.communicate()
p.stdin.write('A')
p.stdin.write('B')
# print('asdfdddddddddd')
# out, err = p.communicate("B\n")
# out, err = p.communicate("0\n")
# out, err = p.communicate("3\n")
# out, err = p.communicate("1\n")
# out, err = p.communicate("4\n")
# out, err = p.communicate("2\n")
print('begin')
print(out, '***')

# p=subprocess.Popen("test.exe", stdin =subprocess.PIPE, stdout =subprocess.PIPE, stderr =subprocess.PIPE )
# p.communicate("текст от пользователя \n")

# import subprocess
# import sys
# child = subprocess.Popen(command, shell=True, stderr=subprocess.PIPE)
# while True:
#     out = child.stderr.read(1)
#     if out == '' and child.poll() != None:
#         break
#     if out != '':
#         sys.stdout.write(out)
#         sys.stdout.flush()

# class TestX_0(unittest.TestCase):
#     def test_X_0(self):
#         name1 = 'A'
#         name2= 'B'
#         expected_output = '''             |     |
#           0  |  1  |  2
#         _____|_____|_____
#              |     |
#           3  |  4  |  5
#         _____|_____|_____
#              |     |
#           6  |  7  |  8
#              |     |   '''
#         with os.popen(f"echo '{name1}' | python3 tic_tac_toe.py") as o:
#             output = o.read()
#         with os.popen(f"echo {name2}' | python3 tic_tac_toe.py") as o:
#             output = o.read()
#         output = output.strip()
#         self.assertEqual(output, expected_output)

# if __name__ == '__main__':
#     unittest.main()


import argparse
import logging
import math
from datetime import datetime

import kalasiris as isis
import hiproc.util as util
import hiproc.HiColorInit as hicolor
import hiproc.HiJitReg as hjr

logger = logging.getLogger(__name__)

def arg_parser():
    parser = argparse.ArgumentParser(
        description=__doc__,
        parents=[util.parent_parser()],
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument(
        "cubes",
        metavar="RED balance.cub and color balance.precolor.cub files",
        nargs="+",
        help=r"Either one or both sets of RED .balance.cub  and IR/BG "
             r".balance.precolor.cub files. However, that's tedious to type,"
             r"so you could just type in *.balance*cub here, and the program "
             r"will sort out what it needs."
    )
    return parser

def main():
    args = arg_parser().parse_args()

    util.set_logger(args.verbose, args.logfile, args.log)

    with util.main_exceptions(args.verbose):
        HiSlither(args.cubes, keep=args.keep)
    return

def HiSlither(cube_paths: list, keep=False):
    cubes = list(map(hicolor.HiColorCube, cube_paths))
    (red4, red5, ir10, ir11, bg12, bg13) = hicolor.separate_ccds(cubes)

    ccds = list()
    for c in red4, red5, ir10, ir11, bg12, bg13:
        if c is not None:
            ccds.append(str(c))

    logger.info(f"HiSlither start: {', '.join(map(str, ccds))}")

    completed = list()
    if cube_check(red4, ir10, bg12):
        completed.append(str(process_set(red4, ir10, bg12, keep=keep)))

    if cube_check(red5, ir11, bg13):
        completed.append(str(process_set(red5, ir11, bg13, keep=keep)))

    logger.info(f"HiSlither done: {', '.join(completed)}")

    return

def cube_check(
    red: hicolor.HiColorCube, ir: hicolor.HiColorCube, bg: hicolor.HiColorCube
) -> bool:
    if red is None and ir is None and bg is None:
        return False

    if red is None or bg is None:
        # have_ccds = list(filter(lambda x: x is not None, [red, ir, bg]))
        # if len(have_ccds) == 1:
        #     have_str = str(have_ccds[0])
        # else:
        #     have_str = "{} and {}".format(*have_ccds)
        # logger.info(
        #     f"For a slither set, we need at least a RED and BG CCD. "
        #     f"We only have: {have_str}, so no set will be made from these."
        # )
        return False

    return True

def process_set(
    red: hicolor.HiColorCube,
    ir: hicolor.HiColorCube,
    bg: hicolor.HiColorCube,
    keep=False,
):
    if red is None:
        raise TypeError("Expected a RED HiColorCube, but got None.")
    if bg is None:
        raise TypeError("Expected a BG HiColorCube, but got None.")

    logger.info("Beginning HiSlither for {}".format(str(red)))

    temp_token = datetime.now().strftime("HiSlither-%y%m%d%H%M%S")

    if ir is None:
        # If the IR band is missing, it is filled with a "dummy" band
        # consisting entirely of null pixels. This band is created by
        # masking the red band with itself. The dummy band allows for
        # RGB (synthetic B) to be created by HiBeautify even if the
        # IR band is missing.
        logger.info("Missing IR, creating a null band.")
        ir_slither_p = make_dummy_IR(red, bg)
        ir = hicolor.HiColorCube(ir_slither_p)
    else:
        ir_slither_p = run_slither(ir)

    bg_slither_p = run_slither(bg)

    logger.info("Slither finished, merging stacks.")
    logger.info(
        "Creating {}-{}-{} mosaic".format(
            ir.get_ccd(), red.get_ccd(), bg.get_ccd()
        )
    )

    stacked_path = red.path.parent / "{}_COLOR{}.cub".format(
        red.get_obsid(), red.ccdnumber
    )
    tmp_stack = stacked_path.with_suffix(f".{temp_token}.cub")
    isis.hicubeit(ir=ir_slither_p, red=red.path, bg=bg_slither_p, to=tmp_stack)

    trim_args = {"from": tmp_stack, "to": stacked_path}
    # trim 5 px in bin 1, 3 in bin 2, 2 in bin 4
    trim = math.ceil(5 / red.bin)
    if red.ccdnumber == "4":
        trim_args["right"] = trim
    else:
        trim_args["left"] = trim
    isis.trim(**trim_args)

    if not keep:
        tmp_stack.unlink()

    return stacked_path

def get_slither_path(cube):
    return cube.path.parent / "{}.slither.cub".format(str(cube))

def run_slither(cube):
    cnet_path = hjr.JitterCube.get_cnet_path(cube)
    s = get_slither_path(cube)
    t = s.with_suffix(".txt")
    isis.slither(
        cube.path,
        to=s,
        control=cnet_path,
        results=t,
        dir="REVERSE",
        spline="CUBIC",
        interp="BILIN",
    )
    return s

def make_dummy_IR(red: hicolor.HiColorCube, bg: hicolor.HiColorCube):
    bg_slither_path = get_slither_path(bg)
    ir_name = bg_slither_path.name.replace(
        bg.get_ccd(), "IR" + str(int(bg.ccdnumber) - 2)
    )
    ir_path = bg_slither_path.parent / ir_name

    if ir_path.exists():
        raise FileExistsError(
            "{} exists ".format(str(ir_path))
            + "and we don't want to overwrite it."
        )

    ir_ccd = "IR" + str(int(red.ccdnumber) + 6)

    isis.mask(red.path, mask=red.path, to=ir_path, preserve="outside")
    isis.editlab(
        ir_path,
        options="modkey",
        grpname="Instrument",
        keyword="CpmmNumber",
        value=int(red.ccdnumber) + 2,
    )
    isis.editlab(
        ir_path,
        options="modkey",
        grpname="Instrument",
        keyword="CcdId",
        value=ir_ccd,
    )
    isis.editlab(
        ir_path,
        options="modkey",
        grpname="Archive",
        keyword="ProductID",
        value="{}_{}".format(red.get_obsid(), ir_ccd),
    )
    isis.editlab(
        ir_path,
        options="modkey",
        grpname="BandBin",
        keyword="Name",
        value="NearInfrared",
    )
    isis.editlab(
        ir_path,
        options="modkey",
        grpname="BandBin",
        keyword="Center",
        value=900,
        units="NANOMETERS",
    )
    isis.editlab(
        ir_path,
        options="modkey",
        grpname="BandBin",
        keyword="Width",
        value=200,
        units="NANOMETERS",
    )
    return ir_path


from src.main.base_solution import BaseSolution
from src.util import *

class Solution(BaseSolution):

    def _parse_grid(self):
        return self.parser.to_number_grid(separator="")

    def _do_flash(self, levels, cells):
        all_neighbors = flatten([levels.get_neighbor_cells(cell.coord, include_diagonal=True) for cell in cells])
        for neighbor in all_neighbors:
            if neighbor.value > 0:
                neighbor.value += 1
        cells_to_flash = {neighbor for neighbor in set(all_neighbors) if neighbor.value >= 10}
        if len(cells_to_flash) == 0:
            return levels, len(cells)
        else:
            for cell in cells_to_flash:
                cell.value = 0
            levels, sub_flashes = self._do_flash(levels, cells_to_flash)
            return levels, len(cells) + sub_flashes

    def _step(self, levels, step, flashes, stop_condition):
        levels = levels.map_values_by_function(lambda x: x + 1 if x < 9 else 0)
        cells_to_flash = levels.find_cells_by_value(0)
        levels, step_flashes = self._do_flash(levels, cells_to_flash)

        if stop_condition(levels, step):
            return step, flashes + step_flashes
        else:
            return self._step(levels, step + 1, flashes + step_flashes, stop_condition)

    def puzzle1(self):
        last_step, flashes = self._step(self._parse_grid(), 1, 0, lambda levels, step: step == 100)
        return flashes

    def puzzle2(self):
        last_step, flashes = self._step(
            self._parse_grid(), 1, 0, lambda levels, step: len(levels.find_cells_by_value(0)) == len(levels.flatten()))
        return last_step

Solution().run(1, SAMPLE)


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # APP1: recurssion
    def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        left = self.maxDepth(root.left)
        right = self.maxDepth(root.right)
        return max(left, right) + 1

    # APP2: BFS
    def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        q = collections.deque([root])
        ans = 0
        while q:
            size = len(q)
            ans += 1
            for _ in range(size):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
        return ans

    def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        stack = [(root, 1)]
        max_depth = 0
        while stack:
            node, depth = stack.pop()
            max_depth = max(max_depth, depth)
            if node.left:
                stack.append((node.left, depth + 1))
            if node.right:
                stack.append((node.right, depth + 1))
        return max_depth

DFS/Binary Tree/104. Maximum Depth of Binary Tree.py


import keras
import matplotlib.pyplot as plt

def model_paint(model, filepath="./"):
    """
        when rankdir == "TB", vertical layout can be showed
    """
    keras.utils.plot_model(model,
        to_file=filepath + "//model.png",
        show_shapes=True,
        show_layer_names=True,
        rankdir='TB')

def acc_loss_paint(history, filepath="./"):

    plt.figure()
    plt.subplot(1, 2, 1)
    plt.plot(history.history['acc'])
    plt.plot(history.history['val_acc'])
    plt.title('Model accuracy')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend(['acc', "val_acc"], loc='lower right')

    plt.subplot(1, 2, 2)
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model loss')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend(['loss', "val_loss"], loc='lower right')
    plt.tight_layout()
    plt.savefig(filepath + "//acc_loss.png")


## TO DO: REMOVE THE ENCODER PART AND ADAPT THE CODE.
### OR JUST ADD THE ATTENTION MECANISM TO THE LSTM models?

import tensorflow as tf
import unicodedata
import re
import numpy as np
import os
import io
import time

class BahdanauAttention(tf.keras.layers.Layer):
  def __init__(self, units):
    super(BahdanauAttention, self).__init__()
    self.W1 = tf.keras.layers.Dense(units)
    self.W2 = tf.keras.layers.Dense(units)
    self.V = tf.keras.layers.Dense(1)

  def call(self, query, values):
    # hidden shape == (batch_size, hidden size)
    # hidden_with_time_axis shape == (batch_size, 1, hidden size)
    # we are doing this to perform addition to calculate the score
    hidden_with_time_axis = tf.expand_dims(query, 1)

    # score shape == (batch_size, max_length, 1)
    # we get 1 at the last axis because we are applying score to self.V
    # the shape of the tensor before applying self.V is (batch_size, max_length, units)
    score = self.V(tf.nn.tanh(
        self.W1(values) + self.W2(hidden_with_time_axis)))

    # attention_weights shape == (batch_size, max_length, 1)
    attention_weights = tf.nn.softmax(score, axis=1)

    # context_vector shape after sum == (batch_size, hidden_size)
    context_vector = attention_weights * values
    context_vector = tf.reduce_sum(context_vector, axis=1)

    return context_vector, attention_weights

attention_layer = BahdanauAttention(10)
attention_result, attention_weights = attention_layer(sample_hidden, sample_output)

print("Attention result shape: (batch size, units) {}".format(attention_result.shape))
print("Attention weights shape: (batch_size, sequence_length, 1) {}".format(attention_weights.shape))


from imutils.video import VideoStream
import time
import cv2
from face_processing import face_processing
face_pro=face_processing()
print("[INFO] starting video stream...")
video = VideoStream(src=0).start()     # có thể chọn cam bằng cách thay đổi src
writer = None
print("[INFO] Opening...")
time.sleep(2.)
model="lfw_model.pkl"
print("Mời bạn hãy mở khó bằng khuôn mặt")
while True:
    frame = video.read()
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    print("[INFO] recognizing faces...")
    name=face_pro.predict_face(rgb,model)
    if name!="UNKNOWN":
        print("Chào mừng",name)
        break
    elif name=="UNKNOWN":
        print("Khuôn mặt không khớp!")
        break


test = int(input())
for t in range(1,test+1):
    n, m = map(int, input().split())
    arr = [input() for _ in range(n)]
    # init
    num = {'0001101' : 0,'0011001' : 1,'0010011' : 2,'0111101' : 3,'0100011' : 4,
           '0110001' : 5,'0101111' : 6,'0111011' : 7,'0110111' : 8,'0001011' : 9}
    length = 7
    total = 0
    num_total = 0

    # 입력된 암호코드 해독
    # 한 줄씩 읽기
    for s in arr:
        # 역방향으로 '1'을 찾음
        # 0~9의 코드들이 다 1로 끝나는 암호코드를 가지고 있음 -> 이를 이용한 위치 파악
        # 이는 전체 코드문 중 암호문이 어디에 있는지 파악하기 위함
        idx = s.rfind('1')
        if idx != -1:
            # 암호코드 있는 부분만 추출
            buff = s[idx - 55:idx + 1]
            # 8칸으로 나눠서 추출
            for i in range(0, length * 8, length):
                # 해당 암호코드와 일치하는 숫자 저장
                num_buff = num[buff[i:i + length]]
                # 짝수면 3을 곱해서 총합에 더해줌
                if i % 2 == 0:
                    total += (num_buff * 3)
                # 홀수면 그냥 총합에 더해줌
                else:
                    total += num_buff
                # 숫자를 숫자합계에 더해줌
                num_total += num_buff
            # 10의 배수일 시 -> 검증
            if total % 10 == 0:
                break
            else:
                total, num_total = 0, 0

    print("#{} {}".format(t,num_total))

1240_[SW문제해결응용]1일차-단순2진암호코드.py


# -*- coding: utf-8 -*-
"""
Created on Sat Oct 01 20:20:16 2011

Author: Josef Perktold
License: BSD-3

TODO:
check orientation, size and alpha should be increasing for interp1d,
but what is alpha? can be either sf or cdf probability
change it to use one consistent notation

check: instead of bound checking I could use the fill-value of the
interpolators
"""
import numpy as np
from scipy.interpolate import interp1d, interp2d, Rbf

from statsmodels.tools.decorators import cache_readonly

class TableDist:
    """
    Distribution, critical values and p-values from tables

    currently only 1 extra parameter, e.g. sample size

    Parameters
    ----------
    alpha : array_like, 1d
        probabiliy in the table, could be either sf (right tail) or cdf (left
        tail)
    size : array_like, 1d
        The sample sizes for the table
    crit_table : array_like, 2d
        The sample sizes in the table
        array with critical values for sample size in rows and probability in
        columns
    asymptotic : callable, optional
        Callable function with the form fn(nobs) that returns len(alpha)
        critical values where the critical value in position i corresponds to
        alpha[i]
    min_nobs : int, optional
        Minimum number of observations to use the asymptotic distribution. If
        not provided, uses max(size).
    max_nobs : int, optional
        Maximum number of observations to use the tabular distribution. If not
        provided, uses max(size)

    Notes
    -----
    size and alpha must be sorted and increasing.

    If both min_nobs and max_nobs are provided, then
    the critical values from the tabular distribution and the asymptotic
    distribution are linearly blended using the formula
    :math:`w cv_a + (1-w) cv_t` where the weight is
    :math:`w = (n - a_{min}) / (a_{max} - a_{min})`. This ensures the
    transition between the tabular and the asymptotic critical values is
    continuous. If these are not provided, then the asymptotic critical value
    is used for nobs > max(size).
    """

    def __init__(self, alpha, size, crit_table, asymptotic=None,
                 min_nobs=None, max_nobs=None):
        self.alpha = np.asarray(alpha)
        if self.alpha.ndim != 1:
            raise ValueError('alpha is not 1d')
        elif (np.diff(self.alpha) <= 0).any():
            raise ValueError('alpha is not sorted')
        self.size = np.asarray(size)
        if self.size.ndim != 1:
            raise ValueError('size is not 1d')
        elif (np.diff(self.size) <= 0).any():
            raise ValueError('size is not sorted')
        if self.size.ndim == 1:
            if (np.diff(alpha) <= 0).any():
                raise ValueError('alpha is not sorted')
        self.crit_table = np.asarray(crit_table)
        if self.crit_table.shape != (self.size.shape[0], self.alpha.shape[0]):
            raise ValueError('crit_table must have shape'
                             '(len(size), len(alpha))')

        self.n_alpha = len(alpha)
        self.signcrit = np.sign(np.diff(self.crit_table, 1).mean())
        if self.signcrit > 0:  # increasing
            self.critv_bounds = self.crit_table[:, [0, 1]]
        else:
            self.critv_bounds = self.crit_table[:, [1, 0]]
        self.asymptotic = None
        max_size = self.max_size = max(size)

        if asymptotic is not None:
            try:
                cv = asymptotic(self.max_size + 1)
            except Exception as exc:
                raise type(exc)('Calling asymptotic(self.size+1) failed. The '
                                'error message was:'
                                '\n\n{err_msg}'.format(err_msg=exc.args[0]))
            if len(cv) != len(alpha):
                raise ValueError('asymptotic does not return len(alpha) '
                                 'values')
            self.asymptotic = asymptotic

        self.min_nobs = max_size if min_nobs is None else min_nobs
        self.max_nobs = max_size if max_nobs is None else max_nobs
        if self.min_nobs > max_size:
            raise ValueError('min_nobs > max(size)')
        if self.max_nobs > max_size:
            raise ValueError('max_nobs > max(size)')

    @cache_readonly
    def polyn(self):
        polyn = [interp1d(self.size, self.crit_table[:, i])
                 for i in range(self.n_alpha)]
        return polyn

    @cache_readonly
    def poly2d(self):
        # check for monotonicity ?
        # fix this, interp needs increasing
        poly2d = interp2d(self.size, self.alpha, self.crit_table)
        return poly2d

    @cache_readonly
    def polyrbf(self):
        xs, xa = np.meshgrid(self.size.astype(float), self.alpha)
        polyrbf = Rbf(xs.ravel(), xa.ravel(), self.crit_table.T.ravel(),
                      function='linear')
        return polyrbf

    def _critvals(self, n):
        """
        Rows of the table, linearly interpolated for given sample size

        Parameters
        ----------
        n : float
            sample size, second parameter of the table

        Returns
        -------
        critv : ndarray, 1d
            critical values (ppf) corresponding to a row of the table

        Notes
        -----
        This is used in two step interpolation, or if we want to know the
        critical values for all alphas for any sample size that we can obtain
        through interpolation
        """
        if n > self.max_size:
            if self.asymptotic is not None:
                cv = self.asymptotic(n)
            else:
                raise ValueError('n is above max(size) and no asymptotic '
                                 'distribtuion is provided')
        else:
            cv = ([p(n) for p in self.polyn])
            if n > self.min_nobs:
                w = (n - self.min_nobs) / (self.max_nobs - self.min_nobs)
                w = min(1.0, w)
                a_cv = self.asymptotic(n)
                cv = w * a_cv + (1 - w) * cv

        return cv

    def prob(self, x, n):
        """
        Find pvalues by interpolation, either cdf(x)

        Returns extreme probabilities, 0.001 and 0.2, for out of range

        Parameters
        ----------
        x : array_like
            observed value, assumed to follow the distribution in the table
        n : float
            sample size, second parameter of the table

        Returns
        -------
        prob : array_like
            This is the probability for each value of x, the p-value in
            underlying distribution is for a statistical test.
        """
        critv = self._critvals(n)
        alpha = self.alpha

        if self.signcrit < 1:
            # reverse if critv is decreasing
            critv, alpha = critv[::-1], alpha[::-1]

        # now critv is increasing
        if np.size(x) == 1:
            if x < critv[0]:
                return alpha[0]
            elif x > critv[-1]:
                return alpha[-1]
            return interp1d(critv, alpha)(x)[()]
        else:
            # vectorized
            cond_low = (x < critv[0])
            cond_high = (x > critv[-1])
            cond_interior = ~np.logical_or(cond_low, cond_high)

            probs = np.nan * np.ones(x.shape)  # mistake if nan left
            probs[cond_low] = alpha[0]
            probs[cond_low] = alpha[-1]
            probs[cond_interior] = interp1d(critv, alpha)(x[cond_interior])

            return probs

    def crit(self, prob, n):
        """
        Returns interpolated quantiles, similar to ppf or isf

        use two sequential 1d interpolation, first by n then by prob

        Parameters
        ----------
        prob : array_like
            probabilities corresponding to the definition of table columns
        n : int or float
            sample size, second parameter of the table

        Returns
        -------
        ppf : array_like
            critical values with same shape as prob
        """
        prob = np.asarray(prob)
        alpha = self.alpha
        critv = self._critvals(n)

        # vectorized
        cond_ilow = (prob > alpha[0])
        cond_ihigh = (prob < alpha[-1])
        cond_interior = np.logical_or(cond_ilow, cond_ihigh)

        # scalar
        if prob.size == 1:
            if cond_interior:
                return interp1d(alpha, critv)(prob)
            else:
                return np.nan

        # vectorized
        quantile = np.nan * np.ones(prob.shape)  # nans for outside
        quantile[cond_interior] = interp1d(alpha, critv)(prob[cond_interior])
        return quantile

    def crit3(self, prob, n):
        """
        Returns interpolated quantiles, similar to ppf or isf

        uses Rbf to interpolate critical values as function of `prob` and `n`

        Parameters
        ----------
        prob : array_like
            probabilities corresponding to the definition of table columns
        n : int or float
            sample size, second parameter of the table

        Returns
        -------
        ppf : array_like
            critical values with same shape as prob, returns nan for arguments
            that are outside of the table bounds
        """
        prob = np.asarray(prob)
        alpha = self.alpha

        # vectorized
        cond_ilow = (prob > alpha[0])
        cond_ihigh = (prob < alpha[-1])
        cond_interior = np.logical_or(cond_ilow, cond_ihigh)

        # scalar
        if prob.size == 1:
            if cond_interior:
                return self.polyrbf(n, prob)
            else:
                return np.nan

        # vectorized
        quantile = np.nan * np.ones(prob.shape)  # nans for outside

        quantile[cond_interior] = self.polyrbf(n, prob[cond_interior])
        return quantile


import requests
import serial
import time
import sys
from selenium import webdriver

def main(current_exam):
    ip_address = "http://127.0.0.1:8000"

    """ CHECKING THE EXISTENCE OF THE ENTERED COURSE """
    try:
        ex_url = ip_address + "/exams/check-course/"
        response = requests.post(ex_url, data={"current_exam": current_exam})
        if response.json()["response"] == "EXAM APPROVED":
            pass
        else:
            print(response.json())
            sys.exit()
    except requests.ConnectionError or requests.Timeout:
        print("\nWEB SERVER NOT RUNNING!!!")
        sys.exit()

    """
    ESTABLISHING MICRO CONTROLLER CONNECTIONS
    """

    number = 1
    port_open = False
    while not port_open and number <= 30:
        arduino_port = "COM" + str(number)
        print(number)
        print("Connecting to MICRO CONTROLLER on port ", arduino_port)
        try:
            global connect
            connect = serial.Serial(arduino_port, timeout=1)
            print("Successfully connected to MICRO CONTROLLER on ", arduino_port)
            port_open = True

        except WindowsError:
            print("Failed to connect MICRO CONTROLLER on port ", arduino_port)
            number += 1
            print(arduino_port)
            port_open = False

    if not port_open:
        print("\nMICRO CONTROLLER NOT CONNECTED !!!")
        sys.exit()

    if port_open:
        print("PREPARING THE BROWSER....")
        browser = webdriver.Chrome(
            executable_path="C:/Users/EBUBEDIKE/Documents/PROGRAMING/CORE-PYTHON/WEBDRIVERS/chromedriver",
            keep_alive=True)
        time.sleep(1)
        print("waiting for data")

        while True:
            rfid_data = connect.readline().strip()

            if len(rfid_data) > 0:
                decoded = rfid_data.decode("utf-8")
                print(decoded)

                try:
                    idurl = ip_address + "/students/get-id/"
                    response = requests.post(idurl, data={"rfid_code": decoded})
                    student_id = response.json()['student_id']
                except requests.ConnectionError or requests.Timeout:
                    print("\nWEB SERVER NOT RUNNING!!!")
                    browser.quit()
                    break

                if not student_id == "00000":

                    url = ip_address + "/exams/exam-profile/" + str(student_id) + "/" + current_exam

                    try:
                        browser.get(url)
                    except Exception as e:
                        print(e)
                        print("INTERNET_DISCONNECTED "
                              " 404 URL Not Found")
                        browser.quit()
                        sys.exit()
                else:
                    browser.get(ip_address + '/students/error/')

if __name__ == '__main__':
    main("MTH121")


import ast
import os

# Third party imports
from setuptools import find_packages, setup

HERE = os.path.abspath(os.path.dirname(__file__))

def get_version(module='dbsession'):
    """Get version from text file and avoids importing the module."""
    with open(os.path.join(HERE, module, '__init__.py'), 'r') as f:
        data = f.read()
    lines = data.split('\n')
    for line in lines:
        if line.startswith('VERSION_INFO'):
            version_tuple = ast.literal_eval(line.split('=')[-1].strip())
            version = '.'.join(map(str, version_tuple))
            break
    return version

def get_description():
    """Get long description."""
    with open(os.path.join(HERE, 'README.md'), 'r') as f:
        data = f.read()
    return data

REQUIREMENTS = [
    'psycopg2-binary'
]

setup(
  name='dbsession',
  version=get_version(),
  license='MIT',
  description='The python postgreSQL ORM',
  long_description=get_description(),
  long_description_content_type='text/markdown',
  author='imwiwiim90',
  author_email='imwiwiim90@gmail.com',
  url='https://github.com/treble-ai/dbsession',
  keywords=['python', 'postgreSQL', 'ORM', 'psycopg2'],
  packages=find_packages(exclude=['contrib', 'docs', 'tests*']),
  install_requires=REQUIREMENTS,
  include_package_data=True,
  classifiers=[
    'Development Status :: 4 - Beta',
    'Intended Audience :: Developers',
    'Topic :: Software Development :: Build Tools',
    'License :: OSI Approved :: MIT License',
    'Programming Language :: Python :: 3.5',
    'Programming Language :: Python :: 3.6',
    'Programming Language :: Python :: 3.7',
    'Programming Language :: Python :: 3.8'
  ],
)


#!/usr/bin/python3
import argparse
import os
from hashlib import sha1 as niceHasher
from collections import defaultdict
import re

def getAllFiles(dirpath):
    pattern = re.compile(r"~|\.")
    for dirp, _, files in os.walk(dirpath):
        for f in files:
            if not pattern.match(f) and not os.path.islink(f):
                yield os.path.join(dirp, f)

def getHashOfFile(filepath):
    hasher = niceHasher()
    with open(filepath, mode='rb') as f:
        dose = 0
        while dose != b'':
            dose = f.read(1024)
            hasher.update(dose)
    return hasher.hexdigest()

def getDictOfFiles(listOfFiles, fullpath, dirpath):
    res = defaultdict(list)
    for f in listOfFiles:
        hashf = getHashOfFile(f)
        res[hashf].append(f if fullpath else os.path.relpath(f, start=dirpath))
    return res

def printSimilarities(dirpath, fullpath):
    dic = getDictOfFiles(getAllFiles(dirpath), fullpath, dirpath)
    res = (l for l in dic.values() if len(l) > 1)
    for l in res:
        print(":".join(l))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="finds in directory all equal files")
    parser.add_argument("-f", "--fullpath", action="store_true") #else shortpath in given directory
    parser.add_argument("path", type=str)
    args = parser.parse_args()
    pathdir = os.path.abspath(args.path)
    printSimilarities(pathdir, args.fullpath)


# 2309번 일곱 난쟁이

# 난쟁이들의 키를 받아서 리스트로 만든다!
list_ = [int(input()) for _ in range(9)]
# 리스트에 들어있는 키를 전부 합한다!
total = sum(list_)

for i in range(9):
    # j는 i 다음 숫자!
    for j in range(i+1,9):

        # 리스트에 들어있는 전체 값의 합에서 요소 두개를 뺐을 때 100이 될 경우
        if total - (list_[i] + list_[j]) == 100:

            # 해당 요소를 n1, n2라고 하고
            n1, n2 = list_[i], list_[j]

            # 리스트에서 해당 요소를 제거한다.
            list_.remove(n1)
            list_.remove(n2)

            # 일곱 난쟁이의 키를 오름차순으로 출력해야한다.
            list_.sort()

            for i in list_:
               print(i)
            exit()

#=====================================
# 조합(combination)을 이용해서 푸는 방법

from itertools import combinations

heights = [int(input()) for _ in range(9)]
for combi in combinations(heights, 7):
    if sum(combi) == 100:
        for height in sorted(combi):
            print(height)
        break


from __future__ import print_function,division
from visual import *
from visual.graph import *
from random import random

winsize =500 #창 사이즈 지정

# 일반 상수 지정
L = 10 # 용기 한변 길이(단위:m)
B_L = 0.5 # 윗벽 두깨(단위:m)
Natom = 30 #원자 갯수
Ratom = 0.1  #원자 반지름(단위:m)
Matom = 4E-3/6E23 # 원자 질량 4g/아보가드로수 = 0.004/6.02*10^23
g = 9.8 # 중력상수
k = 1.4E-23 # 볼츠만 상수
dt = 1.E-4 #시간 간격
beta =1. # 마찰계수
T =300 #온도(300K)

# 그래프 계산용 변수 지정
time=0 # 초기 시간
theory_sum = 0 #평균 압력측정용
theory_avg = [] #평균 압력-그래프-
M_B_Min = 1E-20 #최소 무게
M_B_Max = 5E-20 #최고 무게
dM = 5E-21 #무게 간격
graph_color =[] #그래프 색깔

## 그래프 설정 란 ##
Time_to_P = gdisplay(title="시간에 따른 압력",x = 0,y = winsize,ymax = M_B_Max/500,\
                  width = winsize, height = 0.6*winsize, xtitle ="Time",ytitle="P") #시간에 따른 압력 그래프 화면 생성
Time_P = gdots(color=color.red)#시간에 따른 압력 그래프 점 찍는거
T_to_P = gdisplay(title="압력과 부피간의 관계",x = winsize,y = 0,ymax = L**3,\
                  width = winsize, height = winsize, xtitle ="P",ytitle="V") #온도와 압력관게  그래프화면 생성
P_T_Theory = gcurve(color = color.cyan) #이론 그래프 색깔 지정
P_T_Experimental = gdots(color=color.red) #측정 그래프 색깔 지정
for graph_M in arange(dM,M_B_Max+1E-22+dM,dM): # 이론 예측 그래프 생성
    P_T_Theory.plot(pos=(graph_M,Natom*k*L**3/(graph_M*9.8)))

time_to_P = gdisplay(title="시간에 따른 부피",x=winsize, y=winsize,\
                     ymax = L**3,width=winsize, height=0.6*winsize, xtitle='Time', ytitle='V') #시간에 따른 부피 그래프 화면 생성
theory = gdots(color=color.red)
for i in range(int((M_B_Max-M_B_Min+dM)/dM)):
    graph_color.append((0.5,i/8.,i/8.+0.3))
    theory_avg.append(gcurve(color =graph_color[i]))

for M in arange(M_B_Min,M_B_Max+1E-22,dM):  #M_B_Min 에서 B_M_Max 까지 dM 간격으로 시뮬레이션..
    ## 시뮬레이션 창생성 ##
    scene = display(title="압력에 따른 부피", width=winsize, height=winsize, x=0, y=0,center=(L/2.,L/2.,L/2.))

    ## 외벽 선 생성 ##
    xaxis = curve(pos=[(0,0,0), (L,0,0)], color=color.blue)
    yaxis = curve(pos=[(0,0,0), (0,L,0)], color=color.blue)
    zaxis = curve(pos=[(0,0,0), (0,0,L)], color=color.blue)
    xaxis2 = curve(pos=[(L,L,L), (0,L,L), (0,0,L), (L,0,L)], color=color.blue)
    yaxis2 = curve(pos=[(L,L,L), (L,0,L), (L,0,0), (L,L,0)], color=color.blue)
    zaxis2 = curve(pos=[(L,L,L), (L,L,0), (0,L,0), (0,L,L)], color=color.blue)

    ## 천장 생성 ##
    T_B = box(pos=vector(L/2,L,L/2),size=vector(L,B_L,L))
    B_Pos = vector(L/2,L,L/2)
    B_v = vector(0,0,0)

    atom = [] #원자
    atom_Pos = [] #원자 위치
    atom_p = [] # 원자 운동량

    ## 원자의 위치와 속도 지정##
    for i in range(Natom):
        ## 원자의 위치 랜덤화 ##
        x = Ratom+random()*(L-2*Ratom)
        y = Ratom+random()*(L-2*Ratom)
        z = Ratom+random()*(L-2*Ratom)
        atom_Pos.append((x,y,z))
        atom.append(sphere(pos=(x,y,z), radius=Ratom, color=color.red))

        ## 속도값 지정과 방향 랜덤화 ##
        phi = random()*2*pi
        psi = random()*2*pi
        pavg =sqrt(3.*Matom*k*T) #원자의 평균 속도 지정
        atom_p.append((pavg*sin(psi)*cos(phi),pavg*sin(psi)*sin(phi),pavg*cos(psi)))

    Pos = array(atom_Pos)
    p = array(atom_p)
    theory_length = 500 # 평균할 범위 지정
    theory_P_avg = empty([theory_length],float)# 평균을위한 값 생성
    theory_P_avg[:]=1E-23# 평균 초기값(온도에따라 설정해줘야 함.<-첫 평균압력값임 그래프 보았을때 이상하면 이값 수정하면 됨.)
    while time < 3.0:
        time+= dt
        rate (1000)
        ## dt의 시간이 지난후 위치 계산 ##
        Pos = Pos + (p/Matom)*dt
        B_v = B_v - vector(0,(9.8)*dt,0)
        ## 윗 면들 충돌 계산 ##
        outside = greater_equal(Pos,[L-Ratom,B_Pos[1]-Ratom-B_L,L-Ratom])
        p1 = p*outside
        p = p-p1-abs(p1)
        B_V = B_v[1] #충돌전 벽의 속도
        theory_P = 0
        for c in range(Natom):
            if outside[c][1]:
                b_v = -p[c][1]/Matom # 충돌전 공의 속도
                theory_P += b_v*Matom
                b_v0= (b_v*(Matom-M)+2*M*B_V)/(Matom+M)#충돌후 공의 속도
                B_V0= (B_V*(M-Matom)+2*Matom*b_v)/(Matom+M)#충돌후 벽의 속도
                B_V = B_V0
                theory_P += b_v *Matom
                p[c][1] = b_v0*Matom
        B_v = vector(0,B_V,0)
        B_Pos = B_Pos + B_v*dt
        ## 시간에 따른 압력 값 출력(윗면의 압력만 출력하는것임)##
        theory_P_avg=append(theory_P_avg,theory_P)
        theory_P_avg=delete(theory_P_avg,0)
        Time_P.plot(pos=(time,sum(theory_P_avg)/theory_length),color=graph_color[int((M-M_B_Min)/dM)])
        ## 밑바닥 면들 충돌 계산 ##
        outside = less_equal(Pos,Ratom)
        p1 = p*outside
        p = p-p1+abs(p1)
        ## 시간에 따른 부피 값 출력 ##
        theory_volume= L*L*(B_Pos[1]-B_L)
        theory_avg[int((M-M_B_Min)/dM)].plot(pos=(time,theory_volume))
        ## 원자 위치 재설정 ##
        for i in range(Natom):
            atom[i].pos = Pos[i]
        T_B.pos = B_Pos
    P_T_Experimental.plot(pos=(M,theory_volume),color=graph_color[int((M-M_B_Min)/dM)]) #측정값 그래프화

    ## 값 초기화 ##
    time = 0
    theory_sum = 0
    scene.delete()

while 1:
    rate(1)


from keras import models, layers, losses, optimizers, activations, Input, utils
import numpy as np

# 文本片段词典大小
text_vocabulary_size = 10000
# 问题词典大小
question_vocabulary_size = 10000

maxlen = 500

num_samples = 10000

# 收入分类数
num_income_group = 10

# 处理文本输入
text_input = Input(shape=(None, ), dtype='int32', name='texts')
embedded_text = layers.Embedding(text_vocabulary_size, 64)(text_input)
encoded_text = layers.LSTM(32)(embedded_text)

# 处理问题输入
question_input = Input(shape=(None, ), dtype='int32', name='questions')
embedded_question = layers.Embedding(question_vocabulary_size,
                                     64)(question_input)
encoded_question = layers.LSTM(64)(embedded_question)

# 连接编码后的问题和文本
concatenated = layers.concatenate([encoded_text, encoded_question], axis=-1)

# 回归问题
age_prediction = layers.Dense(1, name='age')(concatenated)

# 多分类问题
income_prediction = layers.Dense(num_income_group,
                                 activation=activations.softmax,
                                 name='income')(concatenated)

# 二分类问题
gender_prediction = layers.Dense(1,
                                 activation=activations.sigmoid,
                                 name='gender')(concatenated)

model = models.Model([text_input, question_input],
                     [age_prediction, income_prediction, gender_prediction])

model.summary()

model.compile(
    optimizer=optimizers.Adam(),  # 这个注释只是为了自动格式化
    loss={
        'age': losses.mse,
        'income': losses.categorical_crossentropy,
        'gender': losses.binary_crossentropy
    },
    loss_weights={
        'age': 0.25,
        'income': 1.,
        'gender': 10.
    })

# 准备模拟数据
# x_train(s)
texts = np.random.randint(1, text_vocabulary_size, size=(num_samples, maxlen))
questions = np.random.randint(1,
                              question_vocabulary_size,
                              size=(num_samples, maxlen))

# y_train(s)
# 1. 预测age是回归问题， lables.shape = (num_simples,)
age_targets = np.random.randint(16, 40, size=num_samples)

# 2. 预测income是多分类问题，有2种标签向量化方式，这边使用one-hot编码,lables.shape = (num_samples, num_income_group)
income_targets = np.random.randint(num_income_group, size=num_samples)
income_targets = utils.to_categorical(income_targets, num_income_group)

# 3. 预测gender是两分类问题, labels.shape = (num_samples, )
gender_targets = np.random.randint(2, size=num_samples)

model.fit(
    {
        'texts': texts,  # 这个注释只是为了自动格式化
        'questions': questions
    },
    {
        'age': age_targets,
        'income': income_targets,
        'gender': gender_targets
    },
    epochs=10,
    batch_size=64)


import requests
from django.contrib.auth import login
from django.core.mail import EmailMessage
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from accounts.models import User

def test1(request):
    email = EmailMessage('test','test', to=['lijahong111@gmail.com'])
    result = email.send()
    return HttpResponse()

def kakaologinpage(request):
    return render(request, 'login.html')

def getcode(request):
    code = request.GET.get('code')
    data = {'grant_type': 'authorization_code',
            'client_id':'발급받은 앱 키', #발급받은 앱 키
            'redirect_uri': 'redirect url', #redirect url
            'code':code #받은 인가 코드
            }
    headers = {'Contents-type':'application/x-www-form-urlencoded;charset=utf-8'}
    res = requests.post('https://kauth.kakao.com/oauth/token', data=data, headers=headers) #import request해야한다, request package 설치 필요, res는 응답 받은 객체 이다
    token_json = res.json() #json 파일로 받아온다
    access_token = token_json['access_token'] #access_token 받아오기

    #token
    headers = {'Authorization': 'Bearer '+access_token,
               'Content-type': 'application/x-www-form-urlencoded;charset=utf-8'}

    res = requests.get('https://kapi.kakao.com//v2/user/me', headers=headers)
    profile_res = res.json()

    nickname = profile_res['kakao_account']['profile']['nickname']
    print(nickname)
    kakaoid = profile_res['id']

    user = User.objects.filter(email=kakaoid)

    if user.first() is not None:
        login(request, user.first(), backend='django.contrib.auth.backends.ModelBackend')
        return render(request, 'profile.html')
    else :
        user = User()
        user.email = kakaoid #email란에 kakaoid를 넣어주겠다. email양식이 아니어도 가능하다
        user.username = nickname
        user.save()
        print('save it--------------------------')
        return render(request, 'login.html')

def profileshow(request):
    return render(request,'profile.html')


from django.core.mail import send_mail
from celery import shared_task

@shared_task()
def send_order_email_task(email, order):
    send_mail(
        "Your Order",
        f"Your order {order}. Thank you!",
        "support@example.com",
        [email],
        fail_silently=False,
    )


import numpy as np

# encriptedText = "KFH YYG IGM CEJ SST EBO EUG RWJ TSD VYK ZOZ LIZ KFH XKU UIC WXF WJG AXQ PBQ AGV GXD VDG UEV GMI GYK QQP IPS CLL FYP MUL KFH XPM HGM EVD KAV YQC EGU EAL YYY ZSZ MPX ZOC TXT RIM DID VDG SXO ZFF TSM EDV MEI MDV MPK OUJ KOD UBO AXB OOR SLP ZCW IMD VYG JWM IFQ"
# encriptedText = "OHT XAE CUO HEI PGX TIQ HOF YZS TLV CTM JOF AZQ DQD RBF KSY AFA LCX BKK IBA YVC WPP WVP ZHT XWO KSH MZQ CPX TIG TML DTX AEL EBJ VGZ MFY ERX IXA CUQ FMQ ZQC PXY TKW LKK BFT UUM EQO HLT MSF AVI XLR VTB HHT KNN XAH UOL VGG IGH DHP WTK KSN NHV PWQ HPW XLA YJQ PRT LRR YCO HRR OHK SVC CUO ZMQ ZCV CQF ZDB F"
# encriptedText = "OTG WRV RHU GXO XUQ UEK VYO TSE NYU NSI YSH MHB BUR ZTR CCD DAK MHC ALI OJZ UOT JYC KFN KIO THO GWK Z"
encriptedText = "YMAWABGYAWKYYUWJSNYMCZ"

#for a=1

encriptedText = encriptedText.replace(" ", "")
# commonWord = "CHEESY" #This must be 5 letters

unitDict = {
    "1" : "1",
    "3" : "9",
    "5" : "21",
    "7" : "15",
    "9" : "3",
    "11": "19",
    "15": "7",
    "17": "23",
    "19": "11",
    "21": "5",
    "23":"17",
    "25":"25"
}

def convertToNums(encriptedWord, encriptedCommonWord):
    encriptedNums, commonNums = [], []
    for x in range(len(encriptedWord)):
        letter = ord(encriptedWord[x]) - 65
        encriptedNums.append(letter)
    for i in range(len(encriptedCommonWord)):
        letter = ord(encriptedCommonWord[i]) - 65
        commonNums.append(letter)

    return encriptedNums, commonNums

convertedText, convertedSearch = convertToNums(encriptedText, commonWord)

def breakDownText(wordCompare, encripted):
    finalDecoded = []
    for x in range(len(encripted)-4):
        evenList = [x,x+1,x+2,x+3,x+4]
        firstTwoEvens = []
        count = 0
        for i in range(len(evenList)):
            if count == 2:
                break
            if evenList[i] % 2 == 0:
                firstTwoEvens.append(evenList[i])
                count += 1

        if evenList[0] % 2 == 0:
            shrinkCompare = np.array(wordCompare[:4])
        else:
            shrinkCompare = np.array(wordCompare[1:])

        #decrypted 'guess' message
        shrinkCompare = [[shrinkCompare[0], shrinkCompare[2]], [shrinkCompare[1], shrinkCompare[3]]]

        chosenCipherText = [[encripted[firstTwoEvens[0]], encripted[firstTwoEvens[1]]], [encripted[firstTwoEvens[0]+1], encripted[firstTwoEvens[1]+1]]]

        determinant = np.linalg.det(chosenCipherText) % 26
        detInv = ","
        determinant = round(int(determinant), 5)
        if str(determinant) in unitDict:
            detInv = unitDict[str(determinant)]
        if "," in detInv:
            continue
        detInv = int(detInv)

        flippedMatrix = [[encripted[firstTwoEvens[1]+1], -encripted[firstTwoEvens[1]]], [-encripted[firstTwoEvens[0]+1], encripted[firstTwoEvens[0]]]]
        flippedMatrix = np.array(flippedMatrix)
        invMatrix = detInv*flippedMatrix

        for x in range(len(invMatrix)):
            for i in range(len(invMatrix[x])):
                invMatrix[x][i] = (invMatrix[x][i]%26)

        keyMatrix = np.matmul(shrinkCompare, invMatrix)
        for x in range(len(keyMatrix)):
            for i in range(len(keyMatrix[x])):
                keyMatrix[x][i] = (keyMatrix[x][i]%26)

        plainTextSearch = []
        for x in range(0,len(encripted),2):
            encode = np.matmul(keyMatrix, [encripted[x], encripted[x+1]])
            encode[0] = (encode[0] % 26)
            encode[1] = (encode[1] % 26)
            # if encode[0] == 0:
            #     encode[0] = 26
            # if encode[1] == 0:
            #     encode[1] == 26
            convert0 = chr(int(encode[0]) + 65)
            convert1 = chr(int(encode[1]) + 65)
            plainTextSearch.append([convert0, convert1])
        plainTextSearch = np.array(plainTextSearch)
        plainTextSearch = np.reshape(plainTextSearch, (-1,))
        finalDecoded.append(plainTextSearch)
    return finalDecoded, keyMatrix

answers, key = breakDownText(convertedSearch, convertedText)
plainText = ' '.join(answers[0])
print(plainText)
print(key)


import logging
import json
import os
import re
import asyncio
from typing import List, Dict, Any

class Phantom(object):

    def __init__(self, logger=None, exec_path='phantomjs', process_timeout=120):
        self.process_timeout = process_timeout
        self.exec_path = exec_path
        self.logger = logger
        if not self.logger:
            self.logger = logging.getLogger(self.__class__.__name__)

    async def syscall(self, cmd: List[str]):
        """cmd is a list comprising the command and the arguments
        """
        try:
            proc = await asyncio.create_subprocess_exec(*cmd,
                                                        stdout=asyncio.subprocess.PIPE,
                                                        stderr=asyncio.subprocess.PIPE)
            # output, errors = await proc.communicate(timeout=self.process_timeout)
            # task = asyncio.Task(proc.communicate())
            output, errors = await asyncio.wait_for(proc.communicate(), self.process_timeout)
            # errors = await proc.stderr.read()
            self.logger.error(errors)
            # output = await proc.stdout.read()
            if output:
                res: str = output.decode('utf-8')
                if res.startswith('E: Phantomjs failed to open page'):
                    self.logger.error(res)
                    res = ''
                return res
        except:
            self.logger.exception("E: PhantomJS command failed")
        return ''

    async def download_page(self, conf, proxy='', proxy_type='', js_path='', ssl_verify=True,
                      load_images=False, cookies_file=''):
        confs = json.dumps(conf)

        cmd = [self.exec_path]

        if not load_images:
            cmd.append('--load-images=false')

        if not ssl_verify:
            cmd.append('--ignore-ssl-errors=true')

        if proxy_type:
            cmd.append("--proxy-type=%s" % (proxy_type,))
        if proxy:
            cmd.append("--proxy=%s" % (proxy,))
        if cookies_file:
            cmd.append("--cookies-file=%s" % (cookies_file,))

        if not js_path:
            cmd.extend([os.path.join(os.path.dirname(__file__), 'get_source_wait_for.js'), confs])
        else:
            cmd.extend([js_path, confs])

        self.logger.debug(cmd)

        output = await self.syscall(cmd)
        return output

    @staticmethod
    def get_bounded_data(output):
        output = re.sub(r'[\s\S]*###DATA_START###', '', output, flags=re.M)
        output = re.sub(r'###DATA_END###[\s\S]*', '', output, flags=re.M)
        return output.strip()


###################################################################################################
# Functions from maf to eset compatible files                                                     #
# load mafs in df - write eset files - merge TCGA pheno together with case_ids                    #
#                                                                                #
# 09/2019                                                                                #
###################################################################################################

import pandas as pd
import os

# Functions to create eset compatible files
# © Sarah Meitz 11.2019

def load_maf(filename, colnames):
    """
    load one maf with specified columns into a dataframe

    :param filename: filename of maf
    :param colnames: specifiy list of colnames
    :return: dataframe containing one maf

    """
    df = pd.read_csv(filename, comment="#", sep="\t", low_memory=False,
        skip_blank_lines=True, header=0, compression = "gzip", usecols=colnames)
    return df

def combine_mafs(files, colnames):
    """
    combine multiple mafs into one dataframe, concatinated by headers

    :param files: file names of all mafs in one folder
    :param colnames: list of colnames, default colnames list
    :return: dataframe with all mafs
    """

    mafs = []
    for f in files:
        df = load_maf(f, colnames)
        mafs.append(df)
        print("read:", f, "\n", "maf shape: ", df.shape)

    df = pd.concat(mafs, axis=0, ignore_index=True)
    print("combined maf dataframe shape: ",df.shape)
    return df

def add_counts(df):
    """
    add counts to dataframe as combination of "t_ref_count":"t_alt_count"
    :param df: combined maf dataframe
    :return: dataframe incl counts
    """
    counts = df["t_ref_count"].map(str) + ":" + df["t_alt_count"].map(str)
    df.insert(loc=0, column="counts", value=counts)
    return df

def add_featurename(df, drop=True):
    """
    add featurename at first column to dataframe as unique identifier and set as index
    :param df: combined maf dataframe
    :return: df incl featurename
    """
    featurename = df["Chromosome"].map(str) + "." + df["Start_Position"].map(str) + "." + df["End_Position"].map(str)\
                  + "." + df["Strand"].map(str) + "." + df["Reference_Allele"].map(str) + "."\
                  + df["Tumor_Seq_Allele1"].map(str) + "." + df["Tumor_Seq_Allele2"].map(str)
    df.insert(loc=0, column="featurename", value=featurename)
    df.set_index("featurename", drop=drop, inplace=True)
    return df

def prepare_maf_df(files, colnames):
    """
    read all maf files within a folder add counts and add featurename column
    :param files: list of mafs
    :return: dataframe of all mafs with additional counts and featurename column
    """
    df_mafs = combine_mafs(files, colnames)
    df_counts = add_counts(df_mafs)
    df = add_featurename(df_counts, drop=True)
    return df

def set_data_file(df, path, use_binary_matrix, filename="data.csv"):
    """
    write data.csv file containing unique featurename as index,
    case_id as header filled with counts (summed by case_id)
    :param df: dataframe containing at least counts, featurename and case_id
    :param path: path where file is stored
    :param use_binary_matrix: if set to True, will create a (0,1)-matrix
    :param filename: name of outputfile, default = data.csv
    :return: data dataframe
    """
    print("extracting assay data..")
    filepath = os.path.join(path + filename)
    df_small = df.drop(df.columns.difference(["counts","case_id"]), 1)
    df_small_unq = col2unq(df_small, groupby=["featurename", "case_id"]) # unique featurename/case_id
    df_sumcounts = df_small_unq.drop(columns="case_id").reset_index()
    df_sumcounts["counts_sum"] = df_sumcounts["counts"].apply(lambda x: counts_addition(x)) # add counts up
    df_pivot = df_sumcounts.pivot(index="featurename", columns="case_id", values="counts_sum")
    #df_pivot.set_index("featurename")
    if use_binary_matrix:
        df_pivot = df_pivot.notnull().astype("int")  # create (0,1)-matrix (nan = 0, else 1)
    else:
        df_pivot.fillna(value="0:0", inplace=True)  # fill nan with 0:0
    df_pivot.to_csv(filepath, sep="\t")
    print("written assay data to ", filepath)
    return df_pivot

def set_featuredata_file(df, df_data, path, filename ="featuredata.csv"):
    """
    write featuredata.csv file containing unique featurename as index and all previous selected columns
    :param df: dataframe with unique (df_uniq) entries containing featurename
    :param df_data: final dataframe of assayData
    :param path: folder path to save featuredata
    :param filename: name of outputfile, default = featuredata.csv
    :return: featuredata dataframe
    """
    print("extracting feature data..")
    filepath = os.path.join(path + filename)
    featuredata = df.copy()
    # drop all irrelevant columns
    featuredata.drop(columns=["counts", "case_id", "t_ref_count", "t_alt_count"], inplace=True)
    df_featuredata = col2unq(featuredata, groupby=["featurename"])

    #print("df_featuredata has shape: ", df_featuredata.shape, ", df_pivot has shape: ", df_data.shape)
    #df_featuredata.set_index("featurename", drop=False, inplace=True)

    # ensure df_featuredata has the same dimensions as df_data (=assayData)
    df_featuredata_joined = df_data.reset_index().join(df_featuredata, on="featurename", how="inner")
    df_featuredata_joined = df_featuredata_joined.set_index("featurename")
    df_featuredata_joined = df_featuredata_joined.drop(df_featuredata_joined.columns.difference(df_featuredata.columns), 1)
    print("shape df_featuredata: ", df_featuredata_joined.shape)
    df_featuredata.to_csv(filepath, sep="\t")
    df_featuredata_joined.to_csv(path+"featuredata.csv", sep="\t")

    print("written featuredata to ", filepath, path+"featuredata.csv")
    return df_featuredata_joined

def set_phenodata_file(df_data, path, filename="pheno.csv"):
    """
    write pheno.csv file case_id as column and headers in same order as in data file
    :param df_data: df output from get_data_file function
    :param filename: name of outputfile, default = pheno.csv
    :return: return pheno dataframe
    """
    print("extracting pheno data..")
    filepath = path+filename
    case = df_data.columns
    pheno = pd.DataFrame(index=case)
    pheno.to_csv(filepath, sep="\t")
    print("written pheno data to ", filepath)
    return pheno

def merge_pheno_data(pheno_data, TCGApheno, phenodata_path):
    """
    merge TCGApheno data to case_ids in pheno.csv file
    :param pheno_data: phenodata file containing only indices (case_ids)
    :param TCGApheno: list of all TCGA case_id and corresponding informations
    :param phenodata_path: path to final phenodata file for eset
    :return: phenodata case_id + added information from TCGA data
    """
    pheno = pd.read_csv(pheno_data, sep="\t")
    phenoTCGA = pd.read_csv(TCGApheno, sep="\t")
    # normal merge or join functions create duplicates
    # this workaround overcomes the problem
    pheno["g"] = pheno.groupby("case_id").cumcount()
    phenoTCGA["g"] = phenoTCGA.groupby("case_id").cumcount()
    phenodata = pheno.merge(phenoTCGA, how="inner").drop("g", 1)
    phenodata.set_index("case_id", inplace=True)
    phenodata.to_csv(phenodata_path, sep="\t")
    os.remove(pheno_data)
    return phenodata

def write_eset_files(df, path, use_binary_matrix=True):
    """
    get all files necessary for files2eset function (R function): data, featuredata, phenodata
    :param df: dataframe with unique featurename and all selected columns
    :return: three dataframes: df_data, df_featuredata, df_pheno
    """
    if not os.path.exists(path):
        os.makedirs(path)
        print("new directory for eset files: "+path)
    print("write data.csv")
    df_data = set_data_file(df, path, use_binary_matrix)
    print("write featuredata.csv")
    df_featuredata = set_featuredata_file(df, df_data, path)
    print("write phenodata.csv")
    df_pheno = set_phenodata_file(df_data, path)
    return df_data, df_featuredata, df_pheno

def col2unq(df, groupby):
    """
    makes columns unique in respect to selected groupby column/s ("featurename")
    :param df: dataframe which columns should be unique
    :param groupby: columns which should become unique in df
    :return: unique dataframe
    """
    grouped = df.drop_duplicates().groupby(groupby)

    def combine(entry):
        try:
            return ";".join(set(entry)) # join
        except: # Exception raised if x is not of type string
            return ";".join(str(x) for x in set(entry))
    dict_for_df = dict()
    for col in df.columns:
        dict_for_df[col] = grouped[col].apply(lambda x: combine(x))
    new_df = pd.DataFrame(dict_for_df)
    return new_df

def counts_addition(counts):
    """
    sum counts up when more than one count exists per featurename/case_id
    :param counts: column containing the counts separated by ";"
    :return: summed up counts column
    """
    counts = counts.split(";")
    result_first = 0
    result_second = 0
    for count in counts: # count looks like e.g. 10:15
        count = count.split(":") # now ["10", "15"]
        first = int(count[0])
        second = int(count[1])
        result_first += first
        result_second += second
    count_sum = str(result_first) + ":" + str(result_second)
    return count_sum


'''
	Riley Knybel
	Program 1: Zeller's Congruence Weekday Calculator
	CSIS1101
	16 December 2019 (a Monday)
'''
import PySimpleGUI as sg
import math

#Selector lists - the Combo box and Spinner UI elements of PySimpleGUI take lists as acceptable values for the inputs.
#Creating these here makes the layout 2D List easier to read.

#holds the months for the month combo box
monthList = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

#creates a list containing numbers 1-31 for the days of the month spin-box
dayList = [i for i in range(1, 32)]

#creates a list containing numbers from 0-9999 for the year spin-box
yearList = [i for i in range(0, 9999)]

sg.change_look_and_feel('Dark Blue 3') #set a nice theme so the GUI isn't boring dull and gray

layout = [	[sg.Combo(monthList, default_value='January', font='Courier` 16'), sg.Spin(dayList, initial_value=1, size=(2,1), font='Courier` 16'), sg.Spin(yearList, initial_value=2019, size=(4,1), font='Courier` 16'), sg.Button('Calculate', font='Courier` 16')],
			[sg.Text('Hit "Calculate" to get the weekday :)', key='infoText', font='Courier` 16')]]

def ZCong(month, day, year): #function to calculate the weekday

	daysOfWeek = ['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
	yearOfCentury = year % 100
	zBasedCentury = year // 100 #the algorithm won't work with a float, so truncate the decimal points and convert to int

	returnString = month + ' ' + str(day) + ' ' + str(year) + ' is a '

	#convert month string to the appropriate integer for the algorithm
	if month is "March":
		if day > 31:
			return "Invalid date, please try again."
		month = 3
	elif month is "April":
		if day > 30:
			return "Invalid date, please try again."
		month = 4
	elif month is "May":
		if day > 31:
			return "Invalid date, please try again."
		month = 5
	elif month is "June":
		if day > 30:
			return "Invalid date, please try again."
		month = 6
	elif month is "July":
		if day > 31:
			return "Invalid date, please try again."
		month = 7
	elif month is "August":
		if day > 31:
			return "Invalid date, please try again."
		month = 8
	elif month is "September":
		if day > 30:
			return "Invalid date, please try again."
		month = 9
	elif month is "October":
		if day > 31:
			return "Invalid date, please try again."
		month = 10
	elif month is "November":
		if day > 30:
			return "Invalid date, please try again."
		month = 11
	elif month is "December":
		if day > 31:
			return "Invalid date, please try again."
		month = 12
	elif month is "January":
		if day > 31:
			return "Invalid date, please try again."
		month = 13
		yearOfCentury -= 1
	elif month is "February":
		if day > 29:
			return "Invalid date, please try again."
		month = 14
		yearOfCentury -= 1

	#Fixed my bug with info from this site https://www.geeksforgeeks.org/zellers-congruence-find-day-date/
	#The actual Zeller's Congruence algorithm - The star of the show!!

	weekday = (day + (13*(month+1)//5) + yearOfCentury + (yearOfCentury//4) + (zBasedCentury//4) - 2*zBasedCentury) % 7

	returnString += daysOfWeek[weekday] + '.'

	print("{} {}/{}/{}".format(weekday, month, day, year))

	return returnString

#Now that everything's defined, let's actually do things.

window = sg.Window('Day of Week Calculator', layout) #opens the window and creates the GUI elements in the order defined in layout 2D List

while True: #event loop - responds if the user clicks Calculate or the close button

	event, values = window.Read() #Get the values of all input elements in the GUI, values is a list of the inputs and event is the button that was clicked

	if event is None: #this occurs when the user clicks the close button in the title bar
		break

	if event is "Calculate": #this occurs when the user clicks "Calculate"
		window.Element('infoText').Update(ZCong(values[0], values[1], values[2]))

window.close() #close the window when the event loop is broken via clicking the close button