import streamlit as st
import streamlit.components.v1 as components
import numpy as np
from scipy import signal
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from PIL import Image
import pandas as pd
import base64
import librosa
import parselmouth
from parselmouth.praat import call
from pysndfx import AudioEffectsChain
import soundfile as sf
import tempfile

HOP = 1000
GRAPH_WIDTH = 1200
GRAPH_HEIGHT = 300

st.set_page_config(
    page_title="Voice Analysis",
    menu_items={
        "Get Help": "https://twitter.com/deiko_cs",
        "Report a bug": "https://twitter.com/deiko_cs",
        "About": """
         # 声を分析してEQを提案するWebアプリ
         このWebアプリはアップロードした音声を分析することができます。周波数スペクトルや声の特徴、声のタイプを表示します。また、EQを提案して加工した音声をダウンロードできます。
         """,
    },
)

@st.cache_data
def measurePitch(wav):
    sound = parselmouth.Sound(wav)
    harmonicity = call(sound, "To Harmonicity (cc)", 0.01, 75, 0.1, 1.0)
    hnr = call(harmonicity, "Get mean", 0, 0)
    return hnr

@st.cache_data
def calc_spec(wav, sr):
    fo, voiced_flag, voiced_prob = librosa.pyin(
        wav, fmin=75, fmax=500)

    ave_fo = np.average(fo[voiced_flag])

    spectrum = np.abs(np.fft.fft(wav, sr)[: int(sr / 2)])
    freqs = np.fft.fftfreq(sr, d=1.0 / sr)[: int(sr / 2)]
    s_power = np.abs(spectrum) ** 2

    peaks = signal.argrelmax(s_power, order=70)[0]

    even = sum(s_power[peaks[1::2]])
    odd = sum(s_power[peaks[2::2]])
    if odd + even == 0:
        odd_per = 0
        even_per = 0
        return ave_fo, s_power, freqs, peaks, odd, even, odd_per, even_per
    else:
        odd_per = odd * 100 / (odd + even)
        even_per = even * 100 / (odd + even)

    return ave_fo, s_power, freqs, peaks, odd, even, odd_per, even_per

@st.cache_data
def draw_wave(wav, tgt_ranges, sr, wav_seconds):
    fig = go.Figure()
    fig.add_trace(go.Scatter(
        y=wav[::HOP], mode="lines", line=dict(color="#2584c1")))
    fig.add_vrect(
        x0=int(tgt_ranges[0] * sr / HOP),
        x1=int(tgt_ranges[1] * sr / HOP),
        fillcolor="#d89648",
        opacity=0.5,
        layer="below",
        line_width=0,
    )
    fig.update_layout(
        title="Waveform",
        height=GRAPH_HEIGHT,
        xaxis=dict(
            tickmode="array",
            tickvals=[1, int(len(wav[::HOP]) / 2), len(wav[::HOP])],
            ticktext=[str(0), str(int(wav_seconds / 2)), str(wav_seconds)],
            title="Time(s)",
            gridcolor="#e5edef",
            color="#20323e",
        ),
        yaxis=dict(gridcolor="#e5edef", color="#20323e", showticklabels=False),
        margin=dict(t=50, b=50, l=10, r=10),
        plot_bgcolor="#b7c3d1",
        paper_bgcolor="#e5edef",
        font_color="#20323e",
        font_size=20,
    )
    img = fig.to_image(format="png", width=600, height=525)
    return img

@st.cache_data
def draw_spectrum(freqs, s_power, peaks):
    fig = go.Figure()
    fig.add_trace(
        go.Scatter(x=freqs, y=s_power, mode="lines",
                   line=dict(color="#2584c1"))
    )
    fig.add_trace(
        go.Scatter(
            x=freqs[peaks[0:7]],
            y=s_power[peaks[0:7]],
            mode="markers+text",
            textposition="top center",
            textfont=dict(size=15),
            text=freqs[peaks[0:7]],
            marker=dict(color="#e3619f", size=10),
        )
    )
    fig.update_layout(
        title="Frequency Spectrum",
        height=GRAPH_HEIGHT,
        xaxis=dict(
            title="Frequency(Hz)", range=[0, 2000], gridcolor="#e5edef", color="#20323e"
        ),
        yaxis=dict(gridcolor="#e5edef", color="#20323e", showticklabels=False),
        showlegend=False,
        margin=dict(t=50, b=50, l=10, r=10),
        plot_bgcolor="#b7c3d1",
        paper_bgcolor="#e5edef",
        font_color="#20323e",
        font_size=20,
    )
    img = fig.to_image(format="png", width=600, height=525)
    return img

@st.cache_data
def draw_result(filename,ave_fo, hnr, even_per, odd_per):
    fig = make_subplots(rows=3, cols=1)

    clip_ave_fo = np.clip(ave_fo, 70, 230)
    New_fo_Value = (((clip_ave_fo - 70) * 10) / 160) - 5
    if New_fo_Value > 0:
        fo_color = "#e3619f"
    else:
        fo_color = "#2584c1"

    fig.append_trace(
        go.Scatter(
            y=[""],
            x=[New_fo_Value],
            marker=dict(color=fo_color, size=40, symbol="diamond"),
        ),
        row=1,
        col=1,
    )
    fig.add_annotation(
        text="Low",
        xref="paper",
        yref="paper",
        x=0,
        y=0.86,
        showarrow=False,
        bgcolor="#e5edef",
        opacity=0.8,
        font_color="#20323e",
        font_size=30,
    )
    fig.add_annotation(
        text="High",
        xref="paper",
        yref="paper",
        x=1,
        y=0.86,
        showarrow=False,
        bgcolor="#e5edef",
        opacity=0.8,
        font_color="#20323e",
        font_size=30,
    )

    clip_hnr = np.clip(hnr, 9, 17)
    New_hnr_Value = (((clip_hnr - 9) * 10) / 8) - 5
    if New_hnr_Value > 0:
        hnr_color = "#e3619f"
    else:
        hnr_color = "#2584c1"

    fig.append_trace(
        go.Scatter(
            y=[""],
            x=[New_hnr_Value],
            marker=dict(color=hnr_color, size=40, symbol="diamond"),
        ),
        row=2,
        col=1,
    )
    fig.add_annotation(
        text="Husky",
        xref="paper",
        yref="paper",
        x=0,
        y=0.43,
        showarrow=False,
        bgcolor="#e5edef",
        opacity=0.8,
        font_size=30,
    )
    fig.add_annotation(
        text="Clear",
        xref="paper",
        yref="paper",
        x=1,
        y=0.43,
        showarrow=False,
        bgcolor="#e5edef",
        opacity=0.8,
        font_size=30,
    )

    fig.append_trace(
        go.Funnel(y=[""], x=[even_per], textinfo="text",
                  marker=dict(color="#2584c1")),
        row=3,
        col=1,
    )
    fig.append_trace(
        go.Funnel(y=[""], x=[odd_per], textinfo="text",
                  marker=dict(color="#e3619f")),
        row=3,
        col=1,
    )
    fig.add_annotation(
        text="Warm",
        xref="paper",
        yref="paper",
        x=0,
        y=0,
        showarrow=False,
        bgcolor="#e5edef",
        opacity=0.8,
        font_color="#20323e",
        font_size=30,
    )
    fig.add_annotation(
        text="Clarity",
        xref="paper",
        yref="paper",
        x=1,
        y=0,
        showarrow=False,
        bgcolor="#e5edef",
        opacity=0.8,
        font_color="#20323e",
        font_size=30,
    )
    fig.update_yaxes(gridcolor="#e5edef")
    fig.update_xaxes(dtick=1.25, showticklabels=False, gridcolor="#e5edef")
    fig.update_layout(
        xaxis=dict(range=[-5, 5]),
        xaxis2=dict(range=[-5, 5]),
        showlegend=False,
        margin=dict(t=0, b=0, l=10, r=10),
        plot_bgcolor="#b7c3d1",
        paper_bgcolor="#e5edef",
    )

    img = fig.to_image(format="png", width=600, height=350)

    if hnr > 13:
        if ave_fo > 150:
            type1 = 'High'
            if odd_per > even_per + 10:
                type2 = 'odd'
                img_path = "images/energy.png"
            else:
                type2 = 'even'
                img_path = "images/pure.png"
        else:
            type1 = 'Low'
            if odd_per > even_per + 10:
                type2 = 'odd'
                img_path = "images/leader.png"
            else:
                type2 = 'even'
                img_path = "images/cool.png"
    else:
        if ave_fo > 150:
            type1 = 'High'
            if odd_per > even_per + 10:
                type2 = 'odd'
                img_path = "images/friend.png"
            else:
                type2 = 'even'
                img_path = "images/soft.png"
        else:
            type1 = 'Low'
            if odd_per > even_per + 10:
                type2 = 'odd'
                img_path = "images/elegant.png"
            else:
                type2 = 'even'
                img_path = "images/gentle.png"

    img_type = Image.open(img_path)

    df = pd.DataFrame(
        {
            "ファイル名": [filename],
            "基本周波数（Hz）": [ave_fo],
            "HNR（dB）": [hnr],
            "奇数倍音（％）": [odd_per],
            "偶数倍音（％）": [even_per]
        }
    )

    csv = df.to_csv(index=False)
    b64 = base64.b64encode(csv.encode('utf-8-sig')).decode()
    href = f'Download'
    return img,img_type,df,href,type1,type2

@st.cache_data
def get_binary_file_downloader_html(bin_file, file_label='File', extension=""):
    with open(bin_file, 'rb') as f:
        data = f.read()
    bin_str = base64.b64encode(data).decode()
    href = f'Download'
    return href

@st.cache_data
def eq_recommended(filename, wav, sr, ave_fo, peaks, eq_gain,type1,type2):
    low = int(ave_fo-5)

    if type1 == 'High':
        eq2_peaks = peaks[(peaks >= 2000) & (peaks <= 3000)]
        eq_gain2 = eq_gain*-1
        q2 = 4.0
        if len(eq2_peaks) == 0:
            eq2 = 2500
        else:
            eq2 = int(np.median(eq2_peaks))
    else:
        eq2_peaks = peaks[(peaks >= 1500) & (peaks <= 3000)]
        eq_gain2 = eq_gain
        q2 = 0.46
        if len(eq2_peaks) == 0:
            eq2 = 2500
        else:
            eq2 = int(np.median(eq2_peaks))

    if type2 == 'odd':
        eq1_peaks = peaks[(peaks >= 100) & (peaks <= 300)]
        eq_gain1 = eq_gain
        q1 = 1.2
        if len(eq1_peaks) == 0:
            eq1 = 250
        else:
            eq1 = int(np.median(eq1_peaks))
    else:
        eq1_peaks = peaks[(peaks >= 400) & (peaks <= 500)]
        eq_gain1 = eq_gain*-1
        q1 = 4.0
        if len(eq1_peaks) == 0:
            eq1 = 450
        else:
            eq1 = int(np.median(eq1_peaks))

    fx = AudioEffectsChain().highpass(low, q=1/np.sqrt(2)).equalizer(eq1, q=q1,db=eq_gain1).equalizer(eq2, q=q2, db=eq_gain2)
    eq_wav = fx(wav)

    fp = tempfile.NamedTemporaryFile()
    sf.write(fp.name, eq_wav, sr, format="wav", subtype="PCM_24")
    href2 = get_binary_file_downloader_html(fp.name, filename, ".wav")

    eq_df = pd.DataFrame(
        data=np.array([['', 'Peaking', 'Peaking'], [low, eq1, eq2], ['12dB/oct', q1, q2], ['', eq_gain1, eq_gain2]]),
        index=['タイプ', '周波数（Hz）', 'Q', 'Gain（dB）'],
        columns=['High Pass Filter','Low Mid Frequency', 'High Mid Frequency']
    )

    return eq_wav, href2, eq_df

