import os
import re
import sys
from pathlib import Path
import platform
import subprocess
import shutil
from setuptools import setup, find_packages
from skbuild import setup

vtk_version = os.getenv('VTK_WHEEL_SDK_VERSION', None)
if vtk_version is None:
    import vtk
    vtk_version = vtk.__version__

vtk_openvr_module_source_dir = Path(__file__).parent.resolve()

def auto_download_vtk_wheel_sdk():
    # Automatically download the VTK wheel SDK based upon the current platform
    # and python version.
    # If the download location changes, we may need to change the logic here.
    # Returns the path to the unpacked SDK.

    base_url = 'https://vtk.org/files/wheel-sdks/'
    prefix = 'vtk-wheel-sdk'
    default_sdk_version = vtk_version
    # The user can set the sdk version via an environment variable
    sdk_version = os.getenv('VTK_WHEEL_SDK_VERSION', default_sdk_version)
    py_version_short = ''.join(map(str, sys.version_info[:2]))

    py_version = f'cp{py_version_short}-cp{py_version_short}'
    if sys.version_info[:2] < (3, 8):
        # Need to add 'm' at the end
        py_version += 'm'

    platform_suffixes = {
        'linux': 'manylinux_2_17_x86_64.manylinux2014_x86_64',
        'darwin': 'macosx_10_10_x86_64',
        'win32': 'win_amd64',
    }

    if sys.platform not in platform_suffixes:
        raise NotImplementedError(sys.platform)

    platform_suffix = platform_suffixes[sys.platform]

    if sys.platform == 'darwin':
        is_arm = (
            platform.machine() == 'arm64' or
            # ARCHFLAGS: see https://github.com/pypa/cibuildwheel/discussions/997
            os.getenv('ARCHFLAGS') == '-arch arm64'
        )
        if is_arm:
            # It's an arm64 build
            platform_suffix = 'macosx_11_0_arm64'

    dir_name = f'{prefix}-{sdk_version}-{py_version}-{platform_suffix}'
    default_install_path = Path('.').resolve() / f'_deps/{dir_name}'
    install_path = Path(os.getenv('VTK_WHEEL_SDK_INSTALL_PATH',
                                  default_install_path))

    if install_path.exists():
        # It already exists, just return it
        return install_path.as_posix()

    # Need to download it
    full_name = f'{prefix}-{sdk_version}-{py_version}-{platform_suffix}.tar.xz'
    url = f'{base_url}{full_name}'

    script_path = str(vtk_openvr_module_source_dir /
                      'FetchFromUrl.cmake')

    cmd = [
        'cmake',
        f'-DFETCH_FROM_URL_PROJECT_NAME={prefix}',
        f'-DFETCH_FROM_URL_INSTALL_LOCATION={install_path.as_posix()}',
        f'-DFETCH_FROM_URL_URL={url}',
        '-P', script_path,
    ]
    subprocess.check_call(cmd)

    return install_path.as_posix()

def auto_download_vtk_external_module():
    # Automatically download the VTKExternalModule repository.
    # Returns the path to the VTKExternalModule directory.

    external_module_path = Path('.').resolve() / '_deps/VTKExternalModule'
    if external_module_path.exists():
        # It must have already been downloaded. Just return it.
        return external_module_path.as_posix()

    # Run the script to download it
    script_path = str(vtk_openvr_module_source_dir /
                      'FetchVTKExternalModule.cmake')
    cmd = [
        'cmake',
        '-DFETCH_VTKExternalModule_INSTALL_LOCATION=' +
        external_module_path.as_posix(),
        '-P', script_path,
    ]
    subprocess.check_call(cmd)
    return external_module_path.as_posix()

def auto_download_vtk_source_tree():
    # Automatically downloads the vtk source tree corresponding to the installed vtk version

    vtk_source_path = Path('.').resolve() / '_deps/VTK'
    if vtk_source_path.exists():
        # It must have already been downloaded. Just return it.
        return vtk_source_path.as_posix()
    # Run the script to download it
    script_path = str(vtk_openvr_module_source_dir /
                      'FetchVTKSourcetree.cmake')
    cmd = [
        'cmake',
        '-DFETCH_VTK_INSTALL_LOCATION=' +
            vtk_source_path.as_posix(),
        '-DVTK_VERSION=' + str(vtk_version),
        '-P', script_path,
    ]
    subprocess.check_call(cmd)
    return vtk_source_path.as_posix()

vtk_wheel_sdk_path = os.getenv('VTK_WHEEL_SDK_PATH')
if vtk_wheel_sdk_path is None:
    vtk_wheel_sdk_path = auto_download_vtk_wheel_sdk()

# check that vtkRenderingopenvr is not part of the wheel
cmake_glob = list(Path(vtk_wheel_sdk_path).glob('**/vtkmodules/vtkRenderingOpenVR.pyi'))
if len(cmake_glob) >= 1:
    raise ValueError("RenderingOpenVR is already part of the python wheels for vtk. Aborting.")

# Find the cmake dir
cmake_glob = list(Path(vtk_wheel_sdk_path).glob('**/headers/cmake'))
if len(cmake_glob) != 1:
    raise Exception('Unable to find cmake directory')

vtk_wheel_sdk_cmake_path = cmake_glob[0]

vtk_external_module_path = os.getenv('VTK_EXTERNAL_MODULE_PATH')
if vtk_external_module_path is None:
    # If it was not provided, clone it into a temporary directory
    # Since we are using pyproject.toml, it will get removed automatically
    vtk_external_module_path = auto_download_vtk_external_module()

vtk_source_tree_path = os.getenv('VTK_SOURCE_TREE_PATH')
if vtk_source_tree_path is None:
    # If it was not provided, clone it into a temporary directory
    # Since we are using pyproject.toml, it will get removed automatically
    vtk_source_tree_path = auto_download_vtk_source_tree()

vtk_openvr_sources_path = (Path(vtk_source_tree_path) / "Rendering/OpenVR")

python3_executable = os.getenv('Python3_EXECUTABLE')
if python3_executable is None:
    python3_executable = shutil.which('python')

if python3_executable is None:
    msg = 'Unable find python executable, please set Python3_EXECUTABLE'
    raise Exception(msg)

cmake_args = [
    '-DVTK_MODULE_NAME:STRING=RenderingOpenVR',
    f'-DVTK_MODULE_SOURCE_DIR:PATH={vtk_openvr_sources_path}',
    f'-DVTK_MODULE_CMAKE_MODULE_PATH:PATH={vtk_wheel_sdk_cmake_path}',
    f'-DVTK_DIR:PATH={vtk_wheel_sdk_cmake_path}',
    '-DCMAKE_INSTALL_LIBDIR:STRING=lib',
    f'-DPython3_EXECUTABLE:FILEPATH={python3_executable}',
    '-DVTK_WHEEL_BUILD:BOOL=ON',
    '-S', vtk_external_module_path,
]

if sys.platform == 'linux':
    #if os.getenv('LINUX_VTK_OPENXR_USE_COMPATIBLE_ABI') == '1':
    # If building locally, it is necessary to set this in order to
    # produce a wheel that can be used. Otherwise, the VTK symbols
    # will not match those in the actual VTK wheel.
    cmake_args.append('-DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0')
else:
    raise ValueError("Only linux is supported right now.")

setup(
    name="vtk-openvr",
    version=vtk_version,
    author="Felix Igelbrink",
    author_email="felix.igelbrink@uni-osnabrueck.de",
    description="VTK's openVR module built as a separate python package",
    license="MIT",
    classifiers=[
        'Private :: Do Not Upload to pypi server',
    ],
    packages=['vtkmodules', 'vtk_openvr'],
    package_dir={'vtkmodules': 'lib/vtkmodules'},
    install_requires=['numpy'],
    cmake_args=cmake_args,
    zip_safe=False,
)


from django.urls import path
from . import views
from .views import statistic, reset_tasks, reset_task_by_key, status_tasks

urlpatterns = [
    path("post/", views.Post.as_view()),

    path("proxy/", views.Proxy.as_view()),
    path("proxy/<int:pk>/", views.Proxy.as_view()),

    path("account/", views.Account.as_view()),
    path("account/<int:pk>/", views.Account.as_view()),

    path("worker/", views.Worker.as_view()),
    path("proxy/", views.Proxy.as_view()),
    path('statistic', statistic),

    path("reset_tasks", reset_tasks),
    path("reset_task_by_key", reset_task_by_key),
    path("status_tasks", status_tasks)

]


"""
Given an array A of size N denoting collection of numbers that might contain duplicates,
return all possible unique permutations.

NOTE: No 2 entries in the permutation sequence should be the same.
"""

# @param A : list of integers
# @return a list of list of integers
def permute(A):
    A.sort()

    def rec(arr, curr, res):
        if len(arr) == 1:
            res.append(curr + arr)
            return
        i = 0
        while i < len(arr):
            rec(arr[:i] + arr[i + 1:], curr + [arr[i]], res)
            j = i
            while j < len(arr) and arr[j] == arr[i]:
                j += 1
            i = j

    perms = []
    rec(A, [], perms)
    return perms


#%%

import base64
from pathlib import Path

import altair as alt
import numpy as np
import pandas as pd
import requests
import streamlit as st
import time

import streamlit.components.v1 as components

#%%

def get_data(screen_name):
    url = f"https://mescalc.p.rapidapi.com/account/{screen_name.lower()}"
    headers = {
        "X-RapidAPI-Host": st.secrets["host"],
        "X-RapidAPI-Key": st.secrets["key"],
    }
    return requests.request("GET", url, headers=headers).json()

# https://stackoverflow.com/questions/70932538/how-to-center-the-title-and-an-image-in-streamlit
def img_to_bytes(img_path):
    img_bytes = Path(img_path).read_bytes()
    return base64.b64encode(img_bytes).decode()

def img_to_html(img_path):
    return f""

def percent_delta(misinfo, partisan):
    misinfo = np.float_(misinfo)
    partisan = np.float_(partisan)
    misinfo_mean = 0.51
    partisan_mean = -0.352 + 1  # rescale to [0, 1], original was [-1, 1]
    follower_mean = 4.65

    partisan += 1
    misinfo_delta = misinfo - misinfo_mean
    partisan_delta = partisan - partisan_mean

    return np.round(misinfo_delta / misinfo_mean * 100, 2), np.round(
        partisan_delta / partisan_mean * 100, 2
    )

def lower_or_higher(delta):
    if delta is None:
        return delta
    if delta[0] == "-":
        delta = f"{delta} lower than average"
    else:
        delta = f"{delta} higher than average"
    return delta

#%% data

df_falsity = pd.read_csv("data/falsity_scores.csv")
df_misinfo_dist = pd.read_csv("data/dist_simulated.csv")

partydata = pd.DataFrame(
    {
        "party": ["Democrat", "Republican"],
        "value": [-1, 1],
        "label": ["", ""],
        "score": [0.0, 0.0],
    }
)

misinfodata = pd.DataFrame(
    {
        "exposure": ["low", "high"],
        "value": [0, 1],
        "label": ["", ""],
        "score": [0.5, 0.5],
    }
)

#%% app set up

st.set_page_config(page_title="Misinformation exposure")

# remove footer txt
# https://discuss.streamlit.io/t/remove-made-with-streamlit-from-bottom-of-app/1370/2
hide_streamlit_style = """

            """
st.markdown(hide_streamlit_style, unsafe_allow_html=True)

#%% main text

font = "rockwell"
st.markdown(
    f"
How much misinformation are you exposed to?
",
    unsafe_allow_html=True,
)