def _set_block_container_style(
    max_width: int = GRAPH_WIDTH + 100,
    max_width_100_percent: bool = False,
    padding_top: int = 5,
    padding_right: int = 1,
    padding_left: int = 1,
    padding_bottom: int = 10,
):
    if max_width_100_percent:
        max_width_str = f"max-width: 100%;"
    else:
        max_width_str = f"max-width: {max_width}px;"
    st.markdown(
        f"""

""",
        unsafe_allow_html=True,
    )

def main():
    st.title("Voice Analysis")
    st.write("create by Deiko")
    st.markdown("---")

    st.subheader("How to use")
    col1, col2 = st.columns(2)
    uploaded_file = col2.file_uploader("＊1秒以上の.wavのみ対応")

    col1.write("①「Browse files」から音声ファイルを読み込む")
    col1.write("② ピンクのスライドバーで分析範囲を指定する")
    col1.write("③ グラフや表に分析結果が表示される")
    st.markdown("---")

    if uploaded_file is not None:
        if not uploaded_file.name.endswith(".wav"):
            st.error("このファイルのフォーマットに対応していません！.wavファイルを読み込んでください！", icon="😵")
        else:
            wav, sr = librosa.load(uploaded_file, sr=None)
            wav_seconds = int(len(wav) / sr)
            col2.audio(wav, sample_rate=sr)
            tgt_ranges = col2.slider("分析範囲（秒）", 0, wav_seconds, (0, wav_seconds))
            wav_element = wav[tgt_ranges[0] * sr: tgt_ranges[1] * sr]

            col3, col4 = st.columns(2)
            ave_fo, s_power, freqs, peaks, odd, even, odd_per, even_per = calc_spec(wav_element, sr)
            wave_img = draw_wave(wav, tgt_ranges, sr, wav_seconds)
            col3.image(wave_img)
            spectrum_img = draw_spectrum(freqs, s_power, peaks)
            col4.image(spectrum_img)

            if tgt_ranges == (0, 0):
                st.error("分析範囲が0秒です！設定から分析範囲を指定し直してください！", icon="😵")
            elif odd_per + even_per == 0:
                st.error("倍音が検出できません！設定から分析範囲を指定し直すか、別のファイルを読み込んでください！", icon="😵")
            else:
                hnr = measurePitch(wav_element)

                st.header("Result")
                col5, col6 = st.columns(2)
                result_img,img_type,df,href,type1,type2 = draw_result(uploaded_file.name,ave_fo, hnr, even_per, odd_per)
                col5.image(result_img)
                col6.image(img_type)
                st.dataframe(df)
                st.markdown(
                    f'csvファイルでダウンロード▶ {href}',
                    unsafe_allow_html=True,
                )
                st.markdown(
                    f'基本周波数とHNRは平均で計算しています。',
                    unsafe_allow_html=True,
                )
                st.markdown("---")

                st.subheader("Recommended EQ")
                st.write("分析結果を元におすすめの音声EQを提案します！")
                eq_gain = st.slider("レコメンドEQのGain適用度", 1, 5, 1)
                eq_wav, href2,eq_df = eq_recommended(uploaded_file.name.removesuffix('.wav'), wav, sr, ave_fo, peaks, eq_gain,type1,type2)
                st.dataframe(eq_df)

                col7, col8 = st.columns(2)
                col7.write("[Before]")
                col7.audio(wav, sample_rate=sr)
                col8.write("[After]")
                col8.audio(eq_wav, sample_rate=sr)
                col8.markdown(
                    f'wavファイルでダウンロード▶ {href2}', unsafe_allow_html=True)
                components.html(
                    """<a href="http://twitter.com/intent/tweet" class="twitter-share-button"
                    data-text="#レコメンドEQ #VoiceAnalysis"
                    data-url="https://deiko0-voice-analysis-app-m0fgp5.streamlit.app"
                    Tweet

                    """)

if __name__ == "__main__":
    _set_block_container_style()
    main()


# encoding: utf-8
"""
@author: github/100101001
@contact: 17702113437@163.com
@time: 2020/3/21 下午2:15
@file: AcsSmsSendLog.py
@desc:
"""

from datetime import datetime
import datetime as dt
from sqlalchemy import func
from sqlalchemy.dialects.mysql import INTEGER

from application import db, app

class AcsSmsSendLog(db.Model):
    __tablename__ = 'acs_sms_send_log'
    __table_args__ = ({'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8mb4', 'comment': '阿里云服务短信发送调用日志'})

    id = db.Column(INTEGER(11, unsigned=True), primary_key=True, autoincrement=True)
    biz_uuid = db.Column(db.String(50), nullable=False, unique=True, comment='本地业务ID')
    trig_member_id = db.Column(INTEGER(11, unsigned=True), nullable=False, default=0, comment='触发发送短信的会员id')
    trig_openid = db.Column(db.String(32), nullable=False, default='', comment='触发发送短信的会员的第三方id')
    rcv_member_id = db.Column(INTEGER(11, unsigned=True), index=True, nullable=False, default=0, comment='收短信的会员id')
    rcv_openid = db.Column(db.String(32), nullable=False, index=True, default='', comment='收短信的会员的第三方id')
    phone_number = db.Column(db.String(20), nullable=False, index=True, comment='手机号')
    sign_name = db.Column(db.String(20), nullable=False, default="", comment='阿里云签名名称')
    template_id = db.Column(db.String(32), nullable=False, index=True, server_default=db.FetchedValue(), comment='阿里云模板id')
    params = db.Column(db.Text, nullable=False, comment='模板消息参数')
    acs_product_name = db.Column(db.String(20), nullable=False, comment='阿里云产品名')
    acs_resp_data = db.Column(db.Text, nullable=False, comment="响应数据")
    acs_request_id = db.Column(db.String(50), nullable=False, comment='调用请求ID')
    acs_biz_id = db.Column(db.String(50), nullable=False, comment='调用业务ID')
    acs_code = db.Column(db.String(32), nullable=False, comment='调用结果代码')
    updated_time = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='最后一次更新时间')
    created_time = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')

    @staticmethod
    def hasRecentLostNotify(openid='', interval=dt.timedelta(weeks=1)):
        return db.session.query(func.count(AcsSmsSendLog.id)).filter(AcsSmsSendLog.rcv_openid == openid,
                                                                     AcsSmsSendLog.template_id ==
                                                                     app.config['ACS_SMS']['TEMP_IDS']['NOTIFY'],
                                                                     AcsSmsSendLog.acs_code == "OK",
                                                                     AcsSmsSendLog.created_time >= datetime.now() - interval).scalar() > 0


import socket
import time
import random

#Definição das variáveis do socket
ClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '26.196.148.132'
port = 5001

#Tentativa de conexão no servidor
print('Waiting for connection')
try:
    ClientSocket.connect((host, port))
except socket.error as e:
    print(str(e))

#Recebe a mensagem do servidor
Response = ClientSocket.recv(1024)

#Define as variáveis de forma aleatória
TC = str(random.randint(36, 39))
FR = str(random.randint(9, 29))
OS = str(random.randint(90, 100))
PA = str(random.randint(71, 100))
FC = str(random.randint(51, 129))

#Opção para definir se o programa irá enviar dados automaticamente ou manualmente
print("Deseja inserir os valores manualmente?")
x = input("(1) Sim e (2) Não ")
x = int(x)

#Loop principal do sensor
while True:

    #Passsa os valores para a variavel que será convertida em string e enviada ao servidor
    Var = TC+','+FR+','+OS+','+PA+','+FC
    ClientSocket.send(str.encode(Var))
    Response = ClientSocket.recv(1024)
    print(Response.decode('utf-8'))

    time.sleep(10)

    #Condição de conferência para o input dos dados
    if (x == 1):
        TC = input('Insira o valor da Temperatura corporal: ')
        FR = input('Insira o valor da Frequência respiratória: ')
        OS = input('Insira o valor da Oxigenação do sangue: ')
        PA = input('Insira o valor da Pressão arterial: ')
        FC = input('Insira o valor da Frequência cardíaca: ')
    else:
        TC = str(random.randint(36, 39))
        FR = str(random.randint(9, 29))
        OS = str(random.randint(90, 100))
        PA = str(random.randint(71, 100))
        FC = str(random.randint(51, 129))

ClientSocket.close()


#!/usr/bin/env python

"""
GPS navigation node
This node should start with the robot_localization navsat_transform_node.
"""

from __future__ import print_function
from __future__ import division

import rospy
import actionlib
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
from geographic_msgs.msg import GeoPose
from std_srvs.srv import Empty, EmptyResponse
from sensor_msgs.msg import NavSatFix

from robot_localization.srv import SetDatum

from ros_gps_nav.srv import GoalGPS, GoalGPSResponse
import geonav_transform.geonav_conversions as gc
import utility

def cb_goal(request):
    """
    Callback for ~goal service, using actionlib.SimpleActionClient
    """
    # -- east zero yaw
    # x, y = gc.ll2xy(request.latitude, request.longitude, DATUM[0], DATUM[1])

    # --north zero yaw
    x, y = gc.ll2xy_nzy(request.latitude, request.longitude, DATUM[0], DATUM[1])

    goal = MoveBaseGoal()
    goal.target_pose.header.frame_id = 'map'
    goal.target_pose.header.stamp = rospy.Time.now()
    goal.target_pose.pose.position.x = x
    goal.target_pose.pose.position.y = y
    goal.target_pose.pose.orientation.w = 1
    rospy.loginfo("GPS target = {} {}".format(request.latitude, request.longitude))
    rospy.loginfo("MAP target = {} {}".format(x, y))
    state = ACTION_MOVE_BASE.send_goal_and_wait(goal=goal)

    response = GoalGPSResponse()
    response.state = state

    return response

def cb_set_datum(request):
    """
    service set_datum callback.
    This method will collect currnt location's gps signal to set the DATUM.
    And reset the ekf_node initial pose. This means the datum will be the origin of map.
    """
    global DATUM

    SERVICE_INIT_STATE.call()

    lati_avg, long_avg = utility.get_avg_gps(topic=NAME_TOPIC_GPS)
    DATUM = (lati_avg, long_avg, 0.0)

    # -- Use robot_localization navsat_transform_node service to set datum.
    # -- Note: Changing existing parameter ~datum doesn't work

    geo_pose = GeoPose()
    geo_pose.position.latitude = DATUM[0]
    geo_pose.position.longitude = DATUM[1]
    geo_pose.position.altitude = 0.0
    geo_pose.orientation.x = 0.0
    geo_pose.orientation.y = 0.0
    geo_pose.orientation.z = 0.0
    geo_pose.orientation.w = 1.0

    SERVICE_NAVSAT_DATUM(geo_pose)  # navsat_transform_node datum
    PUB.publish(geo_pose)

    rospy.loginfo("gps_nav: DATUM = {}, {}".format(DATUM[0], DATUM[1]))

    return EmptyResponse()

if __name__ == "__main__":

    rospy.init_node(name='gps_nav', anonymous=False)

    # -- Get parameters
    """
    Based on http://docs.ros.org/melodic/api/robot_localization/html/navsat_transform_node.html
    If wait_for_datum is true, navsat_transform_node will wait for ~datum parameter or ~set_datum service.
    If it is false. it will use the first gps signal to be the datum.
    In my testing. The name of the service is just "~datum", not ~set_datum.
    """
    NAME_TOPIC_GPS = rospy.get_param(param_name="~top_gps")
    name_service_init_state = rospy.get_param(param_name="~srv_init_state")
    name_service_navsat_datum = rospy.get_param(param_name="~srv_datum")  # navsat service name for setup datum
    name_ns_move_base = rospy.get_param(param_name="~ns_move_base")

    # -- Get ServiceProxy, Action client
    SERVICE_INIT_STATE = rospy.ServiceProxy(name=name_service_init_state, service_class=Empty)
    SERVICE_NAVSAT_DATUM = rospy.ServiceProxy(name=name_service_navsat_datum, service_class=SetDatum)
    ACTION_MOVE_BASE = actionlib.SimpleActionClient(ns=name_ns_move_base, ActionSpec=MoveBaseAction)
    ACTION_MOVE_BASE.wait_for_server()

    # -- Node function
    PUB = rospy.Publisher(name="/datum", data_class=GeoPose, queue_size=1)

    # -- Set DATUM, make sure it is the same with navsat_transform_node datum
    # -- This DATUM means the gps values of the origin of map
    LATIS = list()
    LONGS = list()
    DATUM = list()
    cb_set_datum("")  # Important! this calling will stop the launch execute /fsm/start.

    # -- Node function
    service_goal = rospy.Service(name='~goal', service_class=GoalGPS, handler=cb_goal)
    service_datum = rospy.Service(name='~set_datum', service_class=Empty, handler=cb_set_datum)

    rospy.spin()