st.markdown(
    "
Misinformation exposure scores measure how much the politicians and public organizations you follow tend to lie (based on fact-checking their claims by PolitiFact). These scores go from 0 (none of the fact-checked claims by politicians and public figures you follow are false) to 1 (all of the fact-checked claims by politicians and public organizations you follow are false).
",
    unsafe_allow_html=True,
)

st.markdown(
    "
Partisanship scores measure how much you tend to follow politicians from the left versus right side of the political spectrum. These scores go from -1 (follow only left-leaning accounts) to 1 (follow only right-leaning accounts).",
    unsafe_allow_html=True,
)

st.markdown(
    "
You can also use our API to get the scores. Source code for this app is available here.</>",
    unsafe_allow_html=True,
)

st.markdown(
    "
Citation: Measuring exposure to misinformation from political elites on Twitter. Mosleh, M. & Rand, D.G., Nature Communications, 2022. See Tweet thread.
",
    unsafe_allow_html=True,
)

screen_name = st.text_input("**Enter your Twitter username/ID below to find out.**")
print(f"{screen_name}")
time.sleep(0.05)

components.html(
    """

""",
    height=0,
    width=0,
)

#%% results

if screen_name:
    if screen_name[0] == "@":
        screen_name = screen_name[1:]

    with st.spinner("Retrieving data..."):
        data = get_data(screen_name)

    if data.get("message") and data["message"].startswith("Cannot find information"):
        st.warning("User not found or user does not follow any elite accounts.")
    else:
        print(data)
        st.markdown(
            f"
Scores for {data['twitter_screen_name']} (ID: {data['twitter_user_id']})
",
            unsafe_allow_html=True,
        )

        st.markdown("##### ")

        percent_delta_misinfo, percent_delta_partisan = percent_delta(
            data["misinfo_exposure_score"], data["partisan_score"]
        )

        delta = None if np.isnan(percent_delta_misinfo) else f"{percent_delta_misinfo}%"
        delta = lower_or_higher(delta)
        columns = st.columns([1, 1])
        columns[0].metric(
            "Misinformation exposure",
            value=data["misinfo_exposure_score_weighted_numtweets"],
            help="Misinformation exposure score weighted by number of tweets (min/max: 0/1)",
            delta=delta,
            delta_color="off",
        )
        delta = (
            None if np.isnan(percent_delta_partisan) else f"{percent_delta_partisan}%"
        )
        delta = lower_or_higher(delta)
        columns[1].metric(
            "Partisanship",
            value=data["partisan_score"],
            delta=delta,
            help="Higher scores: more Republican (min/max: -1/1)",
            delta_color="off",
        )

        #%% figures

        st.markdown("# ")

        # misinfo exposure
        st.markdown(
            "
Misinformation exposure
",
            unsafe_allow_html=True,
        )

        if data["misinfo_exposure_score_weighted_numtweets"] is None:
            st.markdown(
                "
No misinformation exposure score is available for this user.

",
                unsafe_allow_html=True,
            )
        else:
            st.markdown(
                "
The vertical line is where you are in relation to others.
",
                unsafe_allow_html=True,
            )

        col1, col2, col3 = st.columns([0.6, 6.4, 1])
        axis_labels = "''"

        col1, col2, col3 = st.columns([1, 6, 1])
        axis_labels = "datum.label == 0 ? ['0.0','Low']: datum.label == 1.0 ? ['1.0','High']: datum.label"
        dens = (
            alt.Chart(df_misinfo_dist)
            .transform_density("value", as_=["value", "density"], extent=[0, 1])
            .mark_area(color="#d8dbe2", opacity=0.8)
            .encode(
                x=alt.X("value:Q", title="", axis=alt.Axis(labelExpr=axis_labels)),
                y=alt.Y("density:Q", title="", axis=alt.Axis(labels=False, tickSize=0)),
                tooltip=["value"],
            )
        )

        misinfodata["score"] = data["misinfo_exposure_score"]
        misinfodata["score_weighted"] = data[
            "misinfo_exposure_score_weighted_numtweets"
        ]
        rule = (
            alt.Chart(misinfodata)
            .mark_rule(color="#91e5f6", size=3)
            .encode(x="score_weighted:Q", tooltip=["score_weighted"])
        )

        if data["misinfo_exposure_score_weighted_numtweets"] is not None:
            plot_misinfoexpose = dens + rule
        else:
            plot_misinfoexpose = dens
        plot_misinfoexpose = (
            plot_misinfoexpose.configure_title(fontSize=13)
            .configure_axis(grid=False, domain=False)
            .configure_view(strokeWidth=0)
        )
        col2.altair_chart(plot_misinfoexpose, use_container_width=True)

        # partisanship
        st.markdown(
            "
Partisanship
",
            unsafe_allow_html=True,
        )

        if data["partisan_score"] is None:
            st.markdown(
                "
No partisanship score is available for this user.

",
                unsafe_allow_html=True,
            )

        st.markdown(
            "
"
            + img_to_html("img/dem_repub_small_nobg.png")
            + "
",
            unsafe_allow_html=True,
        )

        col1, col2, col3 = st.columns([1, 6, 1])
        partydata["score"] = data["partisan_score"]
        axis_labels = "datum.value == -1.0 ? ['-1.0','Democrat']: datum.value == 1.0 ? ['1.0','Republican']: datum.value == 0.0 ? ['0.0']: ''"

        bar = (
            alt.Chart(partydata)
            .mark_bar()
            .encode(
                x=alt.X(
                    "value",
                    title="",
                    axis=alt.Axis(labelExpr=axis_labels),
                ),
                y=alt.Y("label", title=""),
                color=alt.Color(
                    field="party",
                    scale=alt.Scale(range=["#36479d", "#bf1e2e"], interpolate="hsl"),
                    legend=None,
                ),
                tooltip=["party"],
            )
        )

        tick = (
            alt.Chart(partydata)
            .mark_tick(color="#91e5f6", thickness=5, size=34)
            .encode(x="score", y="label", tooltip=["score"])
        )
        plot_party = bar + tick if data["partisan_score"] is not None else bar
        plot_party.configure_title(fontSize=13)
        col2.altair_chart(plot_party, use_container_width=True)

        if int(data["num_following"]) > 1:
            st.markdown(
                f"The estimates above are based on these **{data['num_following']}** users **{data['twitter_screen_name'].lower()}** follows. Falsity scores for the elites are also shown. "
            )
        else:
            st.markdown(
                f"The estimates above are based on this user **{data['twitter_screen_name'].lower()}** follows. The elite's falsity score is also shown."
            )

        # show dataframe of elites and falsity scores
        cols = st.columns([1, 2, 1])
        df = pd.DataFrame(data["following"])
        df.columns = ["elite_account"]
        df = (
            pd.merge(df, df_falsity, on="elite_account", how="left")
            .sort_values("falsity_score", ascending=False)[
                ["elite_account", "falsity_score"]
            ]
            .reset_index(drop=True)
        )
        df.columns = ["Elite", "Falsity score"]
        df.index = df.index + 1
        # https://discuss.streamlit.io/t/how-to-format-float-values-to-2-decimal-place-in-a-dataframe-except-one-column-of-the-dataframe/3619/3
        cols[1].dataframe(
            df.style.format(subset=["Falsity score"], formatter="{:.3f}"),
            use_container_width=True,
        )

components.html(
    """

""",
)

# st.write(data)

#%%


class Solution:
    def minOperations(self, logs: List[str]) -> int:

        '''first i try to intialize empty list that is used store the elements of the stack and then it is used for to return the value of the lenght of this list first i try to use counter=0 but in this case if '../' occurs many times my couner value goes to negative and it does not do what it '''

        '''but know I fix the problem that appears in the first code'''
        stack=[]
        for i in logs:
            if '/' in i and '../' !=i and './' !=i:
                stack.append(i)
            elif '../'==i:
                if len(stack)>0:
                    stack.pop()
        return len(stack)


import random
import json

import nltk
import sklearn.feature_extraction.text

# from sklearn.feature_extraction.text import CountVectorizer
# from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

from telegram import Update, ForceReply
from telegram.ext import Updater, CommandHandler, CallbackContext, Filters, MessageHandler

with open("BOT_CONFIG.json", "r", encoding="utf8") as file:
    BOT_CONFIG = json.load(file)

def clean(text):
    clean_text = ''
    for char in text.lower():
        if char in "абвгдеёжзийклмнопрстуфхцчшщъыьэюя":
            clean_text = clean_text + char
    return clean_text

def compare(s1, s2):
    return nltk.edit_distance(s1, s2) / ((len(s1) + len(s2)) / 2) < 0.4

def get_intent(question):
    for intent in BOT_CONFIG['intents']:
        for example in BOT_CONFIG['intents'][intent]['examples']:
            if compare(clean(example), clean(question)):
                return intent
    return 'Не удалось определить интент'

# Обучение модели

X = []
y = []
for intent in BOT_CONFIG['intents']:
    X += BOT_CONFIG['intents'][intent]['examples']
    y += [intent] * len(BOT_CONFIG['intents'][intent]['examples'])

len(X), len(y)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
len(X_train), len(X_test)

vectorizer = sklearn.feature_extraction.text.CountVectorizer(analyzer='char', ngram_range=(1, 2), min_df=1)
vectorizer.fit(X_train)

X_train_vectorized = vectorizer.transform(X_train)
X_test_vectorized = vectorizer.transform(X_test)

classifier = RandomForestClassifier()
classifier.fit(X_train_vectorized, y_train)

def get_intent_by_ml(text):
    return classifier.predict(vectorizer.transform([text]))[0]

# Запуск Бота

def bot(ml, question):
    if ml:
        intent = get_intent_by_ml(question)
    else:
        intent = get_intent(question)

    if intent != 'Не удалось определить интент':
        return (random.choice(BOT_CONFIG['intents'][intent]['responses']))
    else:
        return (random.choice(BOT_CONFIG['falture_phrases']))

# Подключение Telegram

def start(update: Update, context: CallbackContext) -> None:
    """Send a message when the command /start is issued."""
    user = update.effective_user
    update.message.reply_markdown_v2(
        fr'Hi {user.mention_markdown_v2()}\!',
        reply_markup=ForceReply(selective=True),
    )

def help_command(update: Update, context: CallbackContext) -> None:
    """Send a message when the command /help is issued."""
    update.message.reply_text('Help!')

def echo(update: Update, context: CallbackContext) -> None:
    """Echo the user message."""
    ml = True
    update.message.reply_text(bot(ml, update.message.text))

def main() -> None:
    """Start the bot."""
    updater = Updater("")

    dispatcher = updater.dispatcher

    # on different commands - answer in Telegram
    dispatcher.add_handler(CommandHandler("start", start))
    dispatcher.add_handler(CommandHandler("help", help_command))

    # on non command i.e message - echo the message on Telegram
    dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, echo))

    # Start the Bot
    updater.start_polling()

    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()

if __name__ == '__main__':
    main()


from flask import Flask, render_template, request
import requests
import os

# Fetch the API key from environment variables
api_key = os.getenv('WEATHER_API_KEY')
# Create an instance of the Flask class
app = Flask(__name__)

# Function to fetch weather data from OpenWeatherMap API
def fetch_weather(location, key):
    try:
        response = requests.get(f"http://api.openweathermap.org/data/2.5/forecast?q={location}&appid={api_key}")
        response.raise_for_status()  # If the request failed, this will raise a HTTPError
        data = response.json()
        return data
    except requests.exceptions.HTTPError as errh:
        print ("Http Error:",errh)
    except requests.exceptions.ConnectionError as errc:
        print ("Error Connecting:",errc)
    except requests.exceptions.Timeout as errt:
        print ("Timeout Error:",errt)
    except requests.exceptions.RequestException as err:
        print ("Something went wrong",err)
        return None