# -*- coding: utf-8 -*-
import os
import json
from website import settings
from framework.status import pop_status_messages

from website.settings import EXTERNAL_EMBER_APPS

ember_osf_web_dir = os.path.abspath(os.path.join(os.getcwd(), EXTERNAL_EMBER_APPS['ember_osf_web']['path']))

routes = [
    '/quickfiles/',
    '/<uid>/quickfiles/',
    '/institutions/',
]

def use_ember_app(**kwargs):
    from website.views import stream_emberapp
    resp = stream_emberapp(EXTERNAL_EMBER_APPS['ember_osf_web']['server'], ember_osf_web_dir)
    messages = pop_status_messages()
    if messages:
        try:
            status = [{'id': stat[5] if stat[5] else stat[0], 'class': stat[2], 'jumbo': stat[1], 'dismiss': stat[3], 'extra': stat[6]} for stat in messages]
            resp.set_cookie(settings.COOKIE_NAME + '_status', json.dumps(status))
        except IndexError:
            # Ignoring the error as it will only occur when statuses were created prior to merging the changes that add
            # extra and id, (patch to prevent breaking the app meanwhile)
            pass
    return resp


import face_recognition as face
import cv2

image_file = "/Users/aiyaz/Desktop/rajini.jpg"
img = cv2.imread(image_file)

image = face.load_image_file(image_file)

landmarks = face.face_landmarks(img)
count = len(landmarks)
print(count)

datas = []

for x in landmarks:
    for y in x:
        datas.append(y)

plot_data = []
for z in datas:
    # print(landmarks[0][z])
    plot_data.append(landmarks[0][z])

# print(plot_data)

print(len(plot_data))
data = []
for a in plot_data:
    for b in a:
        data.append(b)

for point in data:
    cv2.circle(img,point,1,(0,0,255),thickness=2)
# for x in landmarks[0]["chin"]:
    # print(x)
    # datas.append(x)

# print(datas)

cv2.imshow("Frame",img)
cv2.waitKey(0)
cv2.destroyAllWindows()


# length of each line -> 31
# number of lines -> 323

# Right 1, down 1. -> 63
# Right 3, down 1. -> 181
# Right 5, down 1. -> 55
# Right 7, down 1. -> 67
# Right 1, down 2. -> 31

locommands = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]
RIGHT = 0
DOWN = 1
def tree_checker(file_name: str) -> int:
    print(file_name)
    product = 1
    for command in locommands:
        print(command)
        move_right = command[RIGHT]
        move_down = command[DOWN]
        index = 0
        count = 0
        f = open(file_name, 'r')
        len_check = f.readline().rstrip()
        length = len(len_check)
        for line in f:
            if move_down > 1:
                for down in range(move_down-1):
                    line = f.readline()
            line = line.rstrip()
            index += move_right
            # print(index)
            if index >= length:
                modulo_index = index % length
            else:
                modulo_index = index
            if line[modulo_index] == "#":
                count += 1
        print('trees hit:', count)
        product *= count
        f.close()
    print('product:', product)
    return product

tree_checker('day3test.txt')
print('\n')
tree_checker('day3.txt')


import random

import cv2
import numpy as np
from PIL import Image
import torch
from torch.utils.data import DataLoader, Dataset

from . import config as C
from .dataaug import get_transforms
from .etl import proc_df
from .utils import seed_everything

# (blank for unmentioned, 0 for negative, -1 for uncertain, and 1 for positive)
class CheXDataset(Dataset):
    """Custom dataset for CheXpert dataset.

    Args:
        df (pandas.DataFrame): preprocessed dataframe that has at least a "Path" column and 14 coulmns containing target labels.
        use_albu (bool, optional): If true, use albumentations for image augmentations else torchvision. Defaults to True.
        tfms (albumentations.Compose,torchvision.Compose, optional): Series of image augmentations to apply. Defaults to None.
        seed (int, optional): random seed used for deterministic augmentations. Defaults to None.
    """

    def __init__(self, df, use_albu=True, tfms=None, color=True, seed=None):
        self.df = df
        self.paths = self.df['Path'].values
        self.labels = self.df[C.TARGET_LABELS].values.astype(float)#.drop(columns=['Path'])
        self.tfms = tfms

        self.use_albu = use_albu
        self.color = color
        self._seedcntr = seed
        self._readflag = cv2.IMREAD_COLOR if color else cv2.IMREAD_UNCHANGED
        if self.tfms is not None:
            self.tfm_list = self.tfms.transforms.transforms if self.use_albu else self.tfms.transforms

    def __len__(self, ):
        return len(self.df)

    def __getitem__(self, idx):
        if self._seedcntr is not None:
            random.seed(self._seedcntr)
            self._seedcntr += 1
        labels = self.labels[idx]

        imgpath = str(C.DATA_PATH / self.paths[idx])

        is_lateral = 'lateral' in imgpath
        if self.use_albu:
            img = cv2.imread(imgpath, self._readflag)
            # img = template_match(img, template)
            # img = cv2.cvtColor(cv2.imread(imgpath), cv2.COLOR_BGR2RGB)
            # img = np.expand_dims(cv2.imread(imgpath,cv2.IMREAD_GRAYSCALE),2)
            aug = self.tfms(image=img, is_lateral=is_lateral)
            img = aug['image'] if self.color else torch.from_numpy(aug['image'][:,:,None].transpose(2,0,1))
            #img =
        else:
            img = Image.open(imgpath)
            img = self.tfms(img)

        return img, labels

def get_dloaders(df_train, df_valid, batch_size=32, sampsz=None, tfmlib='albu', color=True, seed=None, print_tfms=True,
                 proc_kwargs=None):
    """Creates DataLoader objects from training and validation DataFrames.

    Args:
        df_train (DataFrame): Training DataFrame containing Path and Label columns
        df_valid (DataFrame): Validation DataFrame containing Path and Label columns
        batch_size (int, optional): Training/Validation batch size passed to DataLoaders. Defaults to 32.
        sampsz (int, optional): If provided, uses a sample of `df_train` else uses entire dataset. Defaults to None.
        tfmlib (str, optional): Image augmentation library to use. Options: ('albu','torch'). Defaults to 'albu'.
        seed ([type], optional): random seed for sampling, shuffling and augmentations. Defaults to None.
        print_tfms (bool, optional): If True, prints list of training image augmentations. Defaults to True.
        proc_kwargs (dict, optional): Keyword arguments passed to `proc_df` for preprocessing `df_train`. Defaults to None.

    Returns:
        tuple(DataLoader,DataLoader): training and validation DataLoaders
    """
    if seed is not None:
        seed_everything(seed)

    if proc_kwargs is None:
        proc_kwargs = dict(method='uones', smooth=True, nafill_val=0)

    df_trn = proc_df(df_train, **proc_kwargs)
    df_val = proc_df(df_valid)
    if sampsz is not None:
        df_trn = df_trn.sample(sampsz)  # 17->65k, 13->8k

    ualbu = (tfmlib == 'albu')
    train_tfm = get_transforms('train', tfmlib, (244, 244), color=color)
    valid_tfm = get_transforms('test', tfmlib, (244, 244), color=color)

    train_dataset = CheXDataset(df=df_trn, use_albu=ualbu, tfms=train_tfm, color=color, seed=seed)  # smooth_bounds=(0.55,0.8501)
    valid_dataset = CheXDataset(df=df_val, use_albu=ualbu, tfms=valid_tfm, color=color)

    train_loader = DataLoader(train_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS)
    valid_loader = DataLoader(valid_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS,
                              shuffle=False)

    if print_tfms:
        print(f'{"=" * 20} Augmentations {"=" * 20}', '\n'.join([*map(str, train_loader.dataset.tfm_list)]), '-' * 55,
              sep='\n')

    return train_loader, valid_loader

def get_ctdloaders(df_ptrain, df_pvalid, batch_size=32, tfmlib='albu', seed=None, print_tfms=True):
    ualbu = (tfmlib == 'albu')
    train_tfm = get_transforms('train', tfmlib, (244, 244))
    valid_tfm = get_transforms('test', tfmlib, (244, 244))

    train_dataset = CheXDataset(df=df_ptrain, use_albu=ualbu, tfms=train_tfm, seed=seed)  # smooth_bounds=(0.55,0.8501)
    valid_dataset = CheXDataset(df=df_pvalid, use_albu=ualbu, tfms=valid_tfm)

    train_loader = DataLoader(train_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS)
    valid_loader = DataLoader(valid_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS,
                              shuffle=False)
    if print_tfms:
        print(f'{"=" * 20} Augmentations {"=" * 20}', '\n'.join([*map(str, train_loader.dataset.tfm_list)]), '-' * 55,
              sep='\n')

    return train_loader, valid_loader

def subset_dloader(df, grp_id=None, is_train=False, grp_name='ap_pa_ll', batch_size=32, seed=None, tfmlib='albu', color=True,
                   print_tfms=True):
    if seed is not None:
        seed_everything(seed)

    set_tfms = get_transforms('train' if is_train else 'test', tfmlib, (244, 244), color=color)

    df_subset = df[df[grp_name].eq(grp_id)] if grp_id is not None else df

    sub_dataset = CheXDataset(df=df_subset, use_albu=(tfmlib == 'albu'), tfms=set_tfms, color=color, seed=seed)
    sub_loader = DataLoader(sub_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS, shuffle=is_train)

    if print_tfms:
        print(f'{"=" * 20} Augmentations {"=" * 20}', '\n'.join([*map(str, sub_loader.dataset.tfm_list)]), '-' * 55,
              sep='\n')

    return sub_loader

def get_pdloaders(train_df, valid_df, grp_id, grp_name='ap_pa_ll', batch_size=32, seed=None, tfmlib='albu',
                  print_tfms=True, ):
    if seed is not None:
        seed_everything(seed)

    ualbu = (tfmlib == 'albu')

    train_tfm = get_transforms('train', tfmlib, (244, 244))
    valid_tfm = get_transforms('test', tfmlib, (244, 244))

    df_trn = train_df[train_df[grp_name].eq(grp_id)]
    df_val = valid_df[valid_df[grp_name].eq(grp_id)]
    train_dataset = CheXDataset(df=df_trn, use_albu=ualbu, tfms=train_tfm, seed=seed)
    valid_dataset = CheXDataset(df=df_val, use_albu=ualbu, tfms=valid_tfm, seed=seed)

    train_loader = DataLoader(train_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS)
    valid_loader = DataLoader(valid_dataset, batch_size, pin_memory=C.USE_CUDA, num_workers=C.NUM_WORKERS,
                              shuffle=False)

    if print_tfms:
        print(f'{"=" * 20} Augmentations {"=" * 20}', '\n'.join([*map(str, train_loader.dataset.tfm_list)]), '-' * 55,
              sep='\n')

    return train_loader, valid_loader


"""
WhoCommand class container module.
"""

from OB.commands.base import BaseCommand
from OB.constants import GroupTypes
from OB.models import Admin, Room
from OB.strings import StringId
from OB.utilities.database import async_get_owner, async_model_list, async_try_get

class WhoCommand(BaseCommand):
    """
    Lists all the occupants in a room. Can be called without arguments to list the users of the
    issuing user's current room.
    """

    def __init__(self, args, sender, room):
        """
        When there are no arguments, the default is the current room.
        """

        if not args:
            args = [room.name]

        super().__init__(args, sender, room)

    async def check_initial_errors(self):
        """
        There are no initial errors for /who.
        """

        return True

    async def check_arguments(self):
        """
        See BaseCommand.check_arguments().
        """

        for room_name in self.args:
            arg_room = await async_try_get(Room, group_type=GroupTypes.Room, name=room_name)

            if not arg_room:
                self.sender_receipt += [StringId.WhoInvalidTarget.format(room_name)]
            else:
                self.valid_targets += [arg_room]

        return bool(self.valid_targets)

    async def execute_implementation(self):
        """
        Construct a string of occupants in the room and send it back to the sender.
        The sender receipt includes per-argument error messages.
        """

        for room in self.valid_targets:
            occupants = await async_model_list(room.occupants)

            if not occupants:
                who_string = StringId.WhoEmpty.format(room)
            else:
                who_string = StringId.WhoPreface.format(room) + "\n"

                for user in occupants:
                    user_suffix = ""

                    if user == await async_get_owner(room):
                        user_suffix += StringId.OwnerSuffix
                    if await async_try_get(Admin, user=user, room=room):
                        user_suffix += StringId.AdminSuffix
                    if user == self.sender:
                        user_suffix += StringId.YouSuffix

                    who_string += f"    {user}{user_suffix}\n"

            self.sender_receipt += [who_string]


from loguru import logger
import numpy as np
from numpy import pi
import matplotlib.pyplot as plt

from manifold.topology import Point, Manifold, Map, Chart, Interval
from manifold.maps import (
    identity,
    subtract_pi,
    subtract_pi_inverse,
    smul_2,
    smul_2_inverse,
    smul_pi,
    smul_pi_inverse,
)
from manifold.base_function import BaseFunction
from manifold.manifolds.manifold import BaseManifold

class Manifold1D(BaseManifold):
    """
        Base class for 1D manifolds
    """

    d = 1
    vis_n_points = 300

    def __init__(self, embedding, n_sample_points):
        super().__init__(embedding, n_sample_points=n_sample_points)

    def project_with_charts(self, points=None):
        """
            For each point it projects the point to the image
            of a chart map for a chart containing the point
        """
        points = points or self.points

        for point in points:
            chart = self.get_chart_from_point(point)
            point.chart_coordinates = chart.x(point)
            point.chart = chart

    def get_base_functions(self, points=None):
        """
            For each point in the sampled manifold
            define a function I -> x(u) in the image of
            a chart containint the point
        """
        points = points or self.points
        for point in points:
            point.base_functions = [
                BaseFunction(point=point, f=self.base_functions_map,)
            ]

    def sample(self, n=None, fill=False, **kwargs):
        """
            Samples N points from the manifold's interval ensuring that they are not too close
        """
        # how many points
        n = n or self.n_sample_points
        if isinstance(n, list):
            n = n[0]
        logger.debug(f"Sampling manifold points with n={n+1}")

        # sample points
        points = [Point((k,), self.embedding) for k in self.M.sample(n)]

        # fill all data for points
        if fill:
            self._fill_points_data(points)
        return points

    def visualize_charts(self):
        """
            Takes point from the manifold domain and shows their projections in
            the charts domains
        """
        f, axes = plt.subplots(nrows=2, figsize=(16, 9), sharex=True)

        for n, point in enumerate(self.sample(n=50, fill=True)):
            axes[0].scatter(point.coordinates[0], 1, c=n, vmin=0, vmax=50)
            axes[1].scatter(
                point.chart_coordinates, point.chart.idx, c=n, vmin=0, vmax=50
            )
        axes[1].axhline(1, ls=":", color=[0.2, 0.2, 0.2], zorder=-1)
        axes[1].axhline(2, ls=":", color=[0.2, 0.2, 0.2], zorder=-1)

        axes[0].set(yticks=[], xlabel="M domain")
        axes[1].set(
            yticks=np.arange(len(self.manifold.charts)) + 1,
            yticklabels=[f"chart {c.idx}" for c in self.manifold.charts],
        )

class Circle(Manifold1D):
    name = "S^1"
    manifold = Manifold(
        M=Interval("M", 0, 2 * pi),
        charts=[
            Chart(1, Interval("U_1", 0, pi), Map("x_1", identity, identity),),
            Chart(
                2,
                Interval("U_2", pi, 2 * pi, left_open=True),
                Map("x_2", subtract_pi, subtract_pi_inverse),
            ),
        ],
    )
    _full = False
    base_functions_map = Map(
        "pi scalar multiplication", smul_pi, smul_pi_inverse
    )

    def __init__(self, embedding, n_sample_points=10):
        super().__init__(embedding, n_sample_points=n_sample_points)

class Line(Manifold1D):
    name = "R^1"
    manifold = Manifold(
        M=Interval("M", 0, 1),
        charts=[
            Chart(
                1, Interval("U_1", 0, 1), Map("x_1", smul_2, smul_2_inverse),
            ),
        ],
    )

    def __init__(self, embedding, n_sample_points=10):
        super().__init__(embedding, n_sample_points=n_sample_points)


# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from superset.dataframe import dedup, SupersetDataFrame
from superset.db_engine_specs import BaseEngineSpec
from .base_tests import SupersetTestCase

class SupersetDataFrameTestCase(SupersetTestCase):
    def test_dedup(self):
        self.assertEquals(
            dedup(['foo', 'bar']),
            ['foo', 'bar'],
        )
        self.assertEquals(
            dedup(['foo', 'bar', 'foo', 'bar', 'Foo']),
            ['foo', 'bar', 'foo__1', 'bar__1', 'Foo'],
        )
        self.assertEquals(
            dedup(['foo', 'bar', 'bar', 'bar', 'Bar']),
            ['foo', 'bar', 'bar__1', 'bar__2', 'Bar'],
        )
        self.assertEquals(
            dedup(['foo', 'bar', 'bar', 'bar', 'Bar'], case_sensitive=False),
            ['foo', 'bar', 'bar__1', 'bar__2', 'Bar__3'],
        )

    def test_get_columns_basic(self):
        data = [
            ('a1', 'b1', 'c1'),
            ('a2', 'b2', 'c2'),
        ]
        cursor_descr = (
            ('a', 'string'),
            ('b', 'string'),
            ('c', 'string'),
        )
        cdf = SupersetDataFrame(data, cursor_descr, BaseEngineSpec)
        self.assertEqual(
            cdf.columns,
            [
                {
                    'is_date': False,
                    'type': 'STRING',
                    'name': 'a',
                    'is_dim': True,
                }, {
                    'is_date': False,
                    'type': 'STRING',
                    'name': 'b',
                    'is_dim': True,
                }, {
                    'is_date': False,
                    'type': 'STRING',
                    'name': 'c',
                    'is_dim': True,
                },
            ],
        )

    def test_get_columns_with_int(self):
        data = [
            ('a1', 1),
            ('a2', 2),
        ]
        cursor_descr = (
            ('a', 'string'),
            ('b', 'int'),
        )
        cdf = SupersetDataFrame(data, cursor_descr, BaseEngineSpec)
        self.assertEqual(
            cdf.columns,
            [
                {
                    'is_date': False,
                    'type': 'STRING',
                    'name': 'a',
                    'is_dim': True,
                }, {
                    'is_date': False,
                    'type': 'INT',
                    'name': 'b',
                    'is_dim': False,
                    'agg': 'sum',
                },
            ],
        )

    def test_get_columns_type_inference(self):
        data = [
            (1.2, 1),
            (3.14, 2),
        ]
        cursor_descr = (
            ('a', None),
            ('b', None),
        )
        cdf = SupersetDataFrame(data, cursor_descr, BaseEngineSpec)
        self.assertEqual(
            cdf.columns,
            [
                {
                    'is_date': False,
                    'type': 'FLOAT',
                    'name': 'a',
                    'is_dim': False,
                    'agg': 'sum',
                }, {
                    'is_date': False,
                    'type': 'INT',
                    'name': 'b',
                    'is_dim': False,
                    'agg': 'sum',
                },
            ],
        )

    def test_dedup_with_data(self):
        data = [
            ('a', 1),
            ('a', 2),
        ]
        cursor_descr = (
            ('a', 'string'),
            ('a', 'string'),
        )
        cdf = SupersetDataFrame(data, cursor_descr, BaseEngineSpec)
        self.assertListEqual(cdf.column_names, ['a', 'a__1'])


import numpy as np
from math import sqrt

arr = [5, 4, 2, 3]

std_dev = sqrt(sum([(i - (sum(arr) / len(arr))) ** 2 for i in arr]) / len(arr))
print(std_dev)

avg = np.divide(np.sum(arr), np.array(arr).shape[0])
np_std_dev = np.sqrt(np.divide(np.sum([np.power(i - avg, 2) for i in np.nditer(arr)]), np.array(arr).shape[0]))
print(np_std_dev)


from django.conf import settings
from django.core import serializers
from django.http import HttpResponse
from django.shortcuts import render
from django.views.generic.base import View

from points.models import Points

import json
import zipfile
import os
import re

class PointsView(View):

    def get(self, request, *args, **kwargs):
        try:
            #http://localhost:8000/api/points/json/
            format = self.kwargs['format']
            q = request.GET.get("q")
            data =[]
            if q is not None:
                response = HttpResponse(open(os.path.join(settings.MAPS_POINTS, str(q) + '.zip'), 'rb'), content_type='application/zip')
                response["Access-Control-Allow-Origin"] = "*"
                return response
            else:
                data = Points.objects.all()
            return HttpResponse(serializers.serialize(format, data), content_type='application/' + format)
        except Exception as e:
            return HttpResponse( json.dumps({"error" : str(e) }), content_type='application/' + format )

    def post(self, request, *args, **kwargs):
        try:
            #http://localhost:8000/api/points/json/
            format = self.kwargs['format']
            entity = Points( name = request.POST['name'])
            entity.save()
            model = Points.objects.latest('id')
            process_points(request.FILES['file'],model,request.POST['split'])
            return HttpResponse(json.dumps({"message" : "OK"}), content_type='application/' + format)
        except Exception as e:
            print("error")
            print(e)
            return HttpResponse(json.dumps({"error" : str(e) }), content_type='application/' + format)

    def delete(self, request, *args, **kwargs):
        try:
            format = self.kwargs['format']
            id = request.GET.get("pk")
            if id is not None and id is not "":
                p = Points.objects.get(pk=id)
                p.delete()
                return HttpResponse(json.dumps({"message" : "The points had been removed"}), content_type='application/' + format)
            else:
                return HttpResponse(json.dumps({"message" : "The points entity don't exist"}), content_type='application/' + format)
        except ObjectDoesNotExist:
            return HttpResponse( json.dumps({"error" : str(e) }), content_type='application/' + format )

def process_points(file, file_points, split):
    group = -1
    id = -1
    lt = -1
    ln = -1
    text = -1
    value = -1
    number_line = 0
    file_name = os.path.join(settings.MAPS_POINTS, str(file_points.id) + '.json')
    file_writer = open(file_name, 'w+')
    content = ""
    for l in file:
        line=str(l).replace("b'",'').replace("\\r",'').replace("\\n'",'')
        if line != "":
            vals = re.split(split,str(line).lower())
            print(vals)
            if number_line == 0:
                group = vals.index("group")
                id = vals.index("id")
                lt = vals.index("latitude")
                ln = vals.index("longitude")
                text = vals.index("text")
                value = vals.index("value")
            else:
                content += '{"g":"' + vals[group] + '","i":"' + vals[id] + '","lt":"' + vals[lt] + '","ln":"' + vals[ln] + '","t":"' + vals[text] +'","v":"' + vals[value] + '"},\n'
        number_line += 1
    file_writer.write('{"points":[' + content[:len(content)-2] + '],\n"header":{"count":"' + str(number_line)  + '"}}')
    file_writer.close()
    #compress file
    zf = zipfile.ZipFile(os.path.join(settings.MAPS_POINTS, str(file_points.id) + '.zip'), 'w', zipfile.ZIP_DEFLATED)
    zf.write(file_name,str(file_points.id) + ".json")
    zf.close()


#!/usr/bin/python3
def replace_in_list(my_list, idx, element):

    '''Replaces a member in the my_list list at index idx for the
       element introduced in the function. Does nothing on error
       or if the index is out of bounds                       '''

    if idx < 0 or idx >= len(my_list):
        return my_list

    else:
        my_list[idx] = element
        return my_list