# Route for the home page
@app.route('/')
def home():
    # Render the home page
    return render_template('home.html')

# Route for the weather page
@app.route('/weather', methods=['POST'])
def weather():
    # Get the location from the form data
    location = request.form.get('location')
    # Fetch the weather data
    weather_data = fetch_weather(location, api_key)
    if weather_data is None:
        return render_template('error.html', error="Could not fetch weather data. Please try again.")
    forecast = []
    # Prepare a list of forecast data
    for item in weather_data.get('list', []):
        forecast.append({
            'time': item['dt_txt'],
            'description': item['weather'][0]['description'],
            'icon': f"http://openweathermap.org/img/wn/{item['weather'][0]['icon']}.png"
        })
    # Render the weather page with the location and forecast data
    return render_template('weather.html', location=location, forecast=forecast)

# Start the Flask development server
if __name__ == '__main__':
    app.run(debug=True)


import nuke
import os
import inspect
'''
This will add all items in subdirectories to their respective named menu items.
Eg. make a folder in gizmos called 'Fire' and in Nuke there will be a menu called 'Fire' with your gizmos in it
'''
curInitFile = inspect.getfile(inspect.currentframe()) # get location of current py file
fileDir = os.path.dirname(curInitFile) # get the dir name of that file

for (path, dirs, files) in os.walk('%s' % (fileDir)): # walk through the dir tree for things
    categories = path.replace(fileDir,'').replace('\\','/').title() # clear out the base dir and replace all \ with / and create a list of categories
    categories = categories[1:] # this is because there is a preceeding / in the string
    for curFile in files:
        if os.path.splitext(curFile)[1].lower() == '.gizmo': #look for gizmos
            nodeName = os.path.splitext(curFile)[0] #get the name of the node
            nuke.menu('Nodes').addCommand('%s/%s' % (categories, nodeName), 'nuke.createNode("%s")' % (nodeName) ) # add to menu!


# -*- coding: utf-8 -*-
"""
Created on Tue Feb 25 17:33:40 2020

@author: ymamo
"""

import pickle

infile = open("data.pkl", 'rb')
new_dict = pickle.load(infile)
infile.close()

print(new_dict)


# -*- coding: utf-8 -*-
"""
Created on Sat Sep 14 11:01:03 2019

@author: nimitha jammula
"""

import ID3
import sys
import Accuracy
import csv
import pandas as pd

def main():

    train_file=str(sys.argv[1]) ;
    attribute_names_adder(train_file)
    validation_file = sys.argv[2]
    attribute_names_adder(validation_file)
    test_file= sys.argv[3]
    attribute_names_adder(test_file)
    yesno = str(sys.argv[4])
    heu = str(sys.argv[5])
    pru = str(sys.argv[6])
    L = int(sys.argv[7])
    K = int(sys.argv[8])
    decisionTree = ID3.DTree(train_file,heu)
    if yesno == "yes":
        print('Decision Tree before Pruning:')
        print(decisionTree)

    accuracy = Accuracy.Accuracy(test_file)
    accuracy.calculateAccuracy(decisionTree.root)
    print('Accuracy before Pruning:')
    accuracy.displayAccuracy()

    if(pru == 'r'):
        decisionTree.pruneTree(L,K,validation_file)
    elif(pru == 'n'):
        print('No pruning')
        return
    if yesno == "yes":
        print('Decision Tree after Pruning :')
        print(decisionTree)
    accuracy.calculateAccuracy(decisionTree.root)
    print('Accuracy after Pruning:')
    accuracy.displayAccuracy()

def csvParser(self, filename):
    self.data = []
    with open(filename,'rt') as csvfile:
        csvreader = csv.reader(csvfile, delimiter = ',')
        count = 0
        for row in csvreader:
            if count == 0:
                self.attributeNames = row[:-1]
            else:
                self.data.append([int(i) for i in row])
            count += 1

    self.attributes = range(len(self.attributeNames))
    self.trainingValues = range(len(self.data))
    self.Class = [row[-1] for row in self.data]
    return self

def attribute_names_adder(filePath):
   data = pd.read_csv(filePath,sep = ',',header = 0)
   #print('Data Set length :',len(data))
   #print('Data Set shape :',data.shape)
   for i, (ca,cc) in zip(range(len(data.columns)), data.iteritems()):
      name = 'X'+str(i)
      data.rename(columns={ca : name}, inplace=True)
   data.rename(columns={ data.columns[len(data.columns)-1]: "Class" }, inplace = True)
   data.to_csv(filePath, index=False)

if __name__ == '__main__':
    main()


"""
This module defines a number of classes and helper functions to define and work
with commands that operate hardware devices. The goal is to be able to define /
create commands transparently from a YAML file without having to write (too much)
code.

A few definitions for the classes defined in this module:

**command**

a string that is sent to a device over an interface like TCP/IP or USB. This
string is generated by the get_cmd_string() method of the Command class.

The string contains format like syntax that looks like an f-string, but is
interpreted differently. See further: How to format device command strings.

**Command**

the base class for commands. This class contains the definition of the command
and provides methods to parse and check arguments. The Command can be 'called'
or 'executed' in which case a number of actions are performed based on the
provided arguments.

**CommandExecution**

this class contains all the information needed to execute a command, without
actually executing it. A CommandExecution contains the command definition and
the parameters for the execution. It is mainly served as a communication
mechanism to the control servers, i.e. the client side (Proxy) defines a
command execution and the server then executes the command.

**CommandError**

a catch-all exception for unrecoverable errors in this module

**InvalidArgumentsError**

a CommandError raised when the arguments provided are themselve invalid
or if the number of arguments is not matching expectations

The basic interface is:

    cmd = Command(name     = <command name>,
                  cmd      = <command string>,
                  response = <callable to retreive a response>,
                  wait     = <callable to wait a specific time/delay>)

where:

* name: a name for the command, this is just needed for reporting, not used in commanding
* cmd: the command string to send or execute, see further for details
* response: send a second command to read or get a response on the 'cmd' sent
* wait: a function object that will wait for a specific duration,
  e.g. ```partial(time.sleep, 10)```

How to format device command strings

The ``cmd`` argument is a string that contains placeholders (replacement fields)
for future arguments that will be passed when calling the Command. The replacement
fields are marked with curly braces and are mandatory. When a name is provided
in the curly braces, the argument shall be provided as a keyword argument, otherwise
a positional argument is expected. In the current implementation the ``cmd``
can only contain either positional arguments or keyword argument, not a mix of both.

The replacement fields may also have a format specifier to specify a precise format
for that field.

**Examples**

    moveAbsolute = Command(
        name = "moveAbsolute",
        cmd  = "&2 Q70=0 Q71={tx:.6f} Q72={ty:.6f} Q73={tz:.6f} "
               "Q74={rx:.6f} Q75={ry:.6f} Q76={rz:.6f} Q20=11"
    )

    response = moveAbsolute(1, 1, 1, 0, 0, 20)
    response = moveAbsolute(tx=1, ty=1, tz=1, rx=0, ry=0, rz=20)

Questions

Do we need additional hooks into this commanding?

* add a meaning to the check, what is it and what is it used for?
* add a output processor possibility. A callback function that will process the
  output value before returning it by the __call__.
* provide an execute method for the CommandExecution that executes the command
  with the saved parameters
"""
import functools
import inspect
import logging
import re
from collections import namedtuple
from typing import Callable

from egse.control import Success
from egse.exceptions import Error

logger = logging.getLogger(__name__)

def stringify_function_call(function_info: dict) -> str:
    def quote(value):
        return f'"{value}"' if isinstance(value, str) else value

    description = function_info.get("description")
    if description:
        return description

    result = ""

    name = function_info.get("func_name")
    args = function_info.get("args")
    kwargs = function_info.get("kwargs")

    if name:
        result += name
    else:
        result += "unknown_function"

    result += "("

    if args:
        result += f"{args}"[1:-1]

    if kwargs:
        result += ", " if args else ""
        result += ", ".join([f"{k}={quote(v)}" for k, v in kwargs.items()])

    result += ")"

    return result

def dry_run(func: Callable) -> Callable:
    """This decorator prepares the function to handle a dry run.

    A dry run is used to check the logic of an instrument commanding script without
    actually executing the instrument commands. The commands are instead added to the
    command sequence in the global state.

    Args:
        func: the function that needs to be executed

    Returns:
        A wrapper around the given function.
    """

    @functools.wraps(func)
    def func_wrapper(self, *args, **kwargs):

        from egse.state import GlobalState  # prevent circular import

        if GlobalState.dry_run:
            if callable(func) and func.__name__ == "client_call":
                # This client_call function takes an additional argument which is the Proxy.
                # the Proxy is not part of the CommandExecution signature and shall be removed
                # FIXME: do we introduce a memory leak here by adding 'self' to this GlobalState?
                args = args[1:]
                try:
                    self.validate_arguments(*args, **kwargs)
                except CommandError as e_ce:
                    GlobalState.add_command(InvalidCommandExecution(e_ce, self, *args, **kwargs))
                else:
                    GlobalState.add_command(CommandExecution(self, *args, **kwargs))
            else:
                FunctionExecution = namedtuple("FunctionExecution", ["name", "args", "kwargs"])
                GlobalState.add_command(FunctionExecution(func.__name__, args, kwargs))
            return Success(
                "Command execution appended to command sequence, function not executed in dry_run."
            )
        else:
            return func(self, *args, **kwargs)

    return func_wrapper

def parse_format_string(fstring):
    """
    Parse and decode the format string.
    """
    # Remove occurrences of {{ }} from the fstring as they are not replacement fields
    # and will occur after formatting as single braces.

    fstring = re.sub(r"{{.*}}", lambda x: "_", fstring)

    # logger.debug(f"fstring = '{fstring}', replaced {{{{.*}}}} with _")

    parts = re.findall(r"\{(.*?)\}", fstring)

    # logger.debug(f"Parts: {parts!r}, n={len(parts)}")

    tot_n_args = len(parts)
    n_args = 0
    n_kwargs = 0
    keys = []

    for part in parts:
        result = re.split(r"(:)", part)
        if result[0] == "":
            n_args += 1
        else:
            n_kwargs += 1
            keys.append(result[0])

    # If this assertion fails, there is a flaw in the algorithm above
    assert tot_n_args == n_args + n_kwargs, (
        f"Total number of arguments ({tot_n_args}) doesn't match # args ({n_args}) + "
        f"# kwargs ({n_kwargs})."
    )

    if n_args > 0 and n_kwargs > 0:
        raise InvalidArgumentsError("Mixing of positional and keyword arguments is not available.")

    return tot_n_args, n_args, n_kwargs, keys

class CommandError(Error):
    """A Command Exception as a base class for this module."""

class InvalidArgumentsError(CommandError):
    """The arguments provided are invalid"""