#!/usr/bin/env python
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# ------------------------------
# Name:     metagaia_viz.py
# Purpose:  use the output file after calculating bin abundacnces to visualize the data.
# @uthors:     sbs - sbs2756@utexas.edu
# Created:     2021
# Licence:     GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007
# ------------------------------
import argparse
import functools
import math
from matplotlib.patches import Patch
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import random
import re
import seaborn as sns

class Command_line_args():
    """
    This class contains all the arguments the user inputs for the class to run.
    Input(s):
    No other inputs needed.
    Output(s):
    None.
    """

    def __init__(self):

        #Command line arguments
        self.parser = argparse.ArgumentParser()
        self.parser.add_argument('-b', '--bin_abundance', required=True, type=str, help='Input tsv file outputted from the bin_abundance.py script with file extension.')
        self.parser.add_argument('-t', '--taxonomy_info', required=True, type=str, help='Input tsv or csv file mapping taxonomy to each bin with file extension.')
        self.parser.add_argument('-s', '--sample2site', required=True, type=str, default="", help='Input tsv or csv file containing each sample to the site it was taken from with file extension [""].')
        self.parser.add_argument('-p', '--percent', required=False, type=float, default=10, help='Percent of highest sample in each bin [10].')
        self.parser.add_argument('-w', '--width', required=False, type=int, default=4, help='Width of outputted clustermap figure [4].')
        self.parser.add_argument('-l', '--height', required=False, type=int, default=5, help='Height of outputted clustermap figure [5].')
        self.parser.add_argument('-d', '--dpi', required=False, type=int, default=300, help='Resolution for output figure file [300].')
        self.parser.add_argument('-o', '--out_fig', required=False, type=str, default="test.png", help='Stores the figure in the specified file path and format [test.png].')
        self.parser.add_argument('-c', '--taxa_color', required=False, type=str, default="", help='Input tsv or csv file containing the RGB color code for each taxa with file extension [""].')
        self.args = self.parser.parse_args()

def format_dataframe(arguments, bin_abundances, taxonomy_info):
    """
    Formats the bin abundances dataframe to a layout useable for cluster mapping.
    Input(s):
    arguments is a class containing all the command line arguments.
    bin_abundances is a pandas dataframe containing all the bin abundance information.
    taxonomy_info is a pandas dataframe containing all the taxaonomy information for each bin.
    Output(s):
    A formatted bin abundances dataframe.
    """

    if 'tsv' in arguments.args.sample2site:
        sample2site_df = pd.read_csv(arguments.args.sample2site, sep='\t')
    elif "csv" in arguments.args.sample2site:
        sample2site_df = pd.read_csv(arguments.args.sample2site)
    else:
        print("Please make sure all of your input files are in a tsv or csv format!")
        quit()
    bin_abundances = bin_abundances.merge(sample2site_df, on='Sample', how='left')
    bin_abundances = bin_abundances.drop(columns=['Sample']).rename(columns={'Site': 'Sample'})

    #Drop unneeded columns
    bin_abundances = bin_abundances.drop(columns=['RelativeAbundance', 'Sampling_Site', 'NormalizedCoverage'])
    #Log abundances
    bin_abundances['RelativeAbundanceReadable'] = np.log10(bin_abundances['RelativeAbundanceReadable'])
    #Check if NaN in RelativeAbundanceReadable
    if bin_abundances['RelativeAbundanceReadable'].isnull().values.any():
        bin_abundances = bin_abundances.dropna()
        print("WARNING: Some bins were not mapped to samples and thus discarded. If this is incorrect, please make sure the \"sample2site\" file is correct.")
    #Pivot table wider so that each bin is mapped to its respective site
    bin_abundances = bin_abundances.pivot(index='Bin', columns='Sample', values='RelativeAbundanceReadable')
    #Replace NaN with 0 and set the index to the Bin
    bin_abundances = bin_abundances.replace(np.nan, 0)

    if taxonomy_info.columns.tolist() != ['Bin', 'Taxa']:
        #Rename headers
        taxonomy_info.columns = ['Bin', 'Taxa']
    #Left join bin abundance file with taxanomy information
    bin_abundances = bin_abundances.merge(taxonomy_info, on='Bin', how='left').set_index('Bin')
    #Order dataframe by Taxa
    bin_abundances = bin_abundances.replace(np.nan, 'Unknown').sort_values('Taxa')
    print(bin_abundances.columns)
    #Sort columns
    bin_abundances = bin_abundances.reindex(sorted(bin_abundances.columns), axis=1)
    #Replace underscore with space in taxa names
    bin_abundances = bin_abundances.replace('_', ' ', regex=True)

    return bin_abundances

def get_color_palette(bin_abundances):
    """
    Obtains the number of colors needed to label each taxa and converts RGB to hex codes.
    Input(s):
    bin_abundances is a pandas dataframe with all the information joined together.
    Output(s):
    A list containing colors for heatmap.
    """

    #Fix how color scheme is selected
    final_colors_list = []

    #Get hex color codes
    for col in range(len(bin_abundances['Taxa'].unique())):
        r = lambda: random.randint(0,255)
        color = '#%02X%02X%02X' % (r(),r(),r())
        while color in final_colors_list:
            r = lambda: random.randint(0,255)
            color = '#%02X%02X%02X' % (r(),r(),r())
        final_colors_list.append(color)

    return final_colors_list

def filter_top_sites(arguments, bin_abundances):
    """
    Creates a dataframe with the top taxa in each bin.
    Input(s):
    arguments is a class containing all the command line arguments.
    bin_abundances is a pandas dataframe with all the information joined together.
    Output(s):
    merged_dfs is a new pandas dataframe containing the top samples in each column.
    """

    #List to keep dataframes together
    df_list = []
    #Get list of columns
    col_list = bin_abundances.drop(columns=['Taxa']).columns.tolist()
    #Number of rows to keep for each bin
    num_filter = math.floor((arguments.args.percent / 100) * len(bin_abundances))

    #Create new dataframe with top values for each column
    for col in col_list:
        #List of columns to drop after getting rows to keep
        drop_list = [bins for bins in col_list if bins != col]
        #Get needed rows
        bin_abundances_cp = bin_abundances.nlargest(n = num_filter, columns = col)
        #Drop all columns not of interest
        bin_abundances_cp = bin_abundances_cp.drop(columns = drop_list)
        df_list.append(bin_abundances_cp)

    #Combine dataframes into one
    merged_dfs = pd.concat(df_list)
    merged_dfs = merged_dfs.replace(np.nan, 0)
    merged_dfs = merged_dfs.sort_values('Taxa')
    merged_dfs = merged_dfs.drop_duplicates()
    merged_dfs = merged_dfs.reindex(sorted(merged_dfs.columns), axis=1)

    return merged_dfs

def create_clustermap(arguments, bin_abundances, palette, row_colors, heatmp = False):
    """
    Creates clustermap with taxonomic information.
    Input(s):
    bin_abundances is a pandas dataframe with all the information joined together.
    palette is a dictionary containing the taxa-to-color information.
    row_colors is a pandas object that maps the taxa to the color.
    Output(s):
    A clustermap of all the bins and taxa.
    """

    #Get the greatest dimension value
    max_size = max(arguments.args.width, arguments.args.height)

    #Set font size
    sns.set(font_scale=max_size/10)

    #Handles for taxa color legend
    handles = [Patch(facecolor=palette[name]) for name in palette]

    #Remove y axis labels if there are too many
    if len(bin_abundances) > 50:
        y_tick_label = False
    else:
        y_tick_label = True
    #Create clustermap with certain specifications
    if heatmp:
        cluster = sns.clustermap(bin_abundances.drop(columns="Taxa"), col_cluster=False, row_cluster=False, yticklabels=y_tick_label, cmap="Reds", row_colors=row_colors, method='ward', figsize=(arguments.args.width, arguments.args.height), cbar_pos=(0.05, .25, .03, .4))
        #Create taxa-color legend
        plt.legend(handles, palette, bbox_to_anchor=(1.2, 0.82), bbox_transform=plt.gcf().transFigure, loc='upper right', prop={'size': max_size/2}, facecolor="white", edgecolor="white")
    else:
        cluster = sns.clustermap(bin_abundances.drop(columns="Taxa"), col_cluster=True, row_cluster=True, yticklabels=y_tick_label, cmap="Reds", row_colors=row_colors, method='ward', figsize=(arguments.args.width, arguments.args.height))
        #Create taxa-color legend
        plt.legend(handles, palette, bbox_to_anchor=(1.2, 1), bbox_transform=plt.gcf().transFigure, loc='upper right', prop={'size': max_size/2}, facecolor="white", edgecolor="white")

    #Save or show plot
    if arguments.args.out_fig:
        if heatmp:
            plt.savefig(os.path.dirname(os.path.abspath(__file__)) + "/../../output/heatmap_top_" + str(arguments.args.percent) + "%_" + arguments.args.out_fig, dpi=arguments.args.dpi, bbox_inches="tight")
        else:
            plt.savefig(os.path.dirname(os.path.abspath(__file__)) + "/../../output/clustermap_" + arguments.args.out_fig, dpi=arguments.args.dpi, bbox_inches="tight")
    else:
        plt.show()

def main():

    arguments = Command_line_args()

    #Create output directory if not already present
    if not os.path.exists(os.path.dirname(os.path.abspath(__file__)) + "/../../output"):
        os.makedirs(os.path.dirname(os.path.abspath(__file__)) + "/../../output")

    #Read in bin abundance file
    if "tsv" in arguments.args.bin_abundance:
        bin_abundance_df = pd.read_csv(arguments.args.bin_abundance, sep = "\t")
    elif "csv" in arguments.args.bin_abundance:
        bin_abundance_df = pd.read_csv(arguments.args.bin_abundance)
    else:
        print("Please make sure all of your input files are in a tsv or csv format!")
        quit()

    #Read in taxanomy file
    if "tsv" in arguments.args.taxonomy_info:
        taxonomy_df = pd.read_csv(arguments.args.taxonomy_info, sep = "\t", header = 0)
    elif "csv" in arguments.args.taxonomy_info:
        taxonomy_df = pd.read_csv(arguments.args.taxonomy_info, header = 0)
    else:
        print("Please make sure all of your input files are in a tsv or csv format!")
        quit()

    #Format dataframe to desired layout
    bin_abundance_df = format_dataframe(arguments, bin_abundance_df, taxonomy_df)

    #Get colors for each taxa to use in heatmap
    if len(arguments.args.taxa_color) == 0:
        final_colors = get_color_palette(bin_abundance_df)
    else:
        if "tsv" in arguments.args.taxa_color:
            colors_df = pd.read_csv(arguments.args.taxa_color, sep = "\t", header = None)
        elif "csv" in arguments.args.taxa_color:
            colors_df = pd.read_csv(arguments.args.taxa_color, header = None)
        else:
            print("Please make sure all of your input files are in a tsv or csv format!")
            quit()
        final_colors = colors_df[0].tolist()

       #Set color palette
    my_palette = dict(zip(bin_abundance_df.Taxa.unique(), final_colors))
    row_colors = bin_abundance_df.Taxa.map(my_palette)

    #Outputs final clustermap
    create_clustermap(arguments, bin_abundance_df, my_palette, row_colors, False)

    #Get dataframe with highest abundances in each column
    merged_df = filter_top_sites(arguments, bin_abundance_df)
    merged_df.to_csv(os.path.dirname(os.path.abspath(__file__)) + '/../../output/top_' + str(arguments.args.percent) + '%_' + 'sample_abundances.tsv', sep='\t')

    #Set color palette
    my_palette = dict(zip(merged_df.Taxa.unique(), final_colors))
    row_colors = merged_df.Taxa.map(my_palette)

    #Outputs final heatmap
    create_clustermap(arguments, merged_df, my_palette, row_colors, True)

    print("Success!\nThe following files have been saved in the \"output\" directory:\n\ntop_" + str(arguments.args.percent) + "%_" + "sample_abundances.tsv\n" + "heatmap_top_" + str(arguments.args.percent) + "%_" + arguments.args.out_fig + "\nclustermap_" + arguments.args.out_fig)