class CommandExecution:
    """
    This class contains all the information that is needed to execute a command
    with a set of parameters/arguments. The command is however not executed
    automatically. That is the responsibility of the caller to actually execute
    the command with the given parameters.

    Developer info

    you can see this as a partial (functools) which defines the command and
    its arguments, but doesn't execute until explicitly called. You can execute
    the command by calling the `cmd` with the given arguments:

       ```
       ce = CommandExecution(cmd, 20.0)
       ...
       response = ce.run()
       ```
    """

    def __init__(self, cmd, *args, **kwargs):
        self._cmd = cmd
        self._args = args
        self._kwargs = kwargs

    def get_name(self):
        return self._cmd.get_name()

    def get_cmd(self):
        return self._cmd

    def get_args(self):
        return self._args

    def get_kwargs(self):
        return self._kwargs

    def run(self):
        return self._cmd(*self._args, **self._kwargs)

    def __str__(self):
        msg = f"[{self.get_cmd().__class__.__name__}] {self.get_name()}("
        for arg in self.get_args():
            msg += f"{arg}, "
        for k, v in self.get_kwargs().items():
            msg += f"{k}={v}, "
        if msg.endswith(", "):
            msg = msg[:-2]
        msg += ")"
        return msg

class InvalidCommandExecution(CommandExecution):
    """A invalid command execution."""

    def __init__(self, exc, cmd, *args, **kwargs):
        """
        Args:
            exc: the Exception that was raised and describes the problem
            cmd: the Command object
            *args: the positional arguments that were given
            **kwargs: the keyword arguments that were given
        """
        super().__init__(cmd, *args, **kwargs)
        self._exc = exc

    def run(self):
        raise InvalidArgumentsError(
            f"The command {self.get_name()} can not be executed. Reason: {self._exc}"
        )

    def __str__(self):
        msg = super().__str__()
        msg += f" [ERROR: {self._exc}]"
        return msg

class WaitCommand:
    def __init__(self, command, condition):
        self._command = command
        self._condition = condition

    def __call__(self):

        # .. todo:: do we need a timeout possibility here?

        while True:
            return_code = self._command()
            if self._condition(return_code):
                break

        return 0

class Command:
    """
    A Command is basically a string that is send to a device and for which the
    device returns a response.

    The command string can contain placeholders that will be filled when the
    command is 'called'.

    The arguments that are given will be filled into the formatted string.
    Arguments can be positional or keyword arguments, not both.
    """

    def __init__(
            self, name, cmd, response=None, wait=None, check=None, description=None,
            device_method=None
    ):
        self._name = name
        self._cmd = cmd
        self._response = response
        self._wait = wait
        self._check = check
        self._description = description
        self._device_method = device_method

        tot_n_args, n_args, n_kwargs, keys = parse_format_string(cmd)

        self._tot_n_args = tot_n_args
        self._n_args = n_args
        self._n_kwargs = n_kwargs
        self._keys = keys

        self.__doc__ = self.doc_string()

    def doc_string(self):
        msg = f"usage: {self._name}(nargs={self._tot_n_args}, keys={self._keys})\n"
        msg += "       args & kwargs can be mixed (limited)"

        if self._description is not None:
            msg += "\n"
            msg += f"{self._description}\n"

        return msg

    def validate_arguments(self, *args, **kwargs):

        # Special case for commands with *args or **kwargs, we don't validate

        if self._cmd in ("*", "**"):
            return

        nargs = len(args)
        nkwargs = len(kwargs)

        if self._tot_n_args != nargs + nkwargs:
            raise InvalidArgumentsError(
                f"Expected {self._tot_n_args} arguments for command {self._name}, "
                f"got {nargs + nkwargs} arguments."
            )

        if self._tot_n_args == 0:
            pass
        elif nargs and nargs == self._n_args:
            pass
        elif nkwargs and nkwargs == self._n_kwargs:
            pass
        elif nargs == self._n_kwargs and nkwargs == 0:
            pass
        else:
            raise InvalidArgumentsError(
                f"Expected {self._n_args} positional arguments and {self._n_kwargs} "
                f"keyword arguments for command {self._name}, got {nargs} positional "
                f"and {nkwargs} keyword arguments instead."
            )

    def execute(self, cmd):
        return 0

    def get_name(self):
        return self._name

    def needs_argument(self, name):
        if name in self._keys:
            return True
        return False

    def __repr__(self):
        name = self._name if hasattr(self, "_name") else None
        return f"<{self.__class__.__name__}({name})>"

    def get_device_method(self):
        return self._device_method

    def get_device_method_name(self):
        return self._device_method.__name__

    def get_command_execution(self, *args, **kwargs):

        return CommandExecution(self, *args, **kwargs)

    def __call__(self, *args, **kwargs):
        cmd_string = self.get_cmd_string(*args, **kwargs)

        # Now execute the cmd_string

        response = self.execute(cmd_string)

        if self._wait is not None:
            self._wait()

        if self._response is not None:
            response = self._response()

        if self._check is not None:
            response = self._check(response)

        return response

    def get_raw_cmd_string(self):
        return self._cmd

    def get_cmd_string(self, *args, **kwargs):
        nargs = len(args)
        nkwargs = len(kwargs)

        if self._tot_n_args != nargs + nkwargs:
            raise CommandError(
                f"Expected {self._tot_n_args} arguments for command {self._name}, "
                f"got {nargs + nkwargs} arguments."
            )

        if self._tot_n_args == 0:
            cmd_string = self._cmd or self._name
        elif nargs and nargs == self._n_args:
            cmd_string = self._create_command_string_from_args(*args)
        elif nkwargs and nkwargs == self._n_kwargs:
            cmd_string = self._create_command_string_from_kwargs(**kwargs)
        elif nargs == self._n_kwargs and nkwargs == 0:
            cmd_string = self._create_command_string_from_args_with_kw(*args)
        else:
            raise CommandError(
                f"Expected {self._n_args} positional arguments and {self._n_kwargs} "
                f"keyword arguments for command {self._name}, got {nargs} positional "
                f"and {nkwargs} keyword arguments instead."
            )

        return cmd_string

    def _create_command_string_from_args(self, *args):
        full_command = self._cmd.format(*args)
        return full_command

    def _create_command_string_from_args_with_kw(self, *args):
        full_command = self._cmd.format(**{k: v for k, v in zip(self._keys, args)})
        return full_command

    def _create_command_string_from_kwargs(self, **kwargs):
        full_command = self._cmd.format(**kwargs)
        return full_command

class ClientServerCommand(Command):
    @dry_run
    def client_call(self, other, *args, **kwargs):
        """
        This method is called at the client side. It is used by the Proxy
        as a generic command to send a command execution to the server.

        Args:
            other: a sub-class of the Proxy class
            args: arguments that will be passed on to this command when executed
            kwargs: keyword arguments that will be passed on to this command when executed

        Returns:
            the response that is returned by calling the command (at the server side).
        """

        try:
            self.validate_arguments(*args, **kwargs)
        except CommandError as e_ce:
            logger.error(str(e_ce))
            return None

        ce = CommandExecution(self, *args, **kwargs)
        rc = other.send(ce)

        # FIXME:
        #   not sure if I should do this, the Success/Failure returns from the CS should be
        #   re-designed. I have put this here for the following reason: when requesting an obsid
        #   from the CM_CS we don't want a Success message back, but we need the number!

        # if isinstance(rc, Success):
        #     logger.info(rc)
        #     rc = rc.return_code

        return rc

    def server_call(self, other, *args, **kwargs):
        """
        This method is called at the server side. It is used by the CommandProtocol class in the
        ``execute`` method.

        Args:
            other: a sub-class of the CommandProtocol
            args: arguments are passed on to the response method
            kwargs: keyword arguments are passed on to the response method

        Returns:
            0 on success and -1 on failure.
        """

        if self._response is None:
            logger.warning(f"No response defined for {other} command {self.get_name()}")
            return -1

        # Note that `_response` is of type 'function' because it was loaded from
        # a class object and therefore not bound to a class instance. The reason
        # that we could not use a bound method for `_response` is that we pass the
        # command objects back and forth from the control server to the proxy and
        # the class instances are not known at the other side.

        if self._response.__name__ == "handle_device_method":

            # call the handle_device_method of the Protocol sub-class

            logger.log(0,
                       f"Executing Command {self._response.__name__}({other!r}, "
                       f"{self!r}, {args}, {kwargs})")

            rc = self._response(other, self, *args, **kwargs)
        else:
            logger.log(0,
                       f"Executing Command {self._response.__name__}({other!r}, {args}, {kwargs})")

            rc = self._response(other, *args, **kwargs)

        logger.log(0, f"Response is {rc}.")

        return 0

def get_method(parent_obj, method_name: str):
    """
    Returns a bound method from a given class instance.

    Args:
        parent_obj: the class instance that provides the method
        method_name: name of the method that is requested

    Returns:
        the method [type: method].

    .. note::
        The method returned is an bound class instance method and therefore
        this method *does not* expects as its first argument the class
        instance, i.e. self, when you call this as a function.

    """
    if method_name is None or method_name == "None":
        return None

    if hasattr(parent_obj, method_name):
        method = getattr(parent_obj, method_name)
        if inspect.ismethod(method):
            return method
        logger.warning(f"{method_name} is not a method, type={type(method)}")
    else:
        logger.warning(f"{parent_obj!r} has no method called {method_name}")

    return None

def get_function(parent_class, method_name: str):
    """
    Returns a function (unbound method) from a given class.

    Args:
        parent_class: the class that provides the method
        method_name: name of the method that is requested

    Returns:
        the method [type: function].

    .. note::
        The function returned is an unbound class instance method and
        therefore this function expects as its first argument the class
        instance, i.e. self, when you call it as a function.

    """
    if method_name is None or method_name == "None":
        return None

    if hasattr(parent_class, method_name):
        func = getattr(parent_class, method_name)
        if inspect.isfunction(func):
            return func
        logger.warning(f"{method_name} is not a function, type={type(func)}")
    else:
        logger.warning(
            f"{parent_class.__module__}.{parent_class.__name__} has no method called {method_name}"
        )

    return None

def load_commands(protocol_class, command_settings, command_class, device_class):
    """
    Loads the command definitions from the given ``command_settings`` and builds an internal
    dictionary containing the command names as keys and the corresponding ``Command`` class objects
    as values.

    The ``command_settings`` is usually loaded from a YAML configuration file containing the
    command definitions for the device.

    Args:
        protocol_class: the CommandProtocol or a sub-class
        command_settings: a dictionary containing the command definitions for this device
        command_class: the type of command to create, a subclass of Command
        device_class: the type of the base device class from which the methods are loaded
    """
    commands = {}

    for name in command_settings:
        command_settings_name = command_settings[name]
        if "cmd" in command_settings_name:
            cmd = command_settings_name["cmd"]
        else:
            cmd = ""

        if "description" in command_settings_name:
            description = command_settings_name["description"]
        else:
            description = None

        # The response field is the name of a function from the CommandProtocol class
        # or a sub-class. This function shall send a response back to the client (Proxy). That's
        # why this field is called response.
        # By convention we like that this method name would start with `handle_` so that we can
        # make a distinction between response commands and normal methods in Protocol. Remember
        # that response methods should send a reply back to the client (which will be waiting for
        # it..). If no response field is given, then the `handle_device_method` will be called.

        if "response" in command_settings_name:
            response_method = get_function(protocol_class, command_settings_name["response"])
        else:
            response_method = get_function(protocol_class, "handle_device_method")
            response_method = None

        # The device_method field is used in the `handle_device_method` to call the method on the
        # device class. That is the class that implements the DeviceInterface and is usually called
        # a Controller or a Simulator.
        #
        # If no device_name field is given, the name from the command_settings is used.

        if "device_method" in command_settings_name:
            device_method_name = command_settings_name["device_method"]
        else:
            device_method_name = name

        # check if the device_method exists in the device base class

        if device_method_name == "None":
            device_method = None
        else:
            device_method = get_function(device_class, device_method_name)

        logger.debug(
            f"Creating {command_class.__module__}.{command_class.__name__}(name='{name}', "
            f"cmd='{cmd}', response={response_method}, device_method={device_method})"
        )

        commands[name] = command_class(
            name=name,
            cmd=cmd,
            response=response_method,
            description=description,
            device_method=device_method,
        )

    return commands