if __name__ == "__main__":
    main()


from typing import List, Tuple

import numpy as np
import rasterio
from affine import Affine
from rasterio.enums import Resampling
from rasterio.io import MemoryFile
from rasterio.merge import merge

from .rio_window import get_indices_from_extent

def merge_tile_datasets(datasets: List[rasterio.DatasetReader],
                        bounds: list = None,
                        resampling: str = 'nearest',
                        res_buffer: int = 0,
                        nodata: float = np.nan
                        ) -> Tuple[np.ndarray, dict]:
    merged_arr, merged_transform = merge(datasets,
                                         resampling=Resampling[resampling],
                                         # This fixes the nodata values
                                         nodata=nodata,
                                         # This fixes the float32 output
                                         dtype='float32',
                                         )
    merged_arr = merged_arr[0, ...]

    # each pair is in (row, col) format
    corner_ul, corner_br = get_indices_from_extent(merged_transform,
                                                   bounds,
                                                   shape=merged_arr.shape,
                                                   res_buffer=res_buffer)
    sy = np.s_[corner_ul[0]: corner_br[0]]
    sx = np.s_[corner_ul[1]: corner_br[1]]
    merged_arr = merged_arr[sy, sx]

    # We swap row and columns because Affine expects (x, y) or (col, row)
    origin_affine = corner_ul[1], corner_ul[0]
    new_origin = merged_transform * origin_affine
    merged_transform_final = Affine.translation(*new_origin)
    merged_transform_final = merged_transform_final * Affine.scale(merged_transform.a,
                                                                   merged_transform.e)

    merged_profile = datasets[0].profile.copy()
    merged_profile['height'] = merged_arr.shape[0]
    merged_profile['width'] = merged_arr.shape[1]
    merged_profile['nodata'] = np.nan
    merged_profile['dtype'] = 'float32'
    merged_profile['transform'] = merged_transform_final
    return merged_arr, merged_profile

def merge_arrays_with_geometadata(arrays: List[np.ndarray],
                                  profiles: List[dict],
                                  resampling='bilinear',
                                  method='first') -> Tuple[np.ndarray, dict]:

    if len(arrays[0].shape) > 2:
        raise ValueError('Currently only supports 2d arrays')

    if (len(arrays)) != (len(profiles)):
        raise ValueError('Length of arrays and profiles needs to be the same')

    memfiles = [MemoryFile() for p in profiles]
    datasets = [mfile.open(**p) for (mfile, p) in zip(memfiles, profiles)]
    [ds.write(arr, 1) for (ds, arr) in zip(datasets, arrays)]

    merged_arr, merged_trans = merge(datasets,
                                     resampling=Resampling[resampling],
                                     method=method,
                                     )
    merged_arr = merged_arr[0, ...]

    prof_merged = profiles[0].copy()
    prof_merged['transform'] = merged_trans
    prof_merged['width'] = merged_arr.shape[1]
    prof_merged['height'] = merged_arr.shape[0]

    [ds.close() for ds in datasets]
    [mfile.close() for mfile in memfiles]

    return merged_arr, prof_merged


import cv2
import numpy as np
"""
Harris角点检测：
    光滑地区，无论向哪里移动，衡量系数不变
    边缘地址，垂直边缘移动时，衡量系数变化剧烈
    在交点处，往哪个方向移动，衡量系数都变化剧烈
    cornerHarris(img, dst, blockSize, ksize, k)
    blockSize:  检测窗口大小
    ksize: Sobel的卷积核
    k：权重系数，经验值，一般取0.02~0.04之间
"""
img = cv2.imread(r'E:\PycharmProjects\funnyPython\opencv_py\data\imgs\chess.png')
#灰度化
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

blockSize = 2
ksize = 3
k = 0.04
dst = cv2.cornerHarris(gray_img, blockSize, ksize, k)
# harris角点展示
img[dst > 0.01*dst.max()] = [0, 0, 255]

cv2.imshow('harris', img)
cv2.waitKey(0)


"""Class for a log reader."""

from os import listdir
from os.path import isfile, join

from csv import reader

import config

class LogReader():
    """
    Log reader class.

    Attributes:
        files (list): List of files this reader uses.
        header (list): List of columns in this file.
        data (dict): Column/Data key/value pairs.
        data_keys (list): Columns corresponding to the file they represent.

    """

    def __init__(self, filenames=None, prefix=None):
        """
        Init method for LogReader.

        One of filename or prefix should be specified,
        not both.

        Args:
            filenames (list): List of filenames to read.
            prefix (str): Prefix for filenames to read.

        """
        if filenames is None and prefix is None:
            raise AttributeError("One of filename or prefix must be specified")
        if filenames is not None and prefix is not None:
            raise AttributeError("Only one of filename or\
                                 prefix can be specified")

        self.files = []
        if prefix is not None:
            for fname in listdir(config.LOG_DIR):
                full_fname = join(config.LOG_DIR, fname)
                if fname.startswith(prefix) and isfile(full_fname):
                    self.files.append(full_fname)
        else:
            self.files = filenames

        if not self.files:
            raise AttributeError("No files match the prefix provided.")

        self.set_header()
        self.generate_data_keys()
        self.init_data()

    def set_header(self):
        """Extract the header information from a file."""
        sample_filename = self.files[0]
        with open(sample_filename) as sample_file:
            csv_reader = reader(sample_file)
            header_row = next(csv_reader)
            self.header = header_row

    def init_data(self):
        """Initialize an empty list for each column."""
        self.data = {}
        for colname in self.data_keys:
            self.data[colname] = []

    def generate_data_keys(self):
        """Generate list of keys for for self.data."""
        self.data_keys = self.to_data_key(self.header)

    def read_data(self):
        """Populate the data."""
        index = 0
        for filename in self.files:
            file_ = open(filename)
            csv_reader = reader(file_)
            file_header = next(csv_reader)

            if file_header != self.header:
                # Invalid file, reset data
                self.init_data()
                raise RuntimeError(
                    "File {} has an invalid header".format(filename))

            for row in csv_reader:
                for col_index in range(len(self.header)):
                    key_name = "{}{}".format(self.header[col_index], index)
                    self.data[key_name].append(row[col_index])

            index += 1
            file_.close()

    def to_data_key(self, colnames):
        """
        Convert list of column names into data_keys representation.

        Args:
            colnames (list): List of columns to convert into data_keys representation

        Returns:
            List of column names as they correspond to the keys of data.
                ex: "<colname>" becomes "<colname>1"

        """
        keys = []
        for index in range(len(self.files)):
            file_columns = ["{}{}".format(colname, index)
                            for colname in colnames]
            keys.extend(file_columns)
        return keys

    def to_numeric(self, colnames):
        """
        Make the columns in colnames numeric data.

        Args:
            colnames (list): List of columns to convert to numeric data.

        """
        for colname in colnames:
            if colname not in self.data_keys:
                raise AttributeError("Invalid column name: {}".format(colname))
            temp_col = []
            for datum in self.data[colname]:
                if datum != "NA":
                    # Valid Number
                    temp_col.append(float(datum))
                elif temp_col:
                    # Invalid number, use the last value we read
                    temp_col.append(temp_col[-1])
                else:
                    # Invalid number with no previous value, assume 1000
                    temp_col.append(1000)

            self.data[colname] = temp_col


from django import forms
from django.forms.fields import DateField

class AltaTurnoForm2(forms.Form):

    listado_especialidad = (('Z','Seleccione una especialidad'),('Cardiología','Cardiología'),('Dermatología','Dermatología'),('Neurología','Neurología'),('Oftalmología','Oftalmología'),('Pediatría','Pediatría'))

    listado_medicos = (('Z','Seleccione un médico'),
                       ('1','Dr. Juan Pérez (Cardiología)'),
                       ('2','Dra. María González (Dermatología)'),
                       ('3','Dr. Luis Sánchez (Neurología)'),
                       ('4','Dra. Ana Rodríguez (Oftalmología)'),
                       ('5','Dr. Pedro López (Pediatría)'))

    especialidad = forms.ChoiceField(label="especialidadx:",required=False, choices = listado_especialidad,
        widget=forms.Select(attrs={"class": "form-control", "id":"especialidad"}))
    medico = forms.ChoiceField(label="medicox:", required=False, choices = listado_medicos,
        widget=forms.Select(attrs={"class": "form-control", "id":"medico"}))
    fecha = forms.DateField(label="fechax:",required=False,
        widget=forms.DateInput(attrs={"class": "form-control", "id":"fecha",'type': 'date'}))


from .utils import try_open_img, get_image_filetypes, get_video_filetypes
from .window import Window
import tkinter.filedialog
import tkinter as tk
import cv2

def imshow(window, image, time=0):
    if isinstance(window, str):
        if window in Window._active_windows:
            window = Window._active_windows[window]
        else:
            window = Window(window)
    window.set_img(image)

    if time != 0:
        window.after(time, window.close)
    window.mainloop()

def namedWindow(name, *args, **kwargs):
    return Window(name, *args, **kwargs)

def destroyWindow(window):
    if isinstance(window, Window):
        window = window.name
    Window._active_windows[window].destroy()
    Window._active_windows.pop(window)

def destroyAllWindows():
    for _, window in Window._active_windows.items():
        window.destroy()
    Window._active_windows.clear()

def open_image(title="Open Image", parent=None, include_video=False, path_only=False):
    image_formats = get_image_filetypes(to_string=True)
    video_formats = get_video_filetypes(to_string=True)

    formats = [("Image Files", image_formats)]
    if include_video:
        formats = [("Media Files", image_formats+" "+video_formats)] + formats
        formats.append(("Video Files", video_formats))
    formats.append(("All Files", "*.*"))

    if isinstance(parent, str):
        if parent in Window._active_windows:
            parent = Window._active_windows[parent]
        else:
            parent = None
    path = tk.filedialog.askopenfilename(title=title, filetypes=formats, parent=parent)
    if isinstance(path, str):
        if path_only:
            return path
        else:
            return try_open_img(path, try_video=include_video)
    return None

def open_video(title="Open Video", parent=None, path_only=False):
    video_formats = get_video_filetypes(to_string=True)
    formats = [("Video Files", video_formats), ("All Files", "*.*")]

    if isinstance(parent, str):
        if parent in Window._active_windows:
            parent = Window._active_windows[parent]
        else:
            parent = None
    path = tk.filedialog.askopenfilename(title=title, filetypes=formats, parent=parent)
    if isinstance(path, str):
        if path_only:
            return path
        else:
            return cv2.VideoCapture(path)
    return None


#----------------------------------------------------------------------------#
# Imports
#----------------------------------------------------------------------------#

import json
from re import S
import ssl
import dateutil.parser
import babel
from flask import Flask, render_template, request, Response, flash, redirect, url_for
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
import logging
from logging import Formatter, FileHandler
from flask_wtf import FlaskForm
from forms import *
from flask_migrate import Migrate
import sys

#----------------------------------------------------------------------------#
# App Config.
#----------------------------------------------------------------------------#

app = Flask(__name__)
moment = Moment(app)
app.config.from_object('config')
db = SQLAlchemy(app)
migrate = Migrate(app, db)

from models import *

# TODO: connect to a local postgresql database
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user1:password@localhost:5432/fyyur'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

#----------------------------------------------------------------------------#
# Filters.
#----------------------------------------------------------------------------#

def format_datetime(value, format='medium'):
  date = dateutil.parser.parse(value)
  if format == 'full':
      format="EEEE MMMM, d, y 'at' h:mma"
  elif format == 'medium':
      format="EE MM, dd, y h:mma"
  return babel.dates.format_datetime(date, format, locale='en')

app.jinja_env.filters['datetime'] = format_datetime

#----------------------------------------------------------------------------#
# Controllers.
#----------------------------------------------------------------------------#

@app.route('/')
def index():
  return render_template('pages/home.html')

#  Venues
#  ----------------------------------------------------------------