from setuptools import setup, find_packages

with open("README") as file:
    long_description = file.read()

setup(
    name = "gscripts",
    long_description = long_description,
    version = "0.1.1",
    packages = find_packages(),

    install_requires = ['setuptools',
                        'pysam >= 0.6',
                        'numpy >= 1.5.1 ',
                        'scipy >= 0.11.0',
                        'matplotlib >= 1.1.0',
                        'pybedtools >= 0.5',
                        'scikit-learn >= 0.13.0',
                        ],

    setup_requires = ["setuptools_git >= 0.3",],
    scripts=['rnaseq/count_tags.py',
             'general/calculate_NRF.py',
             'general/calculate_NRF.py',
             'general/make_trackhubs.py',
             'general/count_aligned_from_sam.py',
             'general/negBedGraph.py',
             'clipseq/perform_idr.py',
             'clipseq/run_piranha.py'],

    #metadata for upload to PyPI
    author = "Gabriel Pratt",
    author_email = "gpratt@ucsd.edu",
    description = "A set of scripts for analysis of high throughput data",
    license = "GPL2",
    keywords = "bioinformatics",
    url = "https://github.com/gpratt",

    #Other stuff I feel like including here
    include_package_data = True,
    zip_safe = False #True I think
)


"""
Main Menu for Quiddler - called on application start.
"""
import arcade
import two_player
import single_player
import edit_player_names
import highscores
import instructions
from constants import BACKGROUND_IMAGE_WIDTH, CONTINUE, EXIT, MAIN_MENU_MUSIC, EXIT_PRESSED, CONTINUE_PRESSED, \
    HIGHSCORES_BUTTON, HIGHSCORES_BUTTON_PRESSED, EDIT_NAMES, EDIT_NAMES_PRESSED

class GameMenu(arcade.View):

    def __init__(self, player_1, player_2):
        super().__init__()
        self.window.set_fullscreen(True)
        self.screen_width, self.screen_height = self.window.get_size()
        self.scale = min(self.screen_width / 1920, self.screen_height / 1080)
        self.player_1 = player_1
        self.player_2 = player_2

        self.background = arcade.Sprite(filename="images/quiddler_main_menu_background(2).png",
                                        scale=self.screen_width / BACKGROUND_IMAGE_WIDTH)
        self.background.position = self.screen_width / 2, self.screen_height / 2

        self.button_list = arcade.SpriteList()

        self.continue_button = arcade.Sprite(CONTINUE, scale=self.scale)
        self.continue_button.position = self.screen_width / 2, self.screen_height / 2 + 100 * self.scale
        self.button_list.append(self.continue_button)
        self.solo_half_game_button = arcade.Sprite("images/half_game_button.png", scale=self.scale)
        self.solo_half_game_button.position = self.screen_width / 2 - 100 * self.scale, self.screen_height / 2
        self.button_list.append(self.solo_half_game_button)
        self.solo_full_game_button = arcade.Sprite("images/full_game_button.png", scale=self.scale)
        self.solo_full_game_button.position = self.screen_width / 2 + 100 * self.scale, self.screen_height / 2
        self.button_list.append(self.solo_full_game_button)
        self.half_game_button = arcade.Sprite("images/half_game_button.png", scale=self.scale)
        self.half_game_button.position = self.screen_width / 2 - 100 * self.scale, self.screen_height / 2 - 100 * self.scale
        self.button_list.append(self.half_game_button)
        self.full_game_button = arcade.Sprite("images/full_game_button.png", scale=self.scale)
        self.full_game_button.position = self.screen_width / 2 + 100 * self.scale, self.screen_height / 2 - 100 * self.scale
        self.button_list.append(self.full_game_button)
        self.edit_names_button = arcade.Sprite(EDIT_NAMES, scale=self.scale)
        self.edit_names_button.position = self.screen_width / 2, self.screen_height / 2 - 200 * self.scale
        self.button_list.append(self.edit_names_button)
        self.highscores_button = arcade.Sprite(HIGHSCORES_BUTTON, scale=self.scale)
        self.highscores_button.position = self.screen_width / 2, self.screen_height / 2 - 300 * self.scale
        self.button_list.append(self.highscores_button)
        self.instructions_button = arcade.Sprite("images/instructions_button.png", scale=self.scale)
        self.instructions_button.position = self.screen_width / 2, self.screen_height / 2 - 400 * self.scale
        self.button_list.append(self.instructions_button)
        self.exit_button = arcade.Sprite(EXIT, scale=self.scale)
        self.exit_button.position = self.screen_width / 2, self.screen_height / 2 - 500 * self.scale
        self.button_list.append(self.exit_button)

        self.buttons_pressed = []

        self.main_menu_music = MAIN_MENU_MUSIC
        self.sound_player = None
        self.sound_player = self.main_menu_music.play(volume=.50, loop=True)

    def on_show(self):
        """ This is run once when we switch to this view """
        self.background.draw()
        self.button_list.draw()

    def on_draw(self):
        """ Draw this view """
        arcade.start_render()
        self.background.draw()
        self.button_list.draw()
        arcade.draw_text(
            "Solo:",
            self.screen_width / 2 - 225 * self.scale,
            self.screen_height / 2,
            arcade.color.WHITE,
            50,
            anchor_x='right',
            anchor_y='center'
        )
        arcade.draw_text(
            "2-P:",
            self.screen_width / 2 - 225 * self.scale,
            self.screen_height / 2 - 100 * self.scale,
            arcade.color.WHITE,
            50,
            anchor_x='right',
            anchor_y='center'
        )

    # def on_update(self, delta_time: float):
        # if self.main_menu_music.is_complete(self.sound_player):
        #     self.main_menu_music.play(volume=.25)

    def on_key_release(self, symbol: int, modifiers: int):
        if symbol == arcade.key.F10:
            arcade.close_window()
        elif symbol == arcade.key.F9:
            game_view = single_player.QuiddlerSolo(rnd_number=8, player_1=self.player_1)
            game_view.setup()
            self.main_menu_music.stop(self.sound_player)
            self.window.show_view(game_view)

    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int):
        if button == arcade.MOUSE_BUTTON_LEFT:
            self.buttons_pressed = arcade.get_sprites_at_point((x, y,), self.button_list)

            if self.half_game_button in self.buttons_pressed:
                self.half_game_button.texture = arcade.load_texture("images/half_game_button_pressed.png")
            elif self.solo_half_game_button in self.buttons_pressed:
                self.solo_half_game_button.texture = arcade.load_texture("images/half_game_button_pressed.png")
            elif self.solo_full_game_button in self.buttons_pressed:
                self.solo_full_game_button.texture = arcade.load_texture("images/full_game_button_pressed.png")
            elif self.full_game_button in self.buttons_pressed:
                self.full_game_button.texture = arcade.load_texture("images/full_game_button_pressed.png")
            elif self.instructions_button in self.buttons_pressed:
                self.instructions_button.texture = arcade.load_texture("images/instructions_button_pressed.png")
            elif self.exit_button in self.buttons_pressed:
                self.exit_button.texture = arcade.load_texture(EXIT_PRESSED)
            elif self.continue_button in self.buttons_pressed:
                self.continue_button.texture = arcade.load_texture(CONTINUE_PRESSED)
            elif self.edit_names_button in self.buttons_pressed:
                self.edit_names_button.texture = arcade.load_texture(EDIT_NAMES_PRESSED)
            elif self.highscores_button in self.buttons_pressed:
                self.highscores_button.texture = arcade.load_texture(HIGHSCORES_BUTTON_PRESSED)

    def on_mouse_release(self, x: float, y: float, button: int,
                         modifiers: int):

        button = arcade.get_sprites_at_point((x, y), self.button_list)

        if button:
            if self.half_game_button in self.buttons_pressed:
                if self.half_game_button == button[0]:

                    game_view = two_player.Quiddler(rnd_number=8,
                                                    player_1=self.player_1,
                                                    player_2=self.player_2)
                    game_view.setup()
                    self.main_menu_music.stop(self.sound_player)
                    self.window.show_view(game_view)

            elif self.full_game_button in self.buttons_pressed:
                if self.full_game_button == button[0]:
                    game_view = two_player.Quiddler(rnd_number=16,
                                                    player_1=self.player_1,
                                                    player_2=self.player_2)
                    game_view.setup()
                    self.main_menu_music.stop(self.sound_player)
                    self.window.show_view(game_view)

            elif self.solo_half_game_button in self.buttons_pressed:
                if self.solo_half_game_button == button[0]:
                    game_view = single_player.QuiddlerSolo(rnd_number=8, player_1=self.player_1)
                    game_view.setup()
                    self.main_menu_music.stop(self.sound_player)
                    self.window.show_view(game_view)

            elif self.solo_full_game_button in self.buttons_pressed:
                if self.solo_full_game_button == button[0]:
                    game_view = single_player.QuiddlerSolo(rnd_number=16, player_1=self.player_1)
                    game_view.setup()
                    self.main_menu_music.stop(self.sound_player)
                    self.window.show_view(game_view)

            elif self.instructions_button in self.buttons_pressed:
                if self.instructions_button == button[0]:
                    game_view = instructions.InstructionsMenu1(game_view=self)
                    game_view.setup()

                    self.window.show_view(game_view)

            elif self.exit_button in self.buttons_pressed:
                if self.exit_button == button[0]:
                    arcade.close_window()

            elif self.continue_button in self.buttons_pressed:
                if self.continue_button == button[0]:
                    game_view = two_player.Quiddler(rnd_number=8,
                                                    player_1=self.player_1,
                                                    player_2=self.player_2)
                    game_view.setup()
                    game_view.continue_game()
                    self.main_menu_music.stop(self.sound_player)
                    self.window.show_view(game_view)

            elif self.edit_names_button in self.buttons_pressed:
                if self.edit_names_button == button[0]:
                    game_view = edit_player_names.EditPlayerNames(player_1=self.player_1,
                                                                  player_2=self.player_2,
                                                                  game_view=self)
                    self.window.show_view(game_view)

            elif self.highscores_button in self.buttons_pressed:
                if self.highscores_button == button[0]:
                    game_view = highscores.HighScores(game_view=self)
                    self.window.show_view(game_view)

        self.highscores_button.texture = arcade.load_texture(HIGHSCORES_BUTTON)
        self.edit_names_button.texture = arcade.load_texture(EDIT_NAMES)
        self.half_game_button.texture = arcade.load_texture("images/half_game_button.png")
        self.full_game_button.texture = arcade.load_texture("images/full_game_button.png")
        self.instructions_button.texture = arcade.load_texture("images/instructions_button.png")
        self.exit_button.texture = arcade.load_texture(EXIT)
        self.buttons_pressed = []


#!/usr/bin/python3
"""
define class Rectangle
"""
from models.base import Base

class Rectangle(Base):
    """class Rectangle inherits from Base """

    def __init__(self, width, height, x=0, y=0, id=None):
        """class constructor"""

        if type(width) is not int:
            raise TypeError("width must be an integer")
        elif width <= 0:
            raise ValueError("width must be > 0")
        self.__width = width
        if type(height) is not int:
            raise TypeError("height must be an integer")
        elif height <= 0:
            raise ValueError("height must be > 0")
        self.__height = height
        if type(x) is not int:
            raise TypeError("x must be an integer")
        elif x < 0:
            raise ValueError("x must be >= 0")
        self.__x = x
        if type(y) is not int:
            raise TypeError("y must be an integer")
        elif y < 0:
            raise ValueError("y must be >= 0")
        self.__y = y
        super().__init__(id)

    @property
    def width(self):
        """return width"""
        return self.__width

    @width.setter
    def width(self, width):
        """ set width"""
        if type(width) is not int:
            raise TypeError("width must be an integer")
        elif width <= 0:
            raise ValueError("width must be > 0")
        self.__width = width

    @property
    def height(self):
        """ return height"""
        return self.__height

    @height.setter
    def height(self, height):
        """set height"""
        if type(height) is not int:
            raise TypeError("height must be an integer")
        elif height <= 0:
            raise ValueError("height must be > 0")
        self.__height = height

    @property
    def x(self):
        """return x"""
        return self.__x

    @x.setter
    def x(self, x):
        """set x"""
        if type(x) is not int:
            raise TypeError("x must be an integer")
        elif x < 0:
            raise ValueError("x must be >= 0")
        self.__x = x

    @property
    def y(self):
        """return y"""
        return self.__y

    @y.setter
    def y(self, y):
        """set y"""
        if type(y) is not int:
            raise TypeError("y must be an integer")
        elif y < 0:
            raise ValueError("y must be >= 0")
        self.__y = y

    def area(self):
        """public method that returns the area"""

        return self.__width * self.__height

    def display(self):
        """prints in stdout the Rectangle
        instance with the character #"""
        for _ in range(self.__y):
            print("")
        for _ in range(self.__height):
            for _ in range(self.__x):
                print(" ", end="")
            for _ in range(self.__width):
                print("#", end="")
            print()

    def __str__(self):
        return f"[Rectangle] ({self.id}) {self.__x}/{self.__y} - \
{self.__width}/{self.__height}"

    def update(self, *args, **kwargs):
        """assigns an argument to each attribute"""

        if len(args) > 0:
            self.id = args[0]
        if len(args) > 1:
            self.__width = args[1]
        if len(args) > 2:
            self.__height = args[2]
        if len(args) > 3:
            self.__x = args[3]
        if len(args) > 4:
            self.__y = args[4]
        if kwargs:
            for key, value in kwargs.items():
                setattr(self, key, value)

    def to_dictionary(self):
        """return a dictionary representation of a Rectangle"""

        return {"id": self.id, "width": self.width,
                "height": self.height, "x": self.x, "y": self.y}


# 6) Calcule o tempo de uma viagem de carro.
# Pergunte a distância a percorrer e a velocidade média
# esperada para a viagem.

print('Calculo de tempo de viagem')

distancia = float(input('Informe a distancia em km: '))
velocidade_media = float(input('Informe a velocidade media (km/h): '))

tempo_viagem = distancia / velocidade_media

print(f'O tempo aproximado da viagem sera de: {tempo_viagem} horas')


string = 'some string'

len(string)
#print(len(string))

string[0]
#print(string[0])

string[-1]
#print(string[-1])

string[3:6]
#print(string[3:6])

for x in string:
	print(x)

string[2]='2'
#ошибка, так, как это неизменяемый тип, а мы не создаем новую строку. а пытаемся заменить элемент

another_str = 'some another text'

new = string+another_str
#print(new)

"""
ФУНКЦИИ СТРОКИ
Так, как str это объект, то он имеет и свои методы (функции)
"""

#S.find(str, [start],[end])	Поиск подстроки в строке.
#Возвращает номер первого вхождения или -1

new.find('so')

#print(new.find('so'))

#S.rfind(str, [start],[end])	Поиск подстроки в строке.
#Возвращает номер последнего вхождения или -1
new.rfind('so')

#print(new.rfind('so'))

#S.index(str, [start],[end])	Поиск подстроки в строке.
#Возвращает номер первого вхождения или вызывает ValueError

new.index('so')
#print(new.index('so'))

#S.rindex(str, [start],[end])	Поиск подстроки в строке.
#Возвращает номер последнего вхождения или вызывает ValueError

new.rindex('so')
#print(new.rindex('so'))

#S.replace(шаблон, замена) Заменяет заданный символ во всей строке на указанный
new.replace('so',  'new templ')

new_str = 'change-some-symbols'
new_str.replace('-','')
#print(new_str.replace('-',''))

new_str = 'change,some,symbols'
new_str.replace(',', " ")
#print(new_str.replace(',', " "))

new_str = 'change,some,symbols-and:another;tt'
new_str.replace(';','_______')
#print(new_str.replace(';','_______'))

#S.split(символ) разбиение строки на список по символу

new_str = 'change-some-symbols'
new_str.split('-',)
#print(new_str.split('-',))

new_str = 'change,some,symbols'
new_str.split(',',)
#print(new_str.split(',',))

new_str = 'change,some,symbols-and:another;tt'
new_str.split(';')
#print(new_str.split(';'))

long_str = """
Вот так можно писать довольно объемный текст
на несколько строчек. Скажем, запросы к БД или еще что
"""
#print(long_str)

select_obj_in_squad = """
SELECT * FROM obj_locations
WHERE obj_lat BETWEEN {:f} AND {:f}
AND obj_lon BETWEEN {:f} AND {:f};
"""

#ФОРМАТИРОВАНИЕ СТРОК


"""
2019 update of EN1998
"""

from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np

from ..result import ResponseSpectrum

def parse_consequence_class(consequence_class):
	"""
	Make sure consequence class is in the right format, e.g.
	- 2 or '2' --> 'CC2'
	- 'CC3-a' --> 'CC3a'
	- 'CC4' --> 'CC3b'

	:param consequenc_class:
		str, consequence class

	:return:
		str, corrected consequence class
	"""
	if isinstance(consequence_class, int) or consequence_class[0] != 'C':
		consequence_class = 'CC%s' % str(consequence_class)
	consequence_class = consequence_class.replace('-', '').upper()
	if consequence_class == 'CC4':
		consequence_class == 'CC3b'
	return consequence_class

CC_DELTA_DICT = {'CC1': 0.6, 'CC2': 1.0, 'CC3a': 1.25, 'CC3b': 1.6}

LS_CC_TR_DICT = {'NC': {'CC1': 800, 'CC2': 1600, 'CC3a': 2500, 'CC3b': 5000},
				'SD': {'CC1': 250, 'CC2': 475, 'CC3a': 800, 'CC3b': 1600},
				'DL': {'CC1': 50, 'CC2': 60, 'CC3a': 60, 'CC3b': 100}}

LS_CC_GAMMA_DICT = {'NC': {'CC1': 1.2, 'CC2': 1.5, 'CC3a': 1.8, 'CC3b': 2.2},
				'SD': {'CC1': 0.8, 'CC2': 1., 'CC3a': 1.2, 'CC3b': 1.5},
				'DL': {'CC1': 0.4, 'CC2': 0.5, 'CC3a': 0.5, 'CC3b': 0.6}}

REF_RETURN_PERIOD = 475

def get_delta(consequence_class='CC2'):
	"""
	Coefficient depending on consequence class

	:param consequence_class:
		str, one of 'CC1', 'CC2', 'CC3a', 'CC3b', ...
		(default: 'CC2')

	:return:
		float, delta value
	"""
	consequence_class = parse_consequence_class(consequence_class)
	delta = CC_DELTA_DICT[consequence_class]
	return delta

def get_return_period(consequence_class='CC2', limit_state='SD'):
	"""
	Return period of seismic action for different limit states
	(the state of damage under a given seismic action)
	and consequence classes

	:param consequence_class:
		str, one of 'CC1', 'CC2', 'CC3a', 'CC3b', ...
		(default: 'CC2')
	:param limit_state:
		str, one of 'NC' (near collapse), 'SD' (significant damage)
		or 'DL' (damage limitation)
		(default: 'SD')

	:return:
		int, return period (in years)
	"""
	consequence_class = parse_consequence_class(consequence_class)
	Tr = LS_CC_TR_DICT[limit_state.upper()][consequence_class]
	return Tr

def get_performance_factor(consequence_class='CC2', limit_state='SD'):
	"""
	Return period of seismic action for different limit states
	and consequence classes

	:param consequence_class:
		str, one of 'CC1', 'CC2', 'CC3a', 'CC3b', ...
		(default: 'CC2')
	:param limit_state:
		str, one of 'NC' (near collapse), 'SD' (significant damage)
		or 'DL' (damage limitation)
		(default: 'SD')

	:return:
		int, return period (in years)
	"""
	consequence_class = parse_consequence_class(consequence_class)
	gamma = LS_CC_GAMMA_DICT[limit_state.upper()][consequence_class]
	return gamma

get_gamma = get_performance_factor

def calc_seismicity_index(Salpha_ref, delta):
	"""
	Compute seismicity index Sdelta from Salpha_ref and delta

	:param Salpha_ref:
		float, maximum response spectral acceleration (5% damping)
		on site category A for the reference return period of 475 yr
		(in m/s2)
	:param delta:
		float, coefficient that depends on the consequence class
		of the considered structure

	:return:
		float, Sdelta (in m/s2)
	"""
	return delta * Salpha_ref

def get_seismicity_class(Sdelta):
	"""
	Determine seismicity class from seismicity index
	- For very low seismicity class, EN 1998 may be neglected;
	- For low seismicity class, performance requirements may be satisfied
	through the application of rules simpler than given in EN 1998

	:param Sdelta:
		float, seismicity index (in m/s2)

	:return:
		str, seismicity class (very low / low / moderate / high)
	"""
	if Sdelta < 1.:
		seismicity_class = 'very low'
	elif 1. <= Sdelta < 2.5:
		seismicity_class = 'low'
	elif 2.5 <= Sdelta < 5.:
		seismicity_class = 'moderate'
	else:
		seismicity_class = 'high'
	return seismicity_class

def get_seismicity_level(Salpha_ref):
	"""
	Determine seismicity level of a territory based on Salpha_ref.
	This corresponds to the seismicity class for consequence class CC2

	:param Salpha_ref:
		float, maximum response spectral acceleration (5% damping)
		on site category A for the reference return period of 475 yr
		(in m/s2)

	:return:
		str, seismicity level (very low / low / moderate / high)
	"""
	return get_seismicity_class(Salpha_ref)

def get_ground_class(VsH):
	"""
	Determine ground class from VsH

	:param VsH:
		float, equivalent value of the shear-wave velocity of the
		deposit above H800 (in m/s)

	:return:
		str, ground class (rock / stiff / medium /soft / very soft) or None
	"""
	if VsH >= 800:
		ground_class = 'rock'
	elif 800 > VsH >= 400:
		ground_class = 'stiff'
	elif 400 > VsH >= 250:
		ground_class = 'medium'
	elif 250 > VsH >= 150:
		ground_class = 'soft'
	elif 150 > VsH >= 100:
		ground_class = 'very soft'
	else:
		ground_class = None
	return ground_class

def get_depth_class(H800):
	"""
	Determine depth class from H800

	:param H800:
		float, depth of bedrock formation (in m) identified by Vs > 800 m/s
		(may be limited to maximum of 30 m)

	:return:
		str, depth class (very shallow / shallow / intermediate / deep)
	"""
	if H800 <= 5:
		depth_class = 'very shallow'
	elif 5 < H800 <= 30:
		depth_class = 'shallow'
	elif 30 < H800 <= 100:
		depth_class = 'intermediate'
	else:
		depth_class = 'deep'
	return depth_class