@app.route('/venues')
def venues():
  # TODO: replace with real venues data.
  locations = {(i.city, i.state) for i in Venue.query.all()}
  locations_dict = {location: Venue.query.filter(Venue.city == location[0]).filter(Venue.state == location[1]) for location in locations}
  data = []

  for location in locations_dict:

    venues_info = []
    for venue in locations_dict[location]:
      venue_info = {
        "id": venue.id,
        "name": venue.name,
        "num_upcoming_shows": len(venue.shows)
      }

      venues_info.append(venue_info)

    area = {
      "city": location[0],
      "state": location[1],
      "venues": venues_info
    }

    data.append(area)

  return render_template('pages/venues.html', areas=data)

@app.route('/venues/search', methods=['POST'])
def search_venues():
  # TODO: implement search on venues with partial string search. Ensure it is case-insensitive.
  search_term = request.form.get('search_term', '')
  result = Venue.query.filter(Venue.name.ilike(f'%{search_term}%'))
  response={
    "count": result.count(),
    "data": result
  }
  return render_template('pages/search_venues.html', results=response, search_term=request.form.get('search_term', ''))

@app.route('/venues/<int:venue_id>')
def show_venue(venue_id):
  # shows the venue page with the given venue_id
  # TODO: replace with real venue data from the venues table, using venue_id
  venue = Venue.query.get(venue_id)
  shows = Show.query.filter_by(venue_id=venue_id).all()
  past_shows = []
  upcoming_shows = []
  current_time = datetime.now()

  for i in shows:
    data = {
          "artist_id": i.artist_id,
          "artist_name": i.artist.name,
           "artist_image_link": i.artist.image_link,
           "start_time": format_datetime(str(i.start_time))
        }
    if i.start_time > current_time:
      upcoming_shows.append(data)
    else:
      past_shows.append(data)

  data={
    "id": venue.id,
    "name": venue.name,
    "genres": venue.genres,
    "address": venue.address,
    "city": venue.city,
    "state": venue.state,
    "phone": venue.phone,
    "website": venue.website,
    "facebook_link": venue.facebook_link,
    "seeking_talent": venue.seeking_talent,
    "seeking_description":venue.seeking_description,
    "image_link": venue.image_link,
    "past_shows": past_shows,
    "upcoming_shows": upcoming_shows,
    "past_shows_count": len(past_shows),
    "upcoming_shows_count": len(upcoming_shows)
  }
  return render_template('pages/show_venue.html', venue=data)

#  Create Venue
#  ----------------------------------------------------------------

@app.route('/venues/create', methods=['GET'])
def create_venue_form():
  form = VenueForm()
  return render_template('forms/new_venue.html', form=form)

@app.route('/venues/create', methods=['POST'])
def create_venue_submission():
  # TODO: insert form data as a new Venue record in the db, instead
  # TODO: modify data to be the data object returned from db insertion

  error = False
  try:
    form = VenueForm(request.form)
    venue = Venue(name=form.name.data, city=form.city.data, state=form.state.data, address=form.address.data,
                  phone=form.phone.data, image_link=form.image_link.data, genres=form.genres.data,
                  facebook_link=form.facebook_link.data, seeking_description=form.seeking_description.data,
                  website=form.website.data, seeking_talent=form.seeking_talent.data)
    db.session.add(venue)
    db.session.commit()

  # on successful db insert, flash success
    flash('Venue ' + request.form['name'] + ' was successfully listed!')
  # TODO: on unsuccessful db insert, flash an error instead.
  except:
    db.session.rollback()
    print(sys.exc_info())
    flash('An error occurred. Venue ' + request.form['name'] + ' could not be listed.')
  # see: http://flask.pocoo.org/docs/1.0/patterns/flashing/
  finally:
    db.session.close()
    return render_template('pages/home.html')

@app.route('/venues/<venue_id>', methods=['DELETE'])
def delete_venue(venue_id):
  # TODO: Complete this endpoint for taking a venue_id, and using
  # SQLAlchemy ORM to delete a record. Handle cases where the session commit could fail.
  # BONUS CHALLENGE: Implement a button to delete a Venue on a Venue Page, have it so that
  # clicking that button delete it from the db then redirect the user to the homepage
  try:
    venue = Venue.query.get(venue_id)
    venue_name = venue.name
    db.session.delete(venue)
    db.session.commit()
    flash('Venue ' + venue_name + ' was successfully deleted')
  except:
    flash(' a very serious error occured and Venue ' + venue_name + ' was not deleted')
    db.session.rollback()
  finally:
    db.session.close()
  return redirect(url_for('index'))

#  Artists
#  ----------------------------------------------------------------
@app.route('/artists')
def artists():
  # TODO: replace with real data returned from querying the database
  data = Artist.query.all()

  return render_template('pages/artists.html', artists=data)

@app.route('/artists/search', methods=['POST'])
def search_artists():
  # TODO: implement search on artists with partial string search. Ensure it is case-insensitive.
  # seach for "A" should return "Guns N Petals", "Matt Quevado", and "The Wild Sax Band".
  # search for "band" should return "The Wild Sax Band".

  search_term = request.form.get('search_term', '')
  result = Artist.query.filter(Artist.name.ilike(f'%{search_term}%'))
  response = {'count': result.count(),'data': result}

  return render_template('pages/search_artists.html', results=response, search_term=request.form.get('search_term', ''))

@app.route('/artists/<int:artist_id>')
def show_artist(artist_id):
  # shows the artist page with the given artist_id
  # TODO: replace with real artist data from the artist table, using artist_id
  artist = Artist.query.get(artist_id)
  shows = Show.query.filter_by(artist_id=artist_id).all()
  upcoming_shows = db.session.query(Show).join(Artist).filter(Show.artist_id == artist_id).filter(Show.start_time > datetime.now()).all()
  past_shows = db.session.query(Show).join(Artist).filter(Show.artist_id == artist_id).filter(Show.start_time < datetime.now()).all()
  past_shows = []
  upcoming_shows = []
  current_time = datetime.now()

  # This is used to filter shows by upcoming and past

  for i in shows:
    data = {'venue_id': i.venue_id,
      'venue_name': i.venue.name,
      'venue_image_link': i.venue.image_link,
      'start_time': format_datetime(str(i.start_time))
    }
    if i.start_time > current_time:
      upcoming_shows.append(data)
    else:
      past_shows.append(data)

  data = {
    'id': artist.id,
    'name': artist.name,
    'genres': artist.genres,
    'city': artist.city,
    'state': artist.state,
    'phone': artist.phone,
    'facebook_link': artist.facebook_link,
    'image_link': artist.image_link,
    'past_shows': past_shows,
    'upcoming_shows': upcoming_shows,
    'past_shows_count': len(past_shows),
    'upcoming_shows_count': len(upcoming_shows)
  }

  return render_template('pages/show_artist.html', artist=data)

#  Update
#  ----------------------------------------------------------------
@app.route('/artists/<int:artist_id>/edit', methods=['GET'])
def edit_artist(artist_id):
  form = ArtistForm()
  artist=Artist.query.filter_by(id=artist_id).first()
  # TODO: populate form with fields from artist with ID <artist_id>
  artist_data={
    "id": artist.id,
    "name": artist.name,
    "genres": artist.genres,
    "city": artist.city,
    "state": artist.state,
    "phone": artist.phone,
    "facebook_link": artist.facebook_link,
    "image_link": artist.image_link
  }

  return render_template('forms/edit_artist.html', form=form, artist=artist)

@app.route('/artists/<int:artist_id>/edit', methods=['POST'])
def edit_artist_submission(artist_id):
  # TODO: take values from the form submitted, and update existing
  # artist record with ID <artist_id> using the new attributes
  try:
    form = ArtistForm(request.form)
    artist = Artist.query.get(artist_id)
    name = form.name.data
    artist.name = name
    artist.phone = form.phone.data
    artist.state = form.state.data
    artist.city = form.city.data
    artist.genres = form.genres.data
    artist.image_link = form.image_link.data
    artist.facebook_link = form.facebook_link.data

    db.session.commit()
    flash('The Artist ' + request.form['name'] + ' has been successfully updated!')
  except:
    db.session.rollback()
    flash('An Error has occured and the update unsucessful')
  finally:
    db.session.close()

  return redirect(url_for('show_artist', artist_id=artist_id))

@app.route('/venues/<int:venue_id>/edit', methods=['GET'])
def edit_venue(venue_id):
  # TODO: populate form with values from venue with ID <venue_id>
  form = VenueForm()
  venue = Venue.query.get(venue_id)
  venue = {
    "id": venue_id,
    "name": venue.name,
    "genres": venue.genres,
    "address": venue.address,
    "city": venue.city,
    "state": venue.state,
    "phone": venue.phone,
    "website":venue.website,
    "facebook_link": venue.facebook_link,
    "seeking_talent": venue.seeking_talent,
    "seeking_description": venue.seeking_description,
    "image_link": venue.image_link
  }
  return render_template('forms/edit_venue.html', form=form, venue=venue)

@app.route('/venues/<int:venue_id>/edit', methods=['POST'])
def edit_venue_submission(venue_id):
  # TODO: take values from the form submitted, and update existing
  # venue record with ID <venue_id> using the new attributes
  try:
    form = VenueForm()
    venue = Venue.query.get(venue_id)
    name = VenueForm.name.data
    venue.name = name
    venue.genres = form.genres.data
    venue.city = form.city.data
    venue.state = form.state.data
    venue.address = form.address.data
    venue.phone = form.phone.data
    venue.facebook_link = form.facebook_link.data
    venue.website = form.website.data
    venue.image_link = form.image_link.data
    venue.seeking_talent = form.seeking_talent.data
    venue.seeking_description = form.seeking_description.data
    db.session.commit()
    flash('Venue ' + name + 'has been updated')
  except:
    db.session.rollback()
    flash('An error occured while trying to update Venue')
  finally:
    db.session.close()

  return redirect(url_for('show_venue', venue_id=venue_id))

#  Create Artist
#  ----------------------------------------------------------------

@app.route('/artists/create', methods=['GET'])
def create_artist_form():
  form = ArtistForm()
  return render_template('forms/new_artist.html', form=form)

@app.route('/artists/create', methods=['POST'])
def create_artist_submission():
  # called upon submitting the new artist listing form
  # TODO: insert form data as a new Venue record in the db, instead
  # TODO: modify data to be the data object returned from db insertion
  try:
    form = ArtistForm(request.form)
    artist = Artist(name=form.name.data, city=form.city.data, state=form.state.data,
                    phone=form.phone.data, genres=form.genres.data,
                    image_link=form.image_link.data, facebook_link=form.facebook_link.data)
    db.session.add(artist)
    db.session.commit()
  # on successful db insert, flash success
    flash('Artist ' + request.form['name'] + ' was successfully listed!')
  # TODO: on unsuccessful db insert, flash an error instead.
  except:
    db.session.rollback()
    flash('An error occurred. Artist ' + request.form['name'] + ' could not be listed.')
  finally:
    db.session.close()

  return render_template('pages/home.html')

@app.route('/artist/<int:artist_id>', methods=['DELETE'])
def delete_artist(artist_id):
    # TODO: on unsuccessful db insert, flash an error instead.
  try:
    artist = Artist.query.get(artist_id)
    artist_name = artist.name
    db.session.delete(artist)
    db.session.commit()
    flash('Artist ' + artist_name + ' was deleted')
  except:
    flash('An error occured and Artist ' + artist_name + ' was not deleted')
    db.session.rollback()
  finally:
    db.session.close()

  return redirect(url_for('index'))

#  Shows
#  ----------------------------------------------------------------

@app.route('/shows')
def shows():
  # displays list of shows at /shows
  # TODO: replace with real venues data.
  shows = Show.query.order_by(db.desc(Show.start_time))
  data = []
  for i in shows:
    data.append({
      'venue_id': i.venue_id,
      'venue_name': i.venue.name,
      'artist_id': i.artist_id,
      'artist_name': i.artist.name,
      'artist_image_link': i.artist.image_link,
      'start_time': format_datetime(str(i.start_time))
    })

  return render_template('pages/shows.html', shows=data)