def get_site_category(H800, VsH):
	"""
	Determine site category based on H800 and VsH

	:param H800:
		float, depth of bedrock formation (in m) identified by Vs > 800 m/s
		(may be limited to maximum of 30 m)
	:param VsH:
		float, equivalent value of the shear-wave velocity of the
		deposit above H800 (in m/s)

	:return:
		str, site category (A / B / C / D / E / F) or None
	"""
	depth_class = get_depth_class(H800)
	ground_class = get_ground_class(VsH)
	if ground_class == 'rock':
		return 'A'
	if depth_class == 'very shallow':
		site_category = {'stiff': 'A', 'medium': 'A', 'soft': 'E'}.get(ground_class, 'F')
	elif depth_class == 'shallow':
		site_category = {'stiff': 'B', 'medium': 'E', 'soft': 'E'}.get(ground_class, 'F')
	elif depth_class == 'intermediate':
		site_category = {'stiff': 'B', 'medium': 'C', 'soft': 'D'}.get(ground_class, 'F')
	elif depth_class == 'deep':
		site_category = {'stiff': 'B', 'medium': 'F', 'soft': 'F'}.get(ground_class, 'F')
	return site_category

def estimate_Sbeta_ref(Salpha_ref, delta):
	"""
	Estimate Sbeta_ref from Salpha_ref and delta.
	Sbeta_ref is the spectral acceleration (5% damping)
	at vibration period T = 1s on site category A
	for the reference return period.

	:param Salpha_ref:
		float, maximum response spectral acceleration (5% damping)
		on site category A for the reference return period (in m/s2)
	:param delta:
		float, coefficient that depends on the consequence class
		of the considered structure

	:return:
		float, Sbeta_ref (in m/s2)
	"""
	Sdelta = calc_seismicity_index(Salpha_ref, delta)
	seismicity_class = get_seismicity_class(Sdelta)
	fh = {'very low': 0.2, 'low': 0.2, 'moderate': 0.3, 'high': 0.4}[seismicity_class]
	Sbeta_ref = fh * Salpha_ref
	return Sbeta_ref

def estimate_Salpha_rp(Salpha_ref, consequence_class='CC2', limit_state='SD'):
	"""
	Estimate maximum spectral acceleration for specific limit state
	and consequence class from Salpha_ref and the performance factor,
	as alternative to the value calculated for the return period
	associated to that limit state and consequence class
	(see :func:`get_return_period`)

	:param Salpha_ref:
		float, maximum response spectral acceleration (5% damping)
		on site category A for the reference return period (in m/s2)
	:param consequence_class:
	:param limit_state:
		see :func:`get_performance_factor`

	:return:
		float, max. spectral acceleration (in m/s2)
	"""
	gamma = get_performance_factor(consequence_class, limit_state)
	Salpha_rp = Salpha_ref * gamma
	return Salpha_rp

def estimate_Sbeta_rp(Sref, ref_is_beta, consequence_class='CC2', limit_state='SD'):
	"""
	Estimate 1-s spectral acceleration for specific limit state
	and consequence class from either Salpha_ref or Sbeta_ref
	and the performance factor,
	as alternative to the value calculated for the return period
	associated to that limit state and consequence class
	(see :func:`get_return_period`)

	:param Sref:
		float, maximum or 1-s response spectral acceleration (5% damping)
		on site category A for the reference return period (in m/s2)
	:param ref_is_beta:
		bool, whether or not :param:`S_ref` corresponds to Salpha_ref
		(False) or Sbeta_ref (False)
	:param consequence_class:
	:param limit_state:
		see :func:`get_performance_factor`

	:return:
		float, 1-s spectral acceleration (in m/s2)
	"""
	if ref_is_beta is False:
		delta = get_delta(consequence_class)
		Sbeta_ref = estimate_Sbeta_ref(Sref, delta)
	elif ref_is_beta is True:
		Sbeta_ref = Sref
	Sbeta_rp = estimate_Salpha_rp(Sbeta_ref, consequence_class, limit_state)
	return Sbeta_rp

def calc_FA(Salpha_rp, S0):
	"""
	Compute FA, the ratio of Salpha with respect to zero-period
	acceleration (PGA)

	:param Salpha_rp:
		float, maximum response spectral acceleration (5% damping)
		on site category A (in m/s2)
	:param S0:
		float, zero-period response spectral acceleration
		on site category A (in m/s2)

	:return:
		float, FA
	"""
	return Salpha_rp / S0

def calc_TB(TC, CHI=4.):
	"""
	Determine the lower corner period of the constant spectral
	acceleration range

	:param TC:
		upper corner period (in s)
	:param CHI:
		float, width of constant acceleration range of spectrum
		(default: 4.)

	:return:
		float, TC (in s)
	"""
	TB = TC / CHI
	TB = np.maximum(TB, 0.05)
	TB = np.minimum(TB, 0.1)
	return TB

def calc_TC(Salpha, Sbeta):
	"""
	Determine the upper corner period of the constant spectral
	acceleration range

	:param Salpha:
		float, maximum response spectral acceleration (5% damping)
		(in m/s2)
	:param Sbeta:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s (in m/s2)

	:return:
		float, TC (in s)
	"""
	Tbeta = 1.
	TC = (Sbeta * Tbeta) / Salpha
	return TC

def calc_TD(Sbeta_rp):
	"""
	Determine the corner period at the beginning of the constant
	displacement response range of the spectrum

	:param Sbeta_rp:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s on site category A
		for particular return period (in m/s2)

	:return:
		float, TD (in s)
	"""
	if np.isscalar(Sbeta_rp):
		if Sbeta_rp <= 1:
			TD = 2.
		else:
			TD = 1 + Sbeta_rp
	else:
		TD = np.ones_like(Sbeta_rp) * 2
		idxs = Sbeta_rp > 1
		TD[idxs] = 1 + Sbeta_rp[idxs]
	return TD

def estimate_site_amplification_factors(site_category):
	"""
	Estimate site amplification factors from site category.
	If site_category is unspecified, the default values (1.7, 4.)
	will be returned.

	:param site_category:
		str, site category

	:return:
		(Falpha, Fbeta) tuple:
		- Falpha: maximum amplification factor
		- Fbeta: amplification factor at vibration period T = 1s
	"""
	Falpha = {'A': 1., 'B': 1.2, 'C': 1.35, 'D': 1.5, 'E': 1.7, 'F': 1.35}.get(
															site_category, 1.7)
	Fbeta = {'A': 1., 'B': 1.6, 'C': 2.25, 'D': 3.2, 'E': 3., 'F': 4.}.get(
															site_category, 4.)
	return (Falpha, Fbeta)

def calc_site_amplification_factors(site_category, H800=0, VsH=0, Salpha_rp=0, Sbeta_rp=0):
	"""
	Determine site amplification factors from continuous functions
	depending on site category and parameters H800 and VsH,
	as well as Salpha_rp and Sbeta_rp.

	:param site_category:
		str, site category
	:param H800:
		float, depth of bedrock formation (in m) identified by Vs > 800 m/s
		(may be limited to maximum of 30 m)
		(default: 0)
	:param VsH:
		float, equivalent value of the shear-wave velocity of the
		deposit above H800 (in m/s)
		(default: 0)
	:param Salpha_rp:
		float, maximum response spectral acceleration (5% damping)
		on site category A for particular return period (in m/s2)
		(default: 0)
	:param Sbeta_rp:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s on site category A
		for particular return period (in m/s2)
		(default: 0)

	:return:
		(Falpha, Fbeta) tuple:
		- Falpha: maximum amplification factor
		- Fbeta: amplification factor at vibration period T = 1s
	"""
	if site_category == 'A':
		Falpha = Fbeta = 1.
	else:
		assert H800 and VsH
		VsH_800 = VsH / 800.
		ralpha = 1. - 2E+3 * (Salpha_rp / VsH**2)
		rbeta = 1. - 2E+3 * (Sbeta_rp / VsH**2)
		if site_category in ('B', 'C', 'D'):
			Falpha = VsH_800**(-0.25*ralpha)
			Fbeta = VsH_800**(-0.7*rbeta)
		elif site_category == 'E':
			Falpha = VsH_800**(-0.25*ralpha*(H800/30.)*(4-H800/10.))
			Fbeta = VsH_800**(-0.7*rbeta*(H800/30.))
		elif site_category == 'F':
			Falpha = 0.9 * VsH_800**(-0.25*ralpha)
			Fbeta = 1.25 * VsH_800**(-0.7*rbeta)

	return (Falpha, Fbeta)

def get_topography_amplification_factor(slope_angle):
	"""
	Determine topography amplification factor based on slope angle

	:param slope_angle:
		float, slope angle (in degrees)

	:return:
		float, amplification factor
	"""
	## Note: this is too simplistic
	Ftopo = 1.
	if slope_angle > 30:
		Ftopo = 1.4
	elif 15 < slope_angle <= 30:
		Ftopo = 1.2
	return Ftopo

def calc_eta(ksi, periods, TC):
	"""
	Determine damping correction factor eta

	:param ksi:
		float, damping ratio of structure, expressed as % of critical
	:param periods:
		float array, vibration periods
	:param TC:
		float, upper corner period of the constant spectral
		acceleration range

	:return:
		float array, eta values
	"""
	eta = np.zeros_like(periods)
	eta[periods > 0.5] = np.sqrt(10.0 / (5 + ksi))
	idxs = (periods <= 0.5)
	eta[idxs] = np.sqrt((10 + (TC * (ksi - 5.)) / (TC + 30*periods[idxs]))
						/ (5 + ksi))
	return eta

def estimate_fvh_alpha(Salpha):
	"""
	Estimate vertical/horizontal ratio for max. spectral acceleration

	:param Salpha:
		float, maximum spectral acceleration (5 % damping) (in m/s2)

	:return:
		float, V/H ratio
	"""
	if Salpha < 2.5:
		fvh_alpha = 0.6
	elif 2.5 <= Salpha < 7.5:
		fvh_alpha = 0.04 * Salpha + 0.5
	else:
		fvh_alpha = 0.8
	return fvh_alpha