@app.route('/shows/create')
def create_shows():
  # renders form. do not touch.
  form = ShowForm()
  return render_template('forms/new_show.html', form=form)

@app.route('/shows/create', methods=['POST'])
def create_show_submission():
  # called to create new shows in the db, upon submitting new show listing form
  # TODO: insert form data as a new Show record in the db, instead
  # on successful db insert, flash success
  try:
    show = Show(artist_id=request.form['artist_id'], venue_id=request.form['venue_id'],start_time=request.form['start_time'])
    db.session.add(show)
    db.session.commit()
    flash('Show was successfully listed!')

  # TODO: on unsuccessful db insert, flash an error instead.
  except:
    db.session.rollback()
    flash('An error occurred. Show could not be listed.')
  # see: http://flask.pocoo.org/docs/1.0/patterns/flashing/
  return render_template('pages/home.html')

@app.errorhandler(404)
def not_found_error(error):
    return render_template('errors/404.html'), 404

@app.errorhandler(500)
def server_error(error):
    return render_template('errors/500.html'), 500

if not app.debug:
    file_handler = FileHandler('error.log')
    file_handler.setFormatter(
        Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')
    )
    app.logger.setLevel(logging.INFO)
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.info('errors')

#----------------------------------------------------------------------------#
# Launch.
#----------------------------------------------------------------------------#

# Default port:
if __name__ == '__main__':
    app.run()

# Or specify port manually:
'''
if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)
'''


from django.shortcuts import render, get_object_or_404
from .models import Blog, Category

# Create your views here.
def home(request):
    return render(request, 'index.html')

def blogs(request):
    categorylist = Category.objects.all()
    bloglist = Blog.objects.filter(status='PB')
    pinnedblogs = bloglist.filter(pin='PI')

    categorydict = {}
    for category in categorylist:
        categorydict[category] = []
    for blog in bloglist:
        categorydict[blog.category].append(blog)
    print(categorydict)
    return render(request, 'blogs.html', {'blogs':bloglist[:4], 'categories' : categorydict, 'pinnedblogs':pinnedblogs})

def blog(request, pk):
    the_blog = get_object_or_404(Blog, pk=pk)
    return render(request, 'blog.html', {'blog':the_blog})


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
from pseudo_rng import pseudo_gauss
from scipy import fftpack

class DTMF:
    LOW_FREQ = [697.0, 770.0, 852.0, 941.0]
    HIGH_FREQ = [1209.0, 1336.0, 1477.0, 1633.0]
    KEYPAD = [
        ['1', '2', '3', 'A'],
        ['4', '5', '6', 'B'],
        ['7', '8', '9', 'C'],
        ['*', '0', '#', 'D']
    ]
    KEYMAP = (lambda pad, low, high: {pad[i][j]: (l, h) for i, l in enumerate(low) for j, h in enumerate(high)})(
        KEYPAD, LOW_FREQ, HIGH_FREQ)

    def __init__(self, SR=44100.0, SNR_dB=5, dial_ms_range=(300, 500), interval_ms=500, volume=0.5):
        """
        Initialize dual-tone multi-frequency signaling encoder/decoder.

        :param SR:            sampling rate.
        :param SNR_dB:        dB of signal-to-noise ratio.
        :param dial_ms_range: milliseconds of dial time. Choose value in this range randomly.
        :param interval_ms:   milliseconds of interval time.
        :param volume:        volume value.
        """
        self.SR = SR
        self.SNR_dB = SNR_dB
        self.dial_ms_range = dial_ms_range
        self.interval_ms = interval_ms
        self.volume = volume

    @staticmethod
    def AWGN_func(signal, mean, devi):
        return signal + np.array([pseudo_gauss(mean, devi) for _ in range(signal.shape[0])])

    @staticmethod
    def _encodable(m):
        for letter in m:
            if letter not in DTMF.KEYMAP: return False
        return True

    def _ms_to_samples(self, ms):
        return int(ms / 1000 * self.SR)

    def _gen_tone(self, letter, ms=None):
        if ms is None: ms = np.random.randint(*self.dial_ms_range)
        samples = self._ms_to_samples(ms)
        low, high = DTMF.KEYMAP[letter]
        tone = [0.5 * np.sin(2.0 * np.pi * i * low / self.SR) +
                0.5 * np.sin(2.0 * np.pi * i * high / self.SR)
                for i in range(samples)]
        return tone

    def encode(self, message, letter_ms=None, remove_noise=False):
        """
        Encode message to sound wave.

        :param message:      message to encode.
        :param letter_ms:    if None, random choose time from dial_ms_range.
        :param remove_noise: if remove noise.
        :return:             encoded sound wave.
        """
        if not self._encodable(message): raise ValueError(f'Message "{message}" is not encodable.')
        interval_samples = self._ms_to_samples(self.interval_ms)
        wave = np.zeros(interval_samples)
        tones = np.zeros(0)
        for m in message:
            tone = self._gen_tone(m, letter_ms)
            tones = np.concatenate([tones, tone])
            wave = np.concatenate([wave, tone, np.zeros(interval_samples)])

        AWGM_devi = tones.std() / (10 ** (self.SNR_dB / 20))
        print(f'Message: "{message}"    (SNR = {self.SNR_dB}dB)')
        print(f'  Dial wave (without silent interval) standard deviation: {tones.std():.2f}')
        print(f'  AWGM standard deviation: {AWGM_devi:.2f}')
        if not remove_noise: wave = self.AWGN_func(wave, 0, AWGM_devi)
        return self.volume * wave

def show_amplitude(wave, sampling_rate):
    X = fftpack.fft(wave)
    freq = fftpack.fftfreq(len(wave)) * sampling_rate

    fig, ax = plt.subplots()
    ax.stem(freq, np.abs(X), use_line_collection=True, markerfmt='C0,')
    ax.set_xlabel('Frequency (Hz)')
    ax.set_ylabel('Frequency magnitude')
    ax.set_xlim(0, 2500)
    plt.show()

def _make_short_time_window(wave, window_size, shift):
    n_samples = wave.shape[0]
    n_windows = int(np.ceil((n_samples - window_size) / shift))
    window = np.zeros((n_windows, window_size))
    for i in range(n_windows):
        window[i] = wave[i * shift:i * shift + window_size]
    return window

def plot_wave_amplitude(wave, sampling_rate, ax=None, hide_x=False):
    if ax is None:
        fig, ax = plt.subplots(figsize=(12, 2), dpi=400)
    ax.plot(wave, color=(0.27, 0.87, 0.61, 1), lw=0.2)
    ax.set_facecolor((0, 0, 0))
    ax.set_xlim(0, len(wave) - 1)
    n_secs = int(len(wave) / sampling_rate) + 1
    ax.set_xticks(list(range(0, n_secs * int(sampling_rate), 2 * int(sampling_rate))))
    ax.grid(color=(0, 0.4, 0), which='both')
    if hide_x:
        ax.set_xticklabels([])
    else:
        ax.set_xticklabels([(lambda tick: f'{int(tick / sampling_rate)}')(t) for t in ax.get_xticks()])
        ax.set_xlabel('Time (second)')
    ax.set_ylabel('Amplitude')
    return ax

def plot_short_time_freq(wave, sampling_rate, window_size=1024, shift=100, display_max_freq=None, ax=None):
    n_samples = wave.shape[0]
    max_freq = sampling_rate / 2
    window = _make_short_time_window(wave, window_size, shift)
    window = (window * np.hanning(window_size + 1)[:-1]).T
    spectrum = np.fft.fft(window, axis=0)[:window_size // 2 + 1:-1]
    spectrum = np.abs(spectrum)[:, :-2]

    if ax is None:
        fig, ax = plt.subplots(figsize=(12, 2))
    spec = np.abs(spectrum)

    # Comment for visualization performance
    # spec = 20 * np.log10(spec / np.max(spec))

    display_max_idx = int(spec.shape[0] * min(display_max_freq / max_freq, 1))
    spec = spec[:display_max_idx]

    ax.imshow(spec, origin='lower', cmap='gist_heat',
              extent=(0, n_samples / sampling_rate, 0, display_max_freq))
    ax.axis('tight')
    ax.set_ylabel('Frequency (kHz)')
    ax.set_xlabel('Time (second)')
    return ax

def construct_dtmf_experiment(message, SNR_dB):
    dial = DTMF(dial_ms_range=(300, 500), interval_ms=500, volume=0.2, SNR_dB=SNR_dB)
    wave = dial.encode(message, remove_noise=False)

    fig, (ax_up, ax_down) = plt.subplots(nrows=2, ncols=1, figsize=(12, 5))
    plot_wave_amplitude(wave, dial.SR, ax=ax_up, hide_x=True)
    plot_short_time_freq(wave, dial.SR, display_max_freq=2500, ax=ax_down)
    ax_up.set_title(f'Message: "{message}"    (SNR = {SNR_dB}dB)')
    plt.show()

def main():
    construct_dtmf_experiment('13991156869', 3)
    construct_dtmf_experiment('13991156869', -5)
    construct_dtmf_experiment('13991156869', -10)

if __name__ == '__main__':
    main()


class Book:
    def __init__(self, title, price):
        self.title = title
        self.price = price

mybook = Book("bitcoin auto-buy using python", 27000)
print(mybook.title, mybook.price)

mybook2 = ("bitcoin auto-buy using python", 27000)
print(mybook2[0], mybook2[1])

from collections import namedtuple

Book = namedtuple('Book', ['title', 'price'])
mybook3 = Book("bitcoin auto-buy using python", 27000)
print(mybook3.title, mybook3.price)

def print_book(title, price):
    print(title, price)

print_book(*mybook3)

class Func:
    def __call__(self):
        print("called")

f = Func()
f()

def foo(*args):
    print(args)

foo(1, 2, 3)

def foo2(**kwargs):
    print(kwargs)

foo2(a = 1, b = 2, c = 3)

def foo3(*args, **kwargs):
    print(args)
    print(kwargs)

foo3(5, 6, 7, d = 1, e = 2, f = 3)

def foo4(a, b, c):
    print(a, b, c)

date = [1, 2, 3]

foo4(*date)

a = lambda x : x*5

print(a(4))

'''
def outer(num):
    num += 3
    def inner():
        nonlocal num
        num += 3
        return num
    return inner

f = outer(3)
f(2)
'''

# enclosed function locals

def outer2():
    num = 3
    def inner():
        print(num)

    return inner

f = outer2()
f()

def outer3(num):
    def inner():
        print(num)

    return inner

f1 = outer3(3)
f2 = outer3(4)
f1()
f2()

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("-d", "--decidal", dest="decimal", action="store")
parser.add_argument("-f", "--fast", dest="fast", action="store_true")
args = parser.parse_args()

print(args.decimal)
print(args.fast)

import subprocess

output = subprocess.check_output("tasklist")
data = output.decode('cp949')
lines = data.splitlines()

for line in lines:
    print(line)

a = [1, 2, 3]
print(iter(a))

class Car:
    def __init__(self, model):
        self.model = model

    @property
    def get_model(self):
        return self.model

c = Car("GV80")
print(c.get_model)

def outer4(out1):
    def inner(in1):
        print("inner function called")
        print("outer argument: ", out1)
        print("inner argument: ", in1)
    return inner

f = outer4(1)
f(10)

'''
def inner():
    print("inner function is called")

inner()
'''

def deco(f):
    def wrapper():
        print("-" * 20)
        f()
        print("-" * 20)
    return wrapper

# decorated_inner = deco(inner)

# decorated_inner()

@deco
def inner():
    print("inner function called")

inner()


import sys
input = sys.stdin.readline

n = int(input().rstrip())
string = input().rstrip()
if len(string) <= 25: print(string)
else:
    nstring = string[11:len(string)-11]
    if (nstring.count('.') == 1 and nstring[-1] == '.') or (nstring.count('.') == 0):
        print(string[:11] + "..." + string[len(string)-11:])
    else:
        print(string[:9] + "......" + string[len(string)-10:])