def construct_acceleration_rs(Salpha_rp, Sbeta_rp,
						site_category, H800=0, VsH=0, Ftopo = 1.,
						consequence_class='CC2', limit_state='SD', Salpha_ref=None,
						TA=0.02, CHI=4., FA=2.5, S0=None, TD=None,
						periods=None, orientation="horizontal",
						damping=5.):
	"""
	Construct elastic acceleration response spectrum

	:param Salpha_rp:
		float, maximum response spectral acceleration (5% damping)
		on site category A for particular return period (in m/s2)
	:param Sbeta_rp:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s on site category A
		for particular return period (in m/s2)
		If None, will be estimated from :param:`Salpha_rp` and :param:`delta`
	:param site_category:
		str, site category
	:param H800:
	:param VsH:
		see :func:`get_site_amplification_factors`
		optional parameters to compute site amplification factors
		more accurately
		(default: 0)
	:param Ftopo:
		float, topography amplification factor
		(default: 1.)
	:param consequence_class:
		str, consequence class of the considered structure.
		If different from 'CC2', it is assumed that :param:`Salpha_rp`
		and :param:`Sbeta_rp` correspond to Salpha_ref and Sbeta_ref!
		(default: 'CC2')
	:param limit_state:
		str, considered limit state of the structure
		If different from 'SD', it is assumed that :param:`Salpha_rp`
		and :param:`Sbeta_rp` correspond to Salpha_ref and Sbeta_ref!
		(default: 'SD')
	:param Salpha_ref:
		float, maximum response spectral acceleration (5% damping)
		on site category A for the reference return period (in m/s2)
		Optional parameter in case :param:`Sbeta_rp` is None AND
		:param:`Salpha_rp` does not correspond to Salpha_ref (i.e.
		consequence class and limit state are not 'CC2' and 'SD').
		If not given in that case, Salpha_ref will be estimated
		from Salpha_rp (inverse of :func:`estimate_Salpha_rp`
		(default: None)
	:param TA:
		float, short-period cut-off associated to the zero-period
		acceleration (in s)
		(default: 0.02)
	:param CHI:
		float, width of constant acceleration range of spectrum
		(default: 4.)
	:param FA:
		float, ratio of Salpha_rp with respect to the zero-period
		acceleration. Will be ignored if :param:`S0` is specified
		(default: 2.5)
	:param S0:
		float, zero-period acceleration on category A (in m/s2) for same
		return period as :param:`Salpha_rp`. Will be used to override
		:param:`FA`
		(default: None)
	:param TD:
		float, corner period at the beginning of the constant
		displacement response range of the spectrum (in s)
		If not specified, will be determined automatically from
		:param:`Sbeta_rp`
		(default: None)
	:param periods:
		float array, spectral periods
		(default: None)
	:param orientation:
		str, either "horizontal" or "vertical", orientation of spectrum
		(default: "horizontal")
	:param damping:
		float, viscous damping, in % (default: 5)

	:return:
		instance of :class:`rshalib.result.ResponseSpectrum`
	"""
	## Estimate Salpha_rp from Salpha_ref if necessary
	if (consequence_class, limit_state) != ('CC2', 'SD'):
		print("Assuming Salpha_rp/Sbeta_rp correspond to Salpha_ref/Sbeta_ref!")
		Salpha_ref = Salpha_rp
		Salpha_rp = estimate_Salpha_rp(Salpha_ref, consequence_class, limit_state)
		Sbeta_ref = Sbeta_rp
		if Sbeta_ref is None:
			Sbeta_rp = estimate_Sbeta_rp(Salpha_ref, False, consequence_class, limit_state)
		else:
			Sbeta_rp = estimate_Sbeta_rp(Sbeta_ref, True, consequence_class, limit_state)

	## Estimate Sbeta_rp if necessary
	if Sbeta_rp is None:
		if Salpha_ref is None:
			print("Estimating Salpha_ref from Salpha_rp!")
			gamma = get_performance_factor(consequence_class, limit_state)
			Salpha_ref = Salpha_rp / gamma
		Sbeta_rp = estimate_Sbeta_rp(Salpha_ref, False, consequence_class, limit_state)

	Tbeta = 1.

	## Determine site amplification factors
	if H800 and VsH:
		Falpha, Fbeta = calc_site_amplification_factors(site_category, H800, VsH,
													Salpha_rp, Sbeta_rp)
	else:
		Falpha, Fbeta = estimate_site_amplification_factors(site_category)
	Salpha = Salpha_rp * Falpha * Ftopo
	Sbeta = Sbeta_rp * Fbeta * Ftopo

	## Vertical / horizontal ratio
	if orientation == "vertical":
		fvh_alpha = estimate_fvh_alpha(Salpha)
		fvh_beta = 0.6
		Salpha *= fvh_alpha
		Sbeta *= fvh_beta

	if not S0 is None:
		FA = calc_FA(Salpha_rp, S0)

	## Determine corner periods
	TC = calc_TC(Salpha, Sbeta)
	if TC >= 1:
		print("Note: TC >= 1: A specific study should be carried out!")
	if orientation == "horizontal":
		TB = calc_TB(TC, CHI)
	else:
		TB = 0.05
	if not TD:
		TD = calc_TD(Sbeta_rp)

	if periods is None:
		periods = [0, TA, TB, TC, TD]
		TE, TF = 6, 10
		if TD < TE:
			periods.append(TE)
		periods.append(TF)
	periods = np.asarray(periods)

	eta = calc_eta(damping, periods, TC)

	## Construct spectrum
	Se = np.zeros_like(periods)
	Se[(0 <= periods) & (periods < TA)] = Salpha / FA
	idxs = (TA <= periods) & (periods < TB)
	Se[idxs] = (Salpha / (TB - TA)) * (eta[idxs] * (periods[idxs] - TA) + (TB - periods[idxs])/FA)
	idxs = (TB <= periods) & (periods < TC)
	Se[idxs] = eta[idxs] * Salpha
	idxs = (TC <= periods) & (periods < TD)
	Se[idxs] = eta[idxs] * Sbeta * Tbeta / periods[idxs]
	idxs = (periods >= TD)
	Se[idxs] = eta[idxs] * TD * Sbeta * Tbeta / periods[idxs]**2

	model_name = "EN1998 horizontal acceleration response spectrum (site category %s)"
	model_name %= site_category
	return ResponseSpectrum(periods, Se, intensity_unit="ms2", imt="SA",
							model_name=model_name)

def calc_long_period_site_amplification_factor(VsH):
	"""
	Calculate long-period site amplification factor from VsH

	:param VsH:
		float, equivalent value of the shear-wave velocity of the
		deposit above H800 (in m/s)

	:return:
		float
	"""
	Flp = VsH / 800.
	return VsH

def estimate_long_period_site_amplification_factor(Fbeta, site_category):
	"""
	Estimate long-period site amplification factor in case VsH
	is not available

	:param Fbeta:
		float, amplification factor at vibration period T = 1s
	:param site_category:
		str, site category

	:return:
		float
	"""
	if site_category == 'A':
		Flp = Fbeta
	elif site_category in ('B', 'E'):
		Flp = 0.9 * Fbeta
	elif site_category in ('C', 'F'):
		Flp = 0.75 * Fbeta
	elif site_category == 'D':
		Flp = 0.6 * Fbeta
	return Flp

def construct_displacement_rs(Salpha_rp, Sbeta_rp, site_category, periods, **kwargs):
	"""
	Construct elastic displacement response spectrum

	See :func:`get_acceleration_rs` for parameters

	:return:
		instance of :class:`rshalib.result.ResponseSpectrum`
	"""
	Se = construct_acceleration_rs(Salpha_rp, Sbeta_rp, site_category,
										periods=periods, **kwargs)
	Se = Se.values
	SDe = np.zeros_like(Se)
	if not TD in kwargs:
		TD = calc_TD(Sbeta_rp)
	TE = max(TD, 6)
	TF = 10

	if kwargs.get(VsH):
		Flp = calc_long_period_site_amplification_factor(VsH)
	else:
		_, Fbeta = estimate_site_amplification_factors(site_category)
		Flp = estimate_long_period_site_amplification_factor(Fbeta, site_category)

	idxs = (periods <= TE)
	SDe[idxs] = Se[idxs] * (periods[idxs] / 2 * np.pi)**2
	if TE in periods:
		[SDe_TE] = SDe[periods == TE]
	else:
		SDe_TE = construct_acceleration_rs(Salpha_rp, Sbeta_rp, site_category,
											periods=[TE], **kwargs)
	idxs = (TE < periods) & (periods <= TF)
	SDe[idxs] = SDe_TE * (1 + ((Flp / Fbeta) - 1) * (periods[idxs] - TE) / (TF - TE))
	SDe[periods > TF] = SDe_TE * Flp / Fbeta

	model_name = "EN1998 displacement response spectrum (site category %s)"
	model_name %= site_category
	return ResponseSpectrum(periods, SDe, intensity_unit="m", imt="SA",
							model_name=model_name)

def calc_design_pga(Salpha, FA=2.5):
	"""
	Calculate design PGA

	:param Salpha:
		float, maximum response spectral acceleration (5% damping)
		(in m/s2)
	:param FA:
		float, ratio of Salpha_rp with respect to the zero-period
		acceleration
		(default: 2.5)

	:return:
		float, design PGA (in m/s2)
	"""
	return Salpha / FA

def calc_design_pgv(Salpha, Sbeta):
	"""
	Calculate design PGV

	:param Salpha:
		float, maximum response spectral acceleration (5% damping)
		(in m/s2)
	:param Sbeta:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s (in m/s2)

	:return:
		float, design PGB (in m/s)
	"""
	return 0.06 * (Salpha * Sbeta)**0.55

def calc_design_pgd(Sbeta_rp, Flp, TD=None):
	"""
	Calculate design PGD

	:param Sbeta_rp:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s on site category A
		for particular return period (in m/s2)
	:param Flp:
		float, long-period amplification factor
	:param TD:
		float, corner period at the beginning of the constant
		displacement response range of the spectrum (in s)
		If not specified, will be determined automatically from
		:param:`Sbeta_rp`
		(default: None)

	:return:
		float, design PGD (in m)
	"""
	Tbeta = 1.
	if not TD:
		TD = calc_TD(Sbeta_rp)
	return 0.025 * Tbeta * TD * Flp * Sbeta_rp

def estimate_magnitude(Sbeta_rp):
	"""
	Get convential earthquake magnitude (in terms of moment magnitude)
	associated to the elastic response spectrum

	:param Sbeta_rp:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s on site category A
		for particular return period (in m/s2)

	:return:
		float, MW
	"""
	if Sbeta_rp < 0.08:
		MW = 4.5
	elif Sbeta_rp <= Sbeta_rp < 0.2:
		MW = 5.0
	elif 0.2 <= Sbeta_rp < 0.5:
		MW = 5.5
	elif 0.5 <= Sbeta_rp < 1.2:
		MW = 6.0
	elif 1.2 <= Sbeta_rp < 2.5:
		MW = 6.5
	elif 2.5 <= Sbeta_rp < 4.0:
		MW = 7.0
	else:
		MW = 7.5
	return MW

def estimate_duration_on_rock(Sbeta_rp, site_category='A'):
	"""
	Get corresponding duration of the strong part of the ground motion
	on rock, associated to the elastic response spectrum

	:param Sbeta_rp:
		float, response spectral acceleration (5% damping)
		at vibration period T = 1 s on site category A
		for particular return period (in m/s2)
	:param site_category:
		str, site category
		(default: 'A')

	:return:
		float, duration (in s)
	"""
	if Sbeta_rp < 0.08:
		DR = 0.5
	elif Sbeta_rp <= Sbeta_rp < 0.2:
		DR = 1.
	elif 0.2 <= Sbeta_rp < 0.5:
		DR = 2.
	elif 0.5 <= Sbeta_rp < 1.2:
		DR = 4.
	elif 1.2 <= Sbeta_rp < 2.5:
		DR = 8.
	elif 2.5 <= Sbeta_rp < 4.0:
		DR = 16.
	else:
		DR = 32.

	if site_category == 'A':
		pass
	elif site_category in ('B', 'C'):
		DR *= 1.2
	else:
		DR *= 1.5

	return DR

def is_site_specific_study_required():
	# TODO: determine which parameters are required
	"""
	seismicity class == 'high', and site category == 'D' or ('E' or 'F'
		with VsH  < 250 m/s
	site_category is None
	TC >= 1
	:return:
		bool
	"""
	raise NotImplementedError

## Ideas:
## - Compare modeled Sbeta_ref with estimated Sbeta_ref
## - Compute FA and CHI, and compare with standard values of 2.5 and 4.0

## TODO:
## - Map Salpha (and optionally Sbeta, FA) for Tref and other return periods
## Plot site amplification factors in function of VsH and/or H